begin process at 2010 02 10 07:27:58
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Système

 > MINXL (MINIMALIST XML LIBRARY) : GÉNÉRATEUR/ANALYSEUR/TRAITEMENT DE FLUX/FICHIERS XML EN C++

MINXL (MINIMALIST XML LIBRARY) : GÉNÉRATEUR/ANALYSEUR/TRAITEMENT DE FLUX/FICHIERS XML EN C++


 Information sur la source

Note :
9,13 / 10 - par 8 personnes
9,13 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Système Classé sous :xml, parseur, parser, manipulation, arbre Niveau :Initié Date de création :18/05/2005 Date de mise à jour :16/03/2008 09:15:48 Vu / téléchargé :11 693 / 883

Auteur : xterminhate

Ecrire un message privé
Site perso
Commentaire sur cette source (74)
Ajouter un commentaire et/ou une note

 Description

* Libraitrie MinXL : Minimalist XML *

Il s'agit d'une librairie codée en C++ et basée sur la STL uniquement. Le code est donc portable. Il a été compilé sous Windows2000/MinGW/DevCpp, GNU/linux/Eclipse/CDT et sous WindowsXP/Cygwin/Eclipse/CDT avec succès.

Le source de cette librairie se compose de deux fichiers autonomes : xml.hpp (en-tête C++) et xml.cpp (source C++). Un fichier supplémentaire "xml_test.cpp" est un programme principale de test (25 tests successifs + 2 exemples commentés). Ce dernier donne différents cas d'utilisation de la librairie MinXL, en plus de vérifier son bon fonctionnement point par point. Les sources sont documentés en anglais (pauvre mais je l'espère lisible par tous).

---

Cette librairie contient deux classes regroupées au sein du namespace MinXL :
- t_xml_node : classe élémentaire offrant une abstraction d'un noeud/arbre XML (formé d'une chaine 'clé', de chaines 'attributs' et d'une chaine 'valeur'),
- t_xml_manip : classe facilitant le traitement d'un arbre XML complexe offrant une interface proche d'une invite de commande DOS/Linux (on parcours l'arbre XML comme un système de fichiers par des commandes/méthodes du genre 'list', 'make', 'remove', 'copy', 'move', 'read', 'write', etc...).

---

Limitation : le 'parser' ignore seulement le prologue (ex.: <?xxxx?>) et les commentaires (ex.: <!-- xxx -->), sans les décoder. Les performances du 'parser' sont également tres pauvres (constaté par yAAm). Une optimisation du code est en cours sans nuire à sa lisibilité (gain de rapidité de l'ordre de 500% actuellement, par rapport à la première release).

---

Toutes remarques sont les bienvenues. Je suis prêt à modifier le code source pour prendre en charge de nouvelles fonctionnalités suggérées par un éventuel utilisateur intéressé. Merci.

---

Ce projet est disponible sur SourceForge.Net : Unix Name= "minxl". CVS à jour.

---

Cordialement,
Xterm-in-Hate.

Source

  • /////////////////////////////////////////////////////////////////////////////
  • // CECI EST UN APPERCU DU CODE ZIPPE....
  • /////////////////////////////////////////////////////////////////////////////
  • struct t_xml_node
  • {
  • // constructor
  • t_xml_node( std::string const & key = "_EMPTY_", std::string const & value = "" );
  • // destructor
  • virtual ~t_xml_node();
  • // copy constructor
  • t_xml_node( t_xml_node const & node );
  • // assignment
  • t_xml_node & operator=( t_xml_node const & node );
  • // key accessers
  • std::string const & key() const;
  • std::string & key();
  • // value accessers
  • std::string const & value() const;
  • std::string & value();
  • // number of attributes
  • std::size_t nb_attributes() const;
  • // add an attributes
  • void insert_attribute( std::string const & attribute, std::string const & value );
  • // remove an attributes
  • void remove_attribute( std::size_t const & index );
  • // remove an attribute through string indexer
  • void remove_attribute( std::string const & attribute );
  • // get an attribute
  • std::string const & attribute_at( std::size_t const & index ) const;
  • std::string & attribute_at( std::size_t const & index );
  • // get an attribute associated value
  • std::string const & attribute_value_at( std::size_t const & index ) const;
  • std::string & attribute_value_at( std::size_t const & index );
  • // get an attribute associated through string indexer (key_suffix = "aaaa:n", "aaaa"+":0" by default suffix)
  • std::string const & attribute_value_at( std::string const & attribute ) const;
  • std::string & attribute_value_at( std::string const & attribute );
  • // number of children
  • std::size_t nb_children() const;
  • // add a child
  • void insert_child( t_xml_node const & child );
  • // remove a child
  • void remove_child( std::size_t const & index );
  • // remove a child through string indexer (key_suffix = "aaaa:n", "aaaa"+":0" by default suffix)
  • void remove_child( std::string const & key_suffix );
  • // get a child
  • t_xml_node const & child_at( std::size_t const & index ) const;
  • t_xml_node & child_at( std::size_t const & index );
  • // get a child through indexer (key_suffix = "aaaa:n", "aaaa"+":0" by default suffix)
  • t_xml_node const & child_at( std::string const & key_suffix ) const;
  • t_xml_node & child_at( std::string const & key_suffix );
  • // build : transform a tree/node into a XML stream/file
  • void build_to_file( std::string const & path_filename ) const;
  • std::string build_to_str() const;
  • // parse : transform a XML stream/file into a tree/node
  • void parse_from_file( std::string const & path_filename );
  • void parse_from_str( std::string const & str );
  • };
  • /////////////////////////////////////////////////////////////////////////////
  • // CECI EST UN APPERCU DU CODE ZIPPE....
  • /////////////////////////////////////////////////////////////////////////////
  • struct t_xml_manip
  • {
  • // constructor
  • t_xml_manip( t_xml_node & root );
  • // key management
  • std::vector< std::string > ls( std::string const & path ) const; // list keys
  • void mk( std::string const & path ) const; // make new key or new attribute
  • void rm( std::string const & path ) const; // remove key or attribute
  • void mv( std::string const & src_path, std::string const & dst_path ) const; // move key
  • void cp( std::string const & src_path, std::string const & dst_path ) const; // copy key
  • // key-value and attribute-value read/write
  • std::string const & operator()( std::string const & path ) const; // read key-value or attribute-value
  • std::string & operator()( std::string const & path ); // read/write key-value or attribute-value
  • std::string const & read( std::string const & path ) const; // read key-value or attribute-value
  • void write( std::string const & value, std::string const & path ) const; // write key-value or attribute-value
  • }
  • /////////////////////////////////////////////////////////////////////////////
  • // CECI EST UN APPERCU DU CODE ZIPPE....
  • /////////////////////////////////////////////////////////////////////////////
  • {
  • // example 1.1.1 :
  • //
  • // player_list (number_of_players : 2)
  • // +---> player (id : 0001)
  • // | +---> name : xterm-in-hate
  • // | +---> level : 39
  • // | +---> class : berseker
  • // | +---> experience : 8012
  • // | +---> position
  • // | | +---> world : earth
  • // | | +---> xcord : 111
  • // | | +---> ycord : 452
  • // | | +---> zcord : 37
  • // | | +---> xyangle : 162
  • // | | +---> xzangle : -9
  • // | +---> health : 120
  • // | +---> mana : 270
  • // +---> player (id : 0002)
  • // . +---> name : guest
  • // . +---> level : 1
  • // . +---> class : paladin
  • // . +---> experience : 0
  • // . +---> position
  • // . | +---> world : earth
  • // . | +---> xcord : 118
  • // . | +---> ycord : 493
  • // . | +---> zcord : 38
  • // . | +---> xyangle : 25
  • // . | +---> xzangle : 0
  • // . +---> health : 50
  • // . +---> mana : 22
  • cout << "EXAMPLE#1.1.1" << endl;
  • // root node : player list
  • t_xml_node root( "player_list", "" );
  • root.insert_attribute("number_of_players","2");
  • // child 1 node : player
  • t_xml_node c1( "player", "" );
  • c1.insert_attribute( "id", "0001" );
  • // child 1-1 node : name
  • t_xml_node c11( "name", "xterm-in-hate" );
  • c1.insert_child(c11);
  • // child 1-2 node : level
  • t_xml_node c12( "level", "39" );
  • c1.insert_child(c12);
  • // child 1-3 node : class
  • t_xml_node c13( "class", "berseker" );
  • c1.insert_child(c13);
  • // child 1-4 node : experience
  • t_xml_node c14( "experience", "8012" );
  • c1.insert_child(c14);
  • // child 1-5 node : position
  • t_xml_node c15( "position", "" );
  • // child 1-5-1 node : world
  • t_xml_node c151( "world", "earth" );
  • c15.insert_child(c151);
  • // child 1-5-2 node : xcord
  • t_xml_node c152( "xcord", "111" );
  • c15.insert_child(c152);
  • // child 1-5-3 node : ycord
  • t_xml_node c153( "ycord", "452" );
  • c15.insert_child(c153);
  • // child 1-5-4 node : zcord
  • t_xml_node c154( "zcord", "37" );
  • c15.insert_child(c154);
  • // child 1-5-5 node : xyangle
  • t_xml_node c155( "xyangle", "162" );
  • c15.insert_child(c155);
  • // child 1-5-6 node : xzangle
  • t_xml_node c156( "xzangle", "-9" );
  • c15.insert_child(c156);
  • // child 1-5 node : position (end)
  • c1.insert_child(c15);
  • // child 1-6 node : health
  • t_xml_node c16( "health", "120" );
  • c1.insert_child(c16);
  • // child 1-7 node : mana
  • t_xml_node c17( "mana", "270" );
  • c1.insert_child(c17);
  • // child 1 node : player (end)
  • root.insert_child(c1);
  • // child 2 node : player
  • t_xml_node c2( "player", "" );
  • c2.insert_attribute( "id", "0002" );
  • // child 2-1 node : name
  • t_xml_node c21( "name", "guest" );
  • c2.insert_child(c21);
  • // child 2-2 node : level
  • t_xml_node c22( "level", "1" );
  • c2.insert_child(c22);
  • // child 2-3 node : class
  • t_xml_node c23( "class", "paladin" );
  • c2.insert_child(c23);
  • // child 2-4 node : experience
  • t_xml_node c24( "experience", "0" );
  • c2.insert_child(c24);
  • // child 2-5 node : position
  • t_xml_node c25( "position", "" );
  • // child 2-5-1 node : world
  • t_xml_node c251( "world", "earth" );
  • c25.insert_child(c251);
  • // child 2-5-2 node : xcord
  • t_xml_node c252( "xcord", "118" );
  • c25.insert_child(c252);
  • // child 2-5-3 node : ycord
  • t_xml_node c253( "ycord", "493" );
  • c25.insert_child(c253);
  • // child 2-5-4 node : zcord
  • t_xml_node c254( "zcord", "38" );
  • c25.insert_child(c254);
  • // child 2-5-5 node : xyangle
  • t_xml_node c255( "xyangle", "25" );
  • c25.insert_child(c255);
  • // child 2-5-6 node : xzangle
  • t_xml_node c256( "xzangle", "0" );
  • c25.insert_child(c256);
  • // child 2-5 node : position (end)
  • c2.insert_child(c25);
  • // child 2-6 node : health
  • t_xml_node c26( "health", "50" );
  • c2.insert_child(c26);
  • // child 2-7 node : mana
  • t_xml_node c27( "mana", "22" );
  • c2.insert_child(c27);
  • // child 2 node : player (end)
  • root.insert_child(c2);
  • // build XML file/stream
  • cout << root.build() << endl;
  • }
  • {
  • // example 2.1.1 :
  • //
  • // player_list (number_of_players : 2)
  • // +---> player (id : 0001)
  • // | +---> name : xterm-in-hate
  • // | +---> level : 39
  • // | +---> class : berseker
  • // | +---> experience : 8012
  • // | +---> position
  • // | | +---> world : earth
  • // | | +---> xcord : 111
  • // | | +---> ycord : 452
  • // | | +---> zcord : 37
  • // | | +---> xyangle : 162
  • // | | +---> xzangle : -9
  • // | +---> health : 120
  • // | +---> mana : 270
  • // +---> player (id : 0002)
  • // . +---> name : guest
  • // . +---> level : 1
  • // . +---> class : paladin
  • // . +---> experience : 0
  • // . +---> position
  • // . | +---> world : earth
  • // . | +---> xcord : 118
  • // . | +---> ycord : 493
  • // . | +---> zcord : 38
  • // . | +---> xyangle : 25
  • // . | +---> xzangle : 0
  • // . +---> health : 50
  • // . +---> mana : 22
  • cout << "EXAMPLE#2.1.1" << endl;
  • // root node : player list
  • t_xml_node root( "player_list", "" );
  • t_xml_manip m( root );
  • // root node : player list
  • m.mk("/player_list/.number_of_players");
  • m("/player_list/.number_of_players") = "2";
  • // player 1
  • m.mk("/player_list/player");
  • m.mk("/player_list/player:0/.id");
  • m("/player_list/player:0/.id") = "0001";
  • // player 1 name
  • m.mk("/player_list/player:0/name");
  • m("/player_list/player:0/name") = "xterm-in-hate";
  • // player 1 level
  • m.mk("/player_list/player:0/level");
  • m("/player_list/player:0/level") = "39";
  • // player 1 class
  • m.mk("/player_list/player:0/class");
  • m("/player_list/player:0/class") = "berseker";
  • // player 1 experience
  • m.mk("/player_list/player:0/experience");
  • m("/player_list/player:0/experience") = "8012";
  • // player 1 position
  • m.mk("/player_list/player:0/position");
  • m.mk("/player_list/player:0/position/world");
  • m("/player_list/player:0/position/world") = "earth";
  • m.mk("/player_list/player:0/position/xcord");
  • m("/player_list/player:0/position/xcord") = "111";
  • m.mk("/player_list/player:0/position/ycord");
  • m("/player_list/player:0/position/ycord") = "452";
  • m.mk("/player_list/player:0/position/zcord");
  • m("/player_list/player:0/position/zcord") = "37";
  • m.mk("/player_list/player:0/position/xyangle");
  • m("/player_list/player:0/position/xyangle") = "162";
  • m.mk("/player_list/player:0/position/xzangle");
  • m("/player_list/player:0/position/xzangle") = "-9";
  • // player 1 health
  • m.mk("/player_list/player:0/health");
  • m("/player_list/player:0/health") = "120";
  • // player 1 mana
  • m.mk("/player_list/player:0/mana");
  • m("/player_list/player:0/mana") = "270";
  • // player 2
  • m.mk("/player_list/player");
  • m.mk("/player_list/player:1/.id");
  • m("/player_list/player:1/.id") = "0002";
  • // player 2 name
  • m.mk("/player_list/player:1/name");
  • m("/player_list/player:1/name") = "guest";
  • // player 2 level
  • m.mk("/player_list/player:1/level");
  • m("/player_list/player:1/level") = "1";
  • // player 2 class
  • m.mk("/player_list/player:1/class");
  • m("/player_list/player:1/class") = "paladin";
  • // player 2 experience
  • m.mk("/player_list/player:1/experience");
  • m("/player_list/player:1/experience") = "0";
  • // player 2 position
  • m.mk("/player_list/player:1/position");
  • m.mk("/player_list/player:1/position/world");
  • m("/player_list/player:1/position/world") = "earth";
  • m.mk("/player_list/player:1/position/xcord");
  • m("/player_list/player:1/position/xcord") = "118";
  • m.mk("/player_list/player:1/position/ycord");
  • m("/player_list/player:1/position/ycord") = "493";
  • m.mk("/player_list/player:1/position/zcord");
  • m("/player_list/player:1/position/zcord") = "38";
  • m.mk("/player_list/player:1/position/xyangle");
  • m("/player_list/player:1/position/xyangle") = "25";
  • m.mk("/player_list/player:1/position/xzangle");
  • m("/player_list/player:1/position/xzangle") = "0";
  • // player 2 health
  • m.mk("/player_list/player:1/health");
  • m("/player_list/player:1/health") = "50";
  • // player 2 mana
  • m.mk("/player_list/player:1/mana");
  • m("/player_list/player:1/mana") = "22";
  • // build XML file/stream
  • cout << root.build() << endl;
  • }
  • /////////////////////////////////////////////////////////////////////////////
  • // CECI EST UN APPERCU DU CODE ZIPPE....
  • /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CECI EST UN APPERCU DU CODE ZIPPE....
/////////////////////////////////////////////////////////////////////////////

	struct t_xml_node
	{
		// constructor
		t_xml_node( std::string const & key = "_EMPTY_", std::string const & value = "" );
		
		// destructor
		virtual ~t_xml_node();
		
		// copy constructor
		t_xml_node( t_xml_node const & node );
		
		// assignment
		t_xml_node & operator=( t_xml_node const & node );
		
		// key accessers
		std::string const & key() const;
		std::string & key();
		
		// value accessers
		std::string const & value() const;
		std::string & value();	
		
		// number of attributes
		std::size_t nb_attributes() const;

		// add an attributes
		void insert_attribute( std::string const & attribute, std::string const & value );

		// remove an attributes
		void remove_attribute( std::size_t const & index );
		// remove an attribute through string indexer
		void remove_attribute( std::string const & attribute );

		// get an attribute
		std::string const & attribute_at( std::size_t const & index ) const;
		std::string & attribute_at( std::size_t const & index );
		// get an attribute associated value
		std::string const & attribute_value_at( std::size_t const & index ) const;
		std::string & attribute_value_at( std::size_t const & index );
		// get an attribute associated through string indexer (key_suffix = "aaaa:n", "aaaa"+":0" by default suffix)
		std::string const & attribute_value_at( std::string const & attribute ) const;
		std::string & attribute_value_at( std::string const & attribute );

		// number of children
		std::size_t nb_children() const;

		// add a child	
		void insert_child( t_xml_node const & child );

		// remove a child
		void remove_child( std::size_t const & index );
		// remove a child through string indexer (key_suffix = "aaaa:n", "aaaa"+":0" by default suffix)
		void remove_child( std::string const & key_suffix );

		// get a child
		t_xml_node const & child_at( std::size_t const & index ) const;
		t_xml_node & child_at( std::size_t const & index );
		// get a child through indexer (key_suffix = "aaaa:n", "aaaa"+":0" by default suffix)
		t_xml_node const & child_at( std::string const & key_suffix ) const;
		t_xml_node & child_at( std::string const & key_suffix );

		// build : transform a tree/node into a XML stream/file
		void build_to_file( std::string const & path_filename ) const;
		std::string build_to_str() const;
		
		// parse : transform a XML stream/file into a tree/node
		void parse_from_file( std::string const & path_filename );
		void parse_from_str( std::string const & str );
	};

/////////////////////////////////////////////////////////////////////////////
// CECI EST UN APPERCU DU CODE ZIPPE....
/////////////////////////////////////////////////////////////////////////////

	struct t_xml_manip
	{
		// constructor
		t_xml_manip( t_xml_node & root );
		
		// key management
		std::vector< std::string > ls( std::string const & path ) const; // list keys
		void mk( std::string const & path ) const; // make new key or new attribute
		void rm( std::string const & path ) const; // remove key or attribute
		void mv( std::string const & src_path, std::string const & dst_path ) const; // move key
		void cp( std::string const & src_path, std::string const & dst_path ) const; // copy key
				
		// key-value and attribute-value read/write
		std::string const & operator()( std::string const & path ) const; // read key-value or attribute-value
		std::string & operator()( std::string const & path ); // read/write key-value or attribute-value
		std::string const & read( std::string const & path ) const; // read key-value or attribute-value
		void write( std::string const & value, std::string const & path ) const; // write key-value or attribute-value
}

/////////////////////////////////////////////////////////////////////////////
// CECI EST UN APPERCU DU CODE ZIPPE....
/////////////////////////////////////////////////////////////////////////////

{
	 // example 1.1.1 :
	 // 	           
	 // player_list (number_of_players : 2)
	 // +---> player (id : 0001) 	       
	 // |     +---> name : xterm-in-hate 	
	 // |     +---> level : 39 	            
	 // |     +---> class : berseker 	    
	 // |     +---> experience : 8012 	    
	 // |     +---> position 	            
	 // |     |     +---> world : earth 	
	 // |     |     +---> xcord : 111 	   
	 // |     |     +---> ycord : 452 	 
	 // |     |     +---> zcord : 37 	 
	 // |     |     +---> xyangle : 162 	 
	 // |     |     +---> xzangle : -9 	 
	 // |     +---> health : 120 	 
	 // |     +---> mana : 270 	 
	 // +---> player (id : 0002) 	 
	 // .     +---> name : guest 	 
	 // .     +---> level : 1 	 
	 // .     +---> class : paladin 	 
	 // .     +---> experience : 0 	 
	 // .     +---> position 	 
	 // .     |     +---> world : earth 	 
	 // .     |     +---> xcord : 118 	 
	 // .     |     +---> ycord : 493 	 
	 // .     |     +---> zcord : 38 	 
	 // .     |     +---> xyangle : 25 	 
	 // .     |     +---> xzangle : 0 	 
	 // .     +---> health : 50 	 
	 // .     +---> mana : 22 	 
     cout << "EXAMPLE#1.1.1" << endl; 	 
     // root node : player list 	 
     t_xml_node root( "player_list", "" ); 	 
     root.insert_attribute("number_of_players","2"); 	 
     // child 1 node : player 	 
     t_xml_node c1( "player", "" ); 	 
     c1.insert_attribute( "id", "0001" ); 	 
     // child 1-1 node : name 	 
     t_xml_node c11( "name", "xterm-in-hate" ); 	 
     c1.insert_child(c11); 	 
     // child 1-2 node : level 	 
     t_xml_node c12( "level", "39" ); 	 
     c1.insert_child(c12); 	 
     // child 1-3 node : class 	 
     t_xml_node c13( "class", "berseker" ); 	 
     c1.insert_child(c13); 	 
     // child 1-4 node : experience 	 
     t_xml_node c14( "experience", "8012" ); 	 
     c1.insert_child(c14); 	 
     // child 1-5 node : position 	 
     t_xml_node c15( "position", "" ); 	 
     // child 1-5-1 node : world 	 
     t_xml_node c151( "world", "earth" ); 	 
     c15.insert_child(c151); 	 
     // child 1-5-2 node : xcord 	 
     t_xml_node c152( "xcord", "111" ); 	 
     c15.insert_child(c152); 	 
     // child 1-5-3 node : ycord 	 
     t_xml_node c153( "ycord", "452" ); 	 
     c15.insert_child(c153); 	 
     // child 1-5-4 node : zcord 	 
     t_xml_node c154( "zcord", "37" ); 	 
     c15.insert_child(c154); 	 
     // child 1-5-5 node : xyangle 	 
     t_xml_node c155( "xyangle", "162" ); 	 
     c15.insert_child(c155); 	 
     // child 1-5-6 node : xzangle 	 
     t_xml_node c156( "xzangle", "-9" ); 	 
     c15.insert_child(c156); 	 
     // child 1-5 node : position (end) 	 
     c1.insert_child(c15); 	 
     // child 1-6 node : health 	 
     t_xml_node c16( "health", "120" ); 	 
     c1.insert_child(c16); 	 
     // child 1-7 node : mana 	 
     t_xml_node c17( "mana", "270" ); 	 
     c1.insert_child(c17); 	 
     // child 1 node : player (end) 	 
     root.insert_child(c1); 	 
     // child 2 node : player 	 
     t_xml_node c2( "player", "" ); 	 
     c2.insert_attribute( "id", "0002" ); 	 
     // child 2-1 node : name 	 
     t_xml_node c21( "name", "guest" ); 	 
     c2.insert_child(c21); 	  
     // child 2-2 node : level 	 
     t_xml_node c22( "level", "1" ); 	 
     c2.insert_child(c22); 	 
     // child 2-3 node : class 	 
     t_xml_node c23( "class", "paladin" ); 	 
     c2.insert_child(c23); 	 
     // child 2-4 node : experience 	 
     t_xml_node c24( "experience", "0" ); 	 
     c2.insert_child(c24); 	 
     // child 2-5 node : position 	 
     t_xml_node c25( "position", "" ); 	 
     // child 2-5-1 node : world 	 
     t_xml_node c251( "world", "earth" ); 	 
     c25.insert_child(c251); 	 
     // child 2-5-2 node : xcord 	 
     t_xml_node c252( "xcord", "118" ); 	 
     c25.insert_child(c252); 	 
     // child 2-5-3 node : ycord 	 
     t_xml_node c253( "ycord", "493" ); 	 
     c25.insert_child(c253); 	 
     // child 2-5-4 node : zcord 	 
     t_xml_node c254( "zcord", "38" ); 	 
     c25.insert_child(c254); 	 
     // child 2-5-5 node : xyangle 	 
     t_xml_node c255( "xyangle", "25" ); 	 
     c25.insert_child(c255); 	 
     // child 2-5-6 node : xzangle 	 
     t_xml_node c256( "xzangle", "0" ); 	 
     c25.insert_child(c256); 	 
     // child 2-5 node : position (end) 	 
     c2.insert_child(c25); 	 
     // child 2-6 node : health 	 
     t_xml_node c26( "health", "50" ); 	 
     c2.insert_child(c26); 	 
     // child 2-7 node : mana 	 
     t_xml_node c27( "mana", "22" ); 	 
     c2.insert_child(c27); 	 
     // child 2 node : player (end) 	 
     root.insert_child(c2); 	 
     // build XML file/stream 	 
     cout << root.build() << endl;
}
{
	 // example 2.1.1 :
	 // 	           
	 // player_list (number_of_players : 2)
	 // +---> player (id : 0001) 	       
	 // |     +---> name : xterm-in-hate 	
	 // |     +---> level : 39 	            
	 // |     +---> class : berseker 	    
	 // |     +---> experience : 8012 	    
	 // |     +---> position 	            
	 // |     |     +---> world : earth 	
	 // |     |     +---> xcord : 111 	   
	 // |     |     +---> ycord : 452 	 
	 // |     |     +---> zcord : 37 	 
	 // |     |     +---> xyangle : 162 	 
	 // |     |     +---> xzangle : -9 	 
	 // |     +---> health : 120 	 
	 // |     +---> mana : 270 	 
	 // +---> player (id : 0002) 	 
	 // .     +---> name : guest 	 
	 // .     +---> level : 1 	 
	 // .     +---> class : paladin 	 
	 // .     +---> experience : 0 	 
	 // .     +---> position 	 
	 // .     |     +---> world : earth 	 
	 // .     |     +---> xcord : 118 	 
	 // .     |     +---> ycord : 493 	 
	 // .     |     +---> zcord : 38 	 
	 // .     |     +---> xyangle : 25 	 
	 // .     |     +---> xzangle : 0 	 
	 // .     +---> health : 50 	 
	 // .     +---> mana : 22 	 
     cout << "EXAMPLE#2.1.1" << endl; 	 
     // root node : player list 	 
     t_xml_node root( "player_list", "" ); 	 
     t_xml_manip m( root );
     // root node : player list 	 
     m.mk("/player_list/.number_of_players");
     m("/player_list/.number_of_players") = "2";
     // player 1
     m.mk("/player_list/player");
     m.mk("/player_list/player:0/.id");
     m("/player_list/player:0/.id") = "0001";
     // player 1 name
     m.mk("/player_list/player:0/name");
     m("/player_list/player:0/name") = "xterm-in-hate";
     // player 1 level
     m.mk("/player_list/player:0/level");
     m("/player_list/player:0/level") = "39";
     // player 1 class
     m.mk("/player_list/player:0/class");
     m("/player_list/player:0/class") = "berseker";
     // player 1 experience
     m.mk("/player_list/player:0/experience");
     m("/player_list/player:0/experience") = "8012";
     // player 1 position
     m.mk("/player_list/player:0/position");
     m.mk("/player_list/player:0/position/world");
     m("/player_list/player:0/position/world") = "earth";
     m.mk("/player_list/player:0/position/xcord");
     m("/player_list/player:0/position/xcord") = "111";
     m.mk("/player_list/player:0/position/ycord");
     m("/player_list/player:0/position/ycord") = "452";
     m.mk("/player_list/player:0/position/zcord");
     m("/player_list/player:0/position/zcord") = "37";
     m.mk("/player_list/player:0/position/xyangle");
     m("/player_list/player:0/position/xyangle") = "162";
     m.mk("/player_list/player:0/position/xzangle");
     m("/player_list/player:0/position/xzangle") = "-9";
     // player 1 health
     m.mk("/player_list/player:0/health");
     m("/player_list/player:0/health") = "120";
     // player 1 mana
     m.mk("/player_list/player:0/mana");
     m("/player_list/player:0/mana") = "270";
     // player 2
     m.mk("/player_list/player");
     m.mk("/player_list/player:1/.id");
     m("/player_list/player:1/.id") = "0002";
     // player 2 name
     m.mk("/player_list/player:1/name");
     m("/player_list/player:1/name") = "guest";
     // player 2 level
     m.mk("/player_list/player:1/level");
     m("/player_list/player:1/level") = "1";
     // player 2 class
     m.mk("/player_list/player:1/class");
     m("/player_list/player:1/class") = "paladin";
     // player 2 experience
     m.mk("/player_list/player:1/experience");
     m("/player_list/player:1/experience") = "0";
     // player 2 position
     m.mk("/player_list/player:1/position");
     m.mk("/player_list/player:1/position/world");
     m("/player_list/player:1/position/world") = "earth";
     m.mk("/player_list/player:1/position/xcord");
     m("/player_list/player:1/position/xcord") = "118";
     m.mk("/player_list/player:1/position/ycord");
     m("/player_list/player:1/position/ycord") = "493";
     m.mk("/player_list/player:1/position/zcord");
     m("/player_list/player:1/position/zcord") = "38";
     m.mk("/player_list/player:1/position/xyangle");
     m("/player_list/player:1/position/xyangle") = "25";
     m.mk("/player_list/player:1/position/xzangle");
     m("/player_list/player:1/position/xzangle") = "0";
     // player 2 health
     m.mk("/player_list/player:1/health");
     m("/player_list/player:1/health") = "50";
     // player 2 mana
     m.mk("/player_list/player:1/mana");
     m("/player_list/player:1/mana") = "22";
     // build XML file/stream 	 
     cout << root.build() << endl;
}	

/////////////////////////////////////////////////////////////////////////////
// CECI EST UN APPERCU DU CODE ZIPPE....
/////////////////////////////////////////////////////////////////////////////

 Conclusion

Formalisme de t_xml_manip. Les noeuds/attributs XML sont manipulés comme un système de fichier. La notion de chemin est donc la clé de cette interface. Par exemple : "/racine/noeud" pointe vers le noeud 'noeud' appartenant à la racine 'racine'; "/racine/noeud/.attrib" pointe vers l'attribut 'attrib' appartenant au noeud 'noeud', appartenant à la racine 'racine'.

---

Je remercie Tom87@21 et BaBar60 qui m'ont soutenu pendant la première phase de développement de cette petite librairie. Merci également à l'ensemble des intervenant qui au travers de leur remarques et observation m'ont permis d'améliorer MinXL.

---

Je remercie aussi toutes les personnes qui, grace à leurs commentaires, ont permis à MinXL d'évoluer favorablement au fil du temps.

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

20 mai 2005 03:18:31 :
20 mai 2005 : - Modification des inclusions (remarque steve_clamage), - Ajout d'une protection contre les inclusions multiples (remarque steve_clamage), - Ajout commentaires - Révision de la constness des fonctions membres de t_xml_manip, - Ajout d'une exception déclenchée lorsque le fichier XML passé en argument de t_xml_node::parse est de format incorrect.
20 mai 2005 03:23:35 :
20 mai 2005 : - Modification des inclusions (bis).
20 mai 2005 03:27:11 :
20 mai 2005 : - Mise en forme sur CodeS-SourceS.
21 mai 2005 14:10:28 :
21 mai 2005 : - Correction de namespace.
21 mai 2005 14:14:13 :
21 mai 2005 : - Correction du Zip.
21 mai 2005 22:41:00 :
21 main 2005 : - Ajout de la gestion des attributs dans t_xml_node, - Modification du 'build' permetant de transformer un t_xml_node en un fichier/flux XML avec attributs, - Ajouts de commentaires. TODO : Extraction des attributs à partir d'un fichier/flux XML -> 'parser' V1.1 à venir.
22 mai 2005 17:56:59 :
22 mai 2005 : - Nouvelle version : V1.1 ! Les attributs XML sont maintenant gérés correctement.
27 mai 2005 23:18:07 :
27 mai 2005 : - Visualisation/Création/Retrait des attributes via t_xml_manip (les attributs portent le préfixe '.'). - Ajout d'un exemple complet de création d'un fichie rXML à partir de t_xml_node.
27 mai 2005 23:24:46 :
27 mai 2005 : - Mise en forme sur CodeS-SourceS.
28 mai 2005 22:52:31 :
28 mai 2005 : - Amélioration de la classe t_xml_manip pour lire/écrire les attributs de manire simple. - Ajout d'un exemple complémentaire.
31 mai 2005 20:50:54 :
31 mai 2005 : - Modification de l'interface du parser/builder de t_xml_node (merci BaBar 60 pour ton aide).
14 juillet 2005 11:03:08 :
14 juillet 2005 : - Modification des prototypes de fonctions what() des exceptions MinXL (mise en conformité avec la lib C++ std). - Modification du 'parser' pour ignorer commentaires et prologue XML (modification suite au message de yAAm). - Attention : CVS SF n'est pas à jour (resynch prévue le 1er aout / je suis en vacances !!!).
16 juillet 2005 12:35:50 :
16 juillet 2005 : - Réécriture du parser avec formalisation de la machine a états (gain perf. ~10%, lisibilité/évolutivité fortement accrue). - Ajout du support de la syntaxe XML : "<tag/>" et "<tag att1="val" att2="val"/>" (demande Sabugo).
18 juillet 2005 13:45:25 :
18 juillet 2005 : - Amélioration du 'parser'. Support de l'encodage/décodage des caractères XML spéciaux. L'utilisation de &, ", CR, LR, TAB, <, et > dans la valeur d'un noeud XML ou dans la valeur d'un attribut XML est possible (norme XML 1.0).
19 juillet 2005 09:33:41 :
16 juillet 2005 : - Optimisation de la classe t_xml_node (ajout d'une fonction membre publique : last_inserted_child()). Le gain de rapidité, induit au moment de 'parser' un flux XML, est foudroyant (~500%).
11 août 2005 19:27:37 :
11 aout 2005 : - Compatibilité avec le compilateur VC6 (enfin!).
08 mai 2006 00:29:06 :
Correction d'un bug pour compilateur windows 2003 et supérieur.
29 février 2008 15:48:28 :
29-02-2008 : Correction d'une anomalie (segfault) intervenant lors de l'interprétation d'un fichier xml invalide. Le traitement d'une chaine formatée "&xxxx;" invalide génère maintenant une exception de "format xml invalide".
29 février 2008 15:50:49 :
29-02-2008 : Correction d'une anomalie (segfault) intervenant lors de l'interprétation d'un fichier xml invalide. Le traitement d'une chaine formatée "&xxxx;" invalide génère maintenant une exception de "format xml invalide".
16 mars 2008 09:15:49 :
- Modification des directives de précompilation, - Factorisation du code de "copy" et "move". - TODO : compatibilité basique de xml_manip vers Xpath. (remarques Christophe)

 Sources du même auteur

Source avec Zip CLASSE INTERPRETEUR DE COMMANDES
CODE DE CESAR (CHIFFRE/DÉCHIFFRE) EN C.
Source avec une capture OPTIMISATION DES CALLBACKS C++ RÉSOLUS À LA COMPILATION.
Source avec Zip [WIN32 & LINUX] THREADS C++
Source avec Zip SERVEUR HTTP 1.1 SIMPLE V2.XX (WINDOWS & GNU/LINUX COMPATIBL...

 Sources de la même categorie

Source avec Zip Source avec une capture [C/WIN32/WMI]SAVOIR SI UNE CLASSE COM EST INSTALLÉE par rt15
Source avec Zip Source avec une capture [C/WIN32][DRIVER] DÉTECTION DE CRÉATION OU DE SUPPRESSION DE... par deck_bsd
Source avec Zip DÉTECTION DE LANCEMENT D'APPLICATION (WIN32, REGISTERSHELLHO... par buno
Source avec Zip Source avec une capture [C/WIN32] INJECTION DE DLL 2 MÉTHODES (REMOTETHREAD PROPRE &... par deck_bsd
PRODUCER CONSUMER C (WITHIN LINUX) par PCBill

 Sources en rapport avec celle ci

CONSTRUCTION D'UN ARBRE N-AIRES DYNAMIQUE par Squallgamer
Source avec Zip CODEUR DE HUFFMAN par webis
Source avec Zip INI PARSER FLEX++ / BISON++ par neria
Source avec Zip PARSEUR GÉNÉRAL par mehdicherti
Source avec Zip ENCORE UN PARSER XML par darkpoulpo

Commentaires et avis

Commentaire de luhtor le 19/05/2005 11:25:43

Très très bien, je vais l'utiliser. Par contre, bon c'est peut etre à moi de rajouter ces fonctions dans mon programme, j'aurais besoin des fonctions de conversion classique tel que To_Float(), To_Int() etc ... pour convertir les chaines.
Par exemple, utiliser ce qu'il donne sur ce site:
http://c.developpez.com/faq/cpp/?page=strings#STRINGS_convertform

"L'utilisation de istringstream permet de convertir une string en n'importe quel type pour lequel l'opérateur istream::operator >>() a été défini. Il est donc possible de créer une fonction générique de conversion d'une string en un autre type grâce à l'utilisation des templates :"

#include <sstream>
template<typename T>
bool from_string( const std::string & Str, T & Dest )
{
// créer un flux à partir de la chaîne donnée
std::istringstream iss( Str );
// tenter la conversion vers Dest
return iss >> Dest != 0; }

int main()
{
int dix; from_string( "10", dix );
}

Ca pourrait s'avérer pratique pour par exemple, enregistrer une matrice ou n'importe quel autre type.

En tout cas, merci pour cette source.

Commentaire de xterminhate le 19/05/2005 13:34:27

Exact. Cette librarie ne manipule que des clés/valeurs de type std::string. C'est à l'utilisateur d'adapter ses types de données (intégral ou utilisateur). Les classes std::ostringstream et std:istringstream sont en effet tres utiles dans ce cas.

N'hésite pas à me contacter pour obtenir d'avantage d'aide quant à l'utilisation de MinXL.

Cordialement,
Xterm-in'Hate.

Commentaire de Kirua le 19/05/2005 16:55:29

Chouette lib :) bel exemple que la sauvegarde de parties!

Et si ça peut aider quelqu'un, voici mon code pour convertir des string en T et des T en string, c'est plutôt très simple d'utilisation et même élégant je pense ^^. Faites-en ce que vous voulez.

PS: à mettre dans un .h (par exemple StrConverter.h)

//------------------------------------------------------------------------------
#ifndef STRCONVERTER_H
#define STRCONVERTER_H
//------------------------------------------------------------------------------
//convertisseur générique string <-> type adapté aux I/O std -- par Kirua
//kirua@coder-studio.com
//------------------------------------------------------------------------------
#include <sstream>
#include <string>
//------------------------------------------------------------------------------
template<typename T>
T StrTo(std::string s)
{
    T t;
    std::istringstream ss(s);
    ss >> t;
    return t;
}
//------------------------------------------------------------------------------
template<typename T>
std::string ToStr(T t)
{
std::ostringstream ss;
ss << t;
return ss.str();
}
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------


Exemple:

int i = StrTo<int>("5");
string s = ToStr<int>(i);

Je pense que pour la méthode ToStr on n'est même pas obligé de préciser le paramètre template :)

Commentaire de steve_clamage le 19/05/2005 18:49:36

string s = ToStr(i); suffit avec la je sais plus quoi 'instenciation automatique'


Beau code, tres rare sur cppfrance. Je suis surpris que l'en-tete ne soit pas proteger contre les inclusions multiples.
Pour la portabilité
#include <cstddef>

namespace MinXL
{
typedef std::size_t size_t;
}

et une erreur, dans le .cpp
<les en-tetes>
using namespace std; // attention !
#include "xml.hpp"

Mets les en-tete necessaires dans le .hpp et les autres dans le .cpp, et jamais de using dans un en-tete, dans cet exemple ca compile parce-que les en-tetes sont également inclus dans le source xml_test.cpp

Pour les using, tant qu'a faire autant les mettre en portée minimale

int main()
{
using namespace std;
using namespace MinXL;

}

Commentaire de xterminhate le 19/05/2005 19:03:40

Exact! J'ai effectivement 'foiré' ma livraison V1.0 avec les déclarations using dans les .hpp (un copier/coller de dernière minute ... malheureux). Je m'en vais me foueter... et je corrige ça prochainnement.

Merci steve_clamage pour tes remarques. Je les prendrai en compte dans la V1.1.

Commentaire de steve_clamage le 19/05/2005 19:48:53

Tu vas le mettre sur SourceForge.net ?

Commentaire de xterminhate le 19/05/2005 20:27:08

Oui probablement ! Dans un premier temps, cette librarie sera intégrée à un projet en cours sur SF. Peut être que je vais créer un projet à part entière si mon code est bien reçu ici même.

Pourquoi cete question ?

Commentaire de steve_clamage le 19/05/2005 20:59:08

Parce que je penses que ca serais une bonne chose, il est tres lègé.

Commentaire de xterminhate le 20/05/2005 03:30:29

Voila. J'ai pris en compte vos remarques. Merci.

Commentaire de steve_clamage le 20/05/2005 18:48:25

namespace MinXL
{

using namespace std;

};

Tu inserts le namespace std dans le namespace MinXL, dans le .hpp, je te conseille vivement d'utiliser le prefixe std:: sytèmatiquement et de mettre à la rigueur using namespace std; le .cpp

Commentaire de xterminhate le 20/05/2005 19:08:42

Pourquoi pas (std::), mais j'avoue ne pas comprendre l'interet. En fait, je n'utilise courament que deux namespace (STD et BOOST)....

Commentaire de steve_clamage le 20/05/2005 19:24:42

Le probleme c'est que si l'utilisateur fais using namespace MinXL;, le using namespace std; se fait dans son dos
Jamais de 'using' dans un en-tete.

Commentaire de xterminhate le 20/05/2005 19:33:35

Ca roule. Je l'enlève.

Commentaire de MuPuF le 20/05/2005 20:48:45

tiens, ya mon prénom dedans lol, Sinon, c'est pas mal interressant, mais le XML ... Quel est l'interet de l'utiliser ici ? lors de sauvegarde, plus c'est crypté mieux c'est ... a par si tu veux le prendre depuis Irrlicht qui supporte le xml je vois pas ....
Sinon bravo pour la portabilitée, c'est pas tjs facile

Commentaire de xterminhate le 20/05/2005 21:20:30

Merci MuPuF.

Je profite de ta remarque pour parler un peu de mon domaine de compétence. ;-)

Le cryptage (la confidentialité) et l'intégrité sont deux choses indépendantes (et complémentaires).

Le format XML est parfaitement lisible (facilement anlysable). Cependant, il est possible de garantir son intégrité de manière forte, pour éviter qu'il soit modifié (par le joueur pour l'exemple).

Pour contrôler l'intégrité du fichier XML, on ajouter un motif d'intégrité qui serait le résultat d'une opération de hashage (MD5,SHA,HMAC,etc...) calculée sur le l'ensemble ou une partie des champs du fichier XML.

Exemple de fichier XMl de sauvegarde, sécurisé en intégrité :

<players>
....
<MD5>0vL-ZGbqnge78hREGuTY+LsSA0</MD5>
</players>

Donc le XML peut tout a fait s'appliquer à la sauvegarde d'un jeu, à condition d'ajouteur un motif d'intégrité (bien sur, il faudra garder secret comment la fonction de hash est appliquée, voire introdure un aléa, etc...).

Cela dit, rien n'empeche de crypter/chiffrer le fichier XML (contenant un motif d'intégrité) pour un maximum de sécurité.

Cordialement.

Commentaire de MuPuF le 20/05/2005 21:39:09

oh trés interressant ça la cryptographie ....
Si ça t'interresse, je commence a faire une communauté c++ sur msn(pour l'instant jad_raad et moi).
msn: child_of_k0rn@hotmail.com

Commentaire de xterminhate le 22/05/2005 18:00:32

Un petit mot pour annoncer la sortie de la V1.1 de MinXL. Cette nouvelle version permet le traitement des attributs XML.

Cordialement,
   Xterm-in'Hate.

Commentaire de MetalDwarf le 23/05/2005 19:12:54

Bien joué pour la lib XML, je m'en souviendrai quand j'aurais besoin d'une lib XML simple.
En plus tu utilises du C++ _standard_, tres bonne initiative (beaucoup codent avec des trucs specifiques VC++, sans savoir pourquoi c'est con).
9

Commentaire de xterminhate le 24/05/2005 21:31:57

Merci MetalDwarf pour ton appréciation.

De manière générale, n'hésitez pas à me contacter pour obtenir de l'aide (je vais sans doute rédiger une documentation d'aide en ligne, mais rien ne vaut un échange direct avec le concepteur).

Cordialement,
   Xterm-in'Hate.

Commentaire de simtiers le 28/05/2005 11:44:35

Salut xterm-in-hate !
ça faisait longtemps !

A ce que je vois, tu as répondu à mon cahier des charges : j'essaierai de l'utiliser ce Week-end, pour voir s'il y a des modifs à faire, mais ça m'étonnerai.

La config du serveur avance très lentement (entre révisions bac et problème de compréhension de certains points de wxWindows....), je tenterai d'avancer ce WE...

Simtiers, alias Tom87@21

Commentaire de xterminhate le 28/05/2005 22:57:51

Il est vivant !! Merci pour ton appréciation Tom. :-)

Un petit mot pour signaler une nouvelle mise à jour de ce source. La classe t_xml_manip est quasi complète et supporte l'accès aux attributs de manière simple (préfixe '.' dans le chemin signale un attribut). Le projet source forge est également à jour.

Cordialement,
Xterm-in'Hate.

Commentaire de xterminhate le 31/05/2005 20:53:25

Bonjour,

Encore un petit mot pour annoncer la modification de l'interface de t_xml_node suite pour facilier l'utilisation du parser de MinXL.

Cordialement,
Xterm-in'Hate.

Commentaire de BigBulle le 23/06/2005 23:05:07

Salut :),
Je suis très intéressé par ton projet, mais je n'arrive pas à le compiler (mon compilateur est vc7...).
Lors de ta définition de tes exceptions, j'ai dû remplacer la valeur de retour de tes fonctions what par 'const char *'.
Mais il reste cette ligne:
if( find( _attributes.begin(), _attributes.end(), attribute ) != _attributes.end() )
throw ex_attribute_already_exist();

qui génère l'erreur suivante:
error C2784: 'bool std::operator !=(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : impossible de déduire l'argument de modèle de 'const std::basic_string<_Elem,_Traits,_Ax> &' à partir de ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\string(118) : voir la déclaration de 'std::operator`!=''

Est-ce normal? Dois configurer quelque chose?
Merci d'avance,

BigBulle...

Commentaire de xterminhate le 24/06/2005 02:37:27

Bonjur,

Exact, le prototype de std::exception::what est bien "const char * what () const throw ()". Je corrige dans le source des que possible.

Pour le second probleme, je proposerais dans un premier temps la modification suivante : casser le contenu du if en deux lignes.... pour voir le comportement de VC7.

vector<string>::const_iterator it = find( _attributes.begin(), _attributes.end(), attribute );
if( it != _attributes.end() )
throw ex_attribute_already_exist();

Merci de me tenir au courant de la compilation des lignes ci-dessus.

Cordialement,
X.

Commentaire de BigBulle le 24/06/2005 23:23:11

Ok j'ai simplement dû rajouter un #include <algorithm> pour avoir la fonction find(). Maintenant ça compile sans problème :).
Merci pour ta réponse éclair !
A+ ;),

BigBulle...

Commentaire de xterminhate le 25/06/2005 07:14:37

Bonjour BigBulle,

Alors c'est parfait et merci encore pour ta première remarque que je vais prendre en compte dans une prochaine mise à jour. N'hésite pas à revenir vers moi pour signaler un éventuel bug ou obtenir un conseil sur l'utilisation de MinXL.

Cordialement,
X.

Commentaire de yAAm le 08/07/2005 12:58:22

hmmm, en travaillant sur un fichier de 3.5Mo et en faisant ca (l'interet est juste pour mesurer un peu la vitesse :p)

t_xml_node n;
t_xml_manip xmln(n);
n.parse_from_file("cocoon.xml");
n.build_to_file("mycocoon.xml");
mxln.ls("/");
j'obtien un message d'erreur tres chaleureux :
This application has requested the Runtime to terminate
it in an unusual way....

ca te dis qqc ?

Commentaire de yAAm le 08/07/2005 15:06:05

Ok le pb se situe dans le parser :

supporte pas les commentaires du genre :
<clients>
   <carte_verte>
...
   <carte ...>
</clients>
<!-- base des clients privilegiés --> (peut etre parce qu'elle ne se ferme pas. )

Commentaire de xterminhate le 09/07/2005 17:43:22

Bonjour yAAM,

En effet, minxl n'est pas conforme à toute la norme XML. C'est pourquoi je l'ai appelé "Minimalist" XML ;-)

Je pourrai améliorer minxl en ajoutant le support du prologue et du commentaire... un jour peut etre ! Toute contribution et la bienvenue au passage :-)

Cordialement,
Xterm-in-hate.

Commentaire de sabugo le 12/07/2005 12:07:03

Bonjour !!

Je re-débute en C++, avec C++BuilderX. J'ai dans l'idée d'utiliser MinXL pour parser des fragments xml, mais j'ai quelques problèmes d'utilisation.
J'ai tenté de créer un projet avec les fichiers d'exemple, et également d'intégrer MinXL dans mon projet test, mais rien n'y fait, je me retrouve avec 9 erreurs à tous les coups...

"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_invalid_key::what() const throw()' avec la classe de base 'std::exception' en ligne 54
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_invalid_child_index::what() const throw()' avec la classe de base 'std::exception' en ligne 60
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_child_not_found::what() const throw()' avec la classe de base 'std::exception' en ligne 67
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_invalid_path::what() const throw()' avec la classe de base 'std::exception' en ligne 73
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_manip_ignored::what() const throw()' avec la classe de base 'std::exception' en ligne 81
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_invalid_xml_format::what() const throw()' avec la classe de base 'std::exception' en ligne 87
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_attribute_already_exist::what() const throw()' avec la classe de base 'std::exception' en ligne 93
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_attribute_dont_exist::what() const throw()' avec la classe de base 'std::exception' en ligne 99
"xml.hpp" : E2113 Conflits de fonction virtuelle 'ex_invalid_attribute_index::what() const throw()' avec la classe de base 'std::exception' en ligne 105


C'est grave docteur ??


:) D'avance merci
Thierry

Commentaire de xterminhate le 12/07/2005 17:40:42

Bonjour Sabugo,

Je t'invite à lire 4 messages plus haut, la remarque de BigBulle au sujet du prototype des exceptions de MinXL. Ces dernières sont erronnées et j'ai prévu de les modifier dans la prochaine release. Merci de bien vouloir consulter ma précédente réponse de manière a réaliser la correction des prototypes qui s'impose.

Cordialement,
X.

Commentaire de sabugo le 13/07/2005 00:51:44

Merci Xterminhate.

Je n'avais pas vraiment regardé le problème de BigBulle, j'avais lu les messages hier soir et essayé tes classes ce matin. Merci pour m'avoir mis sur la piste, et également pour avoir effacé le msg à double (y a eu un tit blème après l'envoi...)

Bref, sinon, j'ai commencé à tester tout ça, mais il y a quelques trucs que je n'ai pas réussi...
Je les énumère, dis moi si j'ai juste. Peut-être as-tu des moyens de contourner les problèmes que je rencontre...

Tout d'abord, j'ai pu constater que je ne peux pas passer un fichier xml contenant des attributs au parser...

Ensuite, je n'ai pas réussi à faire un truc du genre :

        t_xml_node n1;
        n1.parse_from_str( this->sXmlFragment );
        size_t size = n1.nb_children();

        for( int i = 0; i < size; i++ )
            {
            t_xml_node cmd = n1.child_at( i );
            t_xml_manip cmdm( cmd );
            //fprintf( stderr, "%i\n", size );
            //fprintf( stderr, cmdm.read( "/name" ).c_str() );
            }

récupérer un node, puis itérer sur ses enfants, pour les récupérer et utiliser un t_xml_manip pour travailler sur le contenu du node récupéré... si j'essaie de faire un read à partir du node, j'ai droit à un "abnormal program termination"... Donc j'en déduis que ce n'est pas faisable, qu'il faut passer par le noeud racine pour utiliser xpath... mais j'imagine que je me trompe :p :)

Merci pour les éventuelles réponses
Thierry

Commentaire de xterminhate le 13/07/2005 09:23:29

Bonjour sabugo,

Peux-tu m'envoyer un exemple de fichier XML dont les attributs ne passent pas ? Le support des attributs a été ajouté récemment. S'il y a un bug, il me faut le corriger rappidement.

L'utilisation de t_xml_manip sur un noeud quelconque est logiquement possible. Le probleme est ailleurs : le chemin /name est il correct ? Je t'invite à placer un bloc try/catch. Certaines exceptions spécifiques MinXL peuvent t'aider à résoudre ce pb. Peux tu me communiquer ton code/ton fichier XML par email pour investiguer ?

Globalement, les problemes que tu rencontres m'interessent bcp pour améliorer MinXL... le manque d'un manuel utilisateur, même succint se fait sentir.

(je suis en vacances... je sens que je vais devoir, quand même, reinstaller un compilo vite fait pour corriger MinXL...lol)

Cordialement,
X.

Commentaire de xterminhate le 13/07/2005 09:26:47

Probablement que "/name" n'est pas correct. Il doit te manquer le nom du fils indicé par la variable 'i'. -> "/fils_i/name". Le premier nom du chemin correspond à la racine....

Commentaire de sabugo le 13/07/2005 12:27:32

Voici un eemple de fragment que j'ai essayé de parser, et qui a fait planter le compilo :

<commands><command name='getRootPath'><params><param __name='drive' __type='String' __value='F:/' /><param __name='nb' __type='Number' __value='2027' /><param __name='state' __type='Boolean' __value='true' /></params></command></commands>

Je pars de la méthode parse_from_str qui récupérer le fragment et le traiter, mais ce genre là ne fonctionne pas... J'ai du revoir pour enlever les attributs et en faire des noeuds à la place.

Sinon, pour le problème du t_xml_manip, je vais encore faire des tests ;)
Désolé de te déranger pendant tes vacances

Commentaire de xterminhate le 13/07/2005 13:09:45

MinXl impose que les valeurs associées aux attributs soient encadrés par " (et non '). Ca devrait mieux fonctionner !

PS: Pas de probleme, j'assure le sav, mieux que Darty ;-)

Commentaire de sabugo le 13/07/2005 14:02:20

Oui, non mais tu penses bien que j'avais essayé, lol :)

En fait, j'ai testé ça :
const string result2 = "<commands><command name=\"getRootPath\"><params><param __name=\"drive\" __type=\"String\" __value=\"F:/\" /><param __name=\"nb\" __type=\"Number\" __value=\"2027\" /><param __name=\"state\" __type=\"Boolean\" __value=\"true\" /></params></command></commands>";

A l'affichage via un fprintf, j'ai bien ça :

le résultat : <commands><command name="getRootPath"><params><param __name="drive" __type="String" __value="F:/" /><param __name="nb" __type="Number" __value="2027" /><param __name="state" __type="Boolean" __value="true" /></params></command></commands>

mais aussi ça :

Abnormal program termination

avec un simple parse_from_str... et pourtant, ça me semble plutot valide, comme fragment...

Commentaire de xterminhate le 13/07/2005 17:37:43

Ca ne vient pas des attributs. Ce type de XML n'est pas supporté : <name attribs />, il faut développer <name attribs></name>... Encore une fonctionnalité à ajouter dans la prochaine release !

Commentaire de sabugo le 13/07/2005 19:09:13

oki, autant pour moi, alors :) je pensais que ça venais des attributs, je n'avais pas du tout pensé à un problème de syntaxe.

Mais ce n'est po grave, vu que je n'ai pas encore vraiment défini la structure d'un fragment type, je peux toujours m'adapter :)

En tout cas, merci pour tes infos ;)

Commentaire de xterminhate le 14/07/2005 11:25:40

Bonjour,

Encore un petit mot pour annoncer une mise à jour de MinXL.

J'ai rétabli la conformité des prototypes d'exception et modifié le 'parser' pour ignorer prologue/commentaires (à la place de les ignorer je pourrais éventuellement les rendre accessibles à partir de l'API de t_xml_node.... à méditer sur l'interêt de cette éventuelle fonctionnalité).

Cordialement,
Xterm-in'Hate.

Commentaire de sabugo le 14/07/2005 11:46:00

Hello !!

Rendre accessible l'en-tête serait intéressant. Au moins pouvoir récupérer l'encodage du fichier. Dans certains cas, ça peut servir, déjà rien que pour faire du traitement et renvoyer un document à l'encodage conforme :)

Dans tous les cas, merci pour ton travail ;)

Commentaire de xterminhate le 14/07/2005 11:53:04

Ok, je prends note pour le prologue. Je modifierai l'API pour le rendre accessible à l'utilisateur de MinXL.

D'autre part, MinXL manque d'un encodage normalisé. Encore une fois, mon approche a été "Minimalist"(e), ce qui explique ce genre de lacune. Par exemple, le décodage/encodage des caractères accentués n'est pas pris en charge. Encore une fonctionnalité de plus à prévoir.

Merci à toi également pour tes remarques/conseils.

Cordialement,
Xterm-in'Hate.

Commentaire de sabugo le 14/07/2005 12:01:08

Oulà, oui, ça ça risque d'être problèmatique, le support des caractères spéciaux...
Perso, j'aimerai utiliser MinXL pour décoder des fragments correspondants à des commandes envoyées en direction d'un serveur socket. Et ces commandes permettront par exemple de déclencher l'ouverture d'une boite de dialogue "Save as". Chaque élément de ces boites de dialogues sont configurables, les textes également. Donc j'aimerai pouvoir passer des textes en français, qui contiendront surement des caractères spéciaux.
M'enfin, j'avais pu tester en Python, et j'avais remarqué que les problèmes d'encodages sont toujours assez sensibles... Je n'ose pas imaginer ce que ça doit donner en C++.

Allez, profite un peu de tes vacances ;)

A+
Thierry

Commentaire de xterminhate le 14/07/2005 14:15:34

En fait, l'utilisation de caractères accentués ne pose aucun probleme à MinXL. C'est juste que leur encodage n'est pas normalisé (dans MinXL, le code ASCII du caractère accentué n'est pas remplacé pas son équivalent &****). MinXL s'impose donc au deux bouts de la chaine de transmission du flux XML, si tu ne veux pas d'ennuis.

Cordialement,
Xterm-in'Hate.

Commentaire de xterminhate le 16/07/2005 12:50:53

Bonjour,

Encore un petit mot pour annoncer une mise à jour de MinXL.

Suite au messages de Sabugo, MinXL support la syntaxe XML <****/>.

Pour information, le code du 'parser' a été quelque peu clarifié, par la mise en oeuvre d'une machine à états. Cette modification devrait faciliter les prochaines évolutions.

Au passage, j'ai noté un gain de performance de l'ordre de 10%. Ce faible gain me permet de conclure que le code du 'parser' n'est pas responsable da la lenteur toute relative de MinXL.

Enfin, j'espere qu'aucune regression n'a eu lieu suite à cette modification majeure du code.

Cordialement,
Xterm-in'Hate.

Commentaire de sabugo le 16/07/2005 13:04:27

Que de bonnes nouvelles :)

Merci bcp !

Commentaire de xterminhate le 21/07/2005 19:26:07

Bonjour,

Encore (-et encore-) un petit mot pour annoncer une mise à jour de MinXL.

J'ai commencé à implémenter l'encodage/décodage des caractères spéciaux (&,<,TAB,CR,LF,...). L'utilisation des ces caractères en tant que valeur de noeud ou d'attribut XML est maintenant possible (exemple : bbcode encpasulé dans xml).

J'ai aussi améliorer les performances du 'parser' (gain x 5) {yAAm si tu lis ces lignes...).

Cordialement,
Xterm-in'Hate.

Commentaire de djedid le 27/07/2005 10:06:25

Salut,

Bon ca a l'air sympa ton outil, pil poil ce que je cherchais mais je n'arrive pas a le compiler. Je suis sous XP et Microsoft Visual C++ 6. A mon avis ca doit pas etre grd chose masi ca me pase sous le nez,eh eh eh. Merci d'avance pour ta reponse.

En fait a  la compilation j'ai un truc comme ca:

xml.cpp
e:\xml\minxl\cppfrance_source_31462\xml.hpp(136) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(142) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(147) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(148) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(150) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(151) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(157) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(163) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(168) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(169) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(199) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(41) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(45) : warning C4786: 'std::vector<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::p
air<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >' : identifier was truncated to '255' characters in the debug information
e:\xml\minxl\cppfrance_source_31462\xml.cpp(92) : error C2374: 'index_child' : redefinition; multiple initialization
        e:\xml\minxl\cppfrance_source_31462\xml.cpp(88) : see declaration of 'index_child'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(134) : error C2065: 'find' : undeclared identifier
e:\xml\minxl\cppfrance_source_31462\xml.cpp(134) : error C2446: '!=' : no conversion from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *' to 'int'
        This conversion requires a reinterpret_cast, a C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(134) : error C2040: '!=' : 'int' differs in levels of indirection from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(158) : error C2446: '==' : no conversion from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *' to 'int'
        This conversion requires a reinterpret_cast, a C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(158) : error C2040: '==' : 'int' differs in levels of indirection from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(161) : error C2440: 'initializing' : cannot convert from 'int' to 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(215) : error C2446: '==' : no conversion from 'const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *' to 'int'
        This conversion requires a reinterpret_cast, a C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(215) : error C2040: '==' : 'int' differs in levels of indirection from 'const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(218) : error C2440: 'initializing' : cannot convert from 'int' to 'const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(227) : error C2446: '==' : no conversion from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *' to 'int'
        This conversion requires a reinterpret_cast, a C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(227) : error C2040: '==' : 'int' differs in levels of indirection from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(230) : error C2440: 'initializing' : cannot convert from 'int' to 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'
        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
e:\xml\minxl\cppfrance_source_31462\xml.cpp(651) : error C2374: 'index_key' : redefinition; multiple initialization
        e:\xml\minxl\cppfrance_source_31462\xml.cpp(635) : see declaration of 'index_key'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(698) : error C2374: 'index_key' : redefinition; multiple initialization
        e:\xml\minxl\cppfrance_source_31462\xml.cpp(682) : see declaration of 'index_key'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(729) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(759) : error C2248: 'unmodify_value' : cannot access private member declared in class 'MinXL::t_xml_node'
        e:\xml\minxl\cppfrance_source_31462\xml.hpp(212) : see declaration of 'unmodify_value'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(761) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(835) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(844) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(858) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(881) : error C2248: 'attribute_parser' : cannot access private member declared in class 'MinXL::t_xml_node'
        e:\xml\minxl\cppfrance_source_31462\xml.hpp(258) : see declaration of 'attribute_parser'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(889) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(896) : error C2248: 'attribute_parser' : cannot access private member declared in class 'MinXL::t_xml_node'
        e:\xml\minxl\cppfrance_source_31462\xml.hpp(258) : see declaration of 'attribute_parser'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(901) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
e:\xml\minxl\cppfrance_source_31462\xml.cpp(925) : error C2039: 'clear' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
xml_test.cpp
e:\xml\minxl\cppfrance_source_31462\xml.hpp(136) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(142) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(147) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(148) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(150) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(151) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(157) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(163) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(168) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(169) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml.hpp(199) : error C2039: 'size_t' : is not a member of 'std'
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(49) : warning C4786: 'std::vector<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<s
td::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >' : identifier was truncated to '255' characters in the debug information
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(722) : error C2059: syntax error : '/'
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(722) : error C2017: illegal escape sequence
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(722) : error C2017: illegal escape sequence
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(722) : error C2017: illegal escape sequence
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(722) : error C2017: illegal escape sequence
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(722) : error C2017: illegal escape sequence
e:\xml\minxl\cppfrance_source_31462\xml_test.cpp(976) : warning C4508: 'main' : function should return a value; 'void' return type assumed

Commentaire de xterminhate le 27/07/2005 22:50:19

Avant d'investiguer (ce que je vais faire d'ici ce WE), es-tu contraint d'utiliser cette 'daube' de VC6 ? L'une des principales tares de VC6 est la mauvaise implémentation de la STL, ce sur quoi je me suis basé pour fournir MinXL... Je te recommande soit d'upgrader vers VC7.1+ (qui est tres bon), soit un GCC-like (Cygwi,MinGW,...).

Cordialement,
X.

Commentaire de djedid le 28/07/2005 05:07:05

OK! desole pour le message un peu long... ben en fait jusqu'a present je n'ai jamais eu de problemes avec VC6 mais bon rien ne m'empeche de passer sous VC7.1+ mais bon je vais encore plancher dessus je changerai de version si vraiment y'a pas d'autres solutions :-)

Merci d'avoir repondu aussi vite !

Commentaire de xterminhate le 28/07/2005 07:08:08

En attendant de retrouver mon IDE favoris pour pouvoir debugger : si tu ajoutes un #include<string> au début du xml.cpp et de ton main.cpp, est ce que ca améliore les choses ?. Ext ce qu'en retirant typedef std::size_t size_t; du xml.cpp, ca améliore aussi les choses ?

Commentaire de xterminhate le 11/08/2005 19:28:50

Bonjour,

Encore un petit mot pour annoncer une mise à jour de MinXL.

Le code compile correctement sous VC6 sp5.

Cordialement,
Xterm-in'Hate.

Commentaire de nicutza le 08/03/2006 14:02:32

Moi, je voudrai utiliser ces fichiers avec Palm OS Developer Suite, mais a chaque fois quand je fais un nouveau fichier et j'ajoute les lignes:

#include<string.h>
#include<assert.h>
.....
etc

il ne trouve pas les fichier string.h, assert.h, etc, mais dans les fichier crees automatiquement par Palm OS Developer Suite(AppMain.c, AppRessources.h) il reconnait ces fichiers.

Quelqu'un peut m'aider svp, car je ne sais plus avancer a cause de ces erreurs.

Merci,

Commentaire de xterminhate le 08/05/2006 00:30:57

Un bug de corrigé pour assurer la bonne compilation sous compilateur windows 2003 et supérieur.

Cordialement,
Xter.

Commentaire de babar60 le 24/08/2006 09:31:38

Je vois que ton projet a bien avancé. Moi je reprends juste maintenant le mien, je vais inclure la dernière révision de MinXL.
A mon tour je te remercie, ton outil correspond tout à fait à ce dont j'avais besoin.

Cordialement,
BaBaR60

Commentaire de MuPuF le 24/08/2006 11:26:49

Et moi aussi je te remercis car sans ce parseur, je suis pas sur que mon programme tournerait aussi vite, il speede quand meme pas mal, pour parser 17ko de données il lui faut 2.7 ms ouverture du fichier comprise, bravo. Et puis quelle simplicité d'utilisation ...

Commentaire de xterminhate le 24/08/2006 17:20:56

Content que MinXL vous plaise ! :-)

J'utile toujours cette librairie dans mes projets, son interface me permet de gagner du temps.

Bonne continuation.

Commentaire de prgasp77 le 29/11/2006 06:05:51

Salut, et merci pour la lib ;)

################################################################
> Une proposition pour commencer : modifier la fonction
#string t_xml_node::recursive_builder( t_xml_node const & node )
   en
#string t_xml_node::recursive_builder( t_xml_node const & node, int level = 0 )
#{
# string str;
# // node header (key)
# str += "\n";
#> for(int i=0; i<level; i++) str +="\t";
#> str += "<" + node.key();
# // node header (attributes)
# for( stdsize_t attrib_index = 0; attrib_index != node.nb_attributes(); #++attrib_index )
# str += " " + node.attribute_at( attrib_index ) + "=\"" + #modify_attribute( node.attribute_value_at( attrib_index ) ) + "\"";
# // node end of header (key)
# //str += ">\r\n";
# str += ">";
# // node value
# str += modify_value( node.value() );
# // process children (recurs.)
# if( node.nb_children() != 0 )
# for( stdsize_t index_child = 0 ; index_child < node.nb_children(); ++index_child )
# str +=  recursive_builder( node.child_at( index_child ), level+1 );
# // node footer
# str += "\n";
#> for(int i=0; i<level; i++) str +="\t";
#> str += "</" + node.key() + ">";
# return str;
#}

Cela permet de gérer l'indentation des fichier xml.


################################################################
> Une question pour terminer :
¤ Fichier XML (scuzy pour l'anglais approx, c'est pas moi qui ais fait la DTD) :
-----------
#<?xml version="1.0"?>
#<Options>
# <FTP .Activated="True">
# <Host>
# </Host>
# <Login>
# </Login>
# <Pass>
# </Pass>
# <FTPDir>
# </FTPDir>
# <UsePhpPage>False
# </UsePhpPage>
# </FTP>
#</Options>
---------
¤ je le parse :
#XMLOption.parse_from_file(Path); // XMLOption est un t_xml_node
#Tree = new t_xml_manip(XMLOption);
¤ je tente de lire l'attribut .Activated (comme c'est moche)
#Tree->read("/Options/FTP/.Activated")
et là : ex_attribute_dont_exist alors que la lecture des vlés
#Server=Tree->read("/Options/FTP/Host")
ne pose absolument aucun problème.

Peux-tu m'aider.
Merci à toi.

Commentaire de xterminhate le 29/11/2006 08:18:17

L'indentation dans un fichier XML n'a pas vraiment de sens. C'est l'outil qui affiche le contenu du fichier qui doit s'en charger (IE le fait par exemple). En effet, tes tabulation vont se retrouver dans la champ valeur de la clé.

Remplace .Atecivated par Activated dans ton fichier XML et le code devrait marcher. Le '.' est utile à la classe de manipaltion pour faire la différence entre une clé et un attribut dans le chemin passé en argument.

J'utilise toujours cette classe pour mes projet et elle me donne entière sastifaction.

Bonne chance !

Xter

Commentaire de prgasp77 le 29/11/2006 16:53:23

Tu as raison pour la clé, je m'excuse c'est évidant :(
Mai spour l'indentation, la norme XML veut que les whitespaces ne soient pas interprétés. Mais dans le cadre de ta lib, ça me convient très bien de faire sans :)

Merci et bonne continuation.

Commentaire de lovejava le 21/09/2007 20:34:20

Salut,
pour te dire que ta librairie est exactement ce que je cherchais ^^ très simple mais effective et intuitive.
Comme tout projet open-source, je préviens au passage que je l'utilise dans un de mes prog (hughobot : http://www.cppfrance.com/codes/BOT-IRC-CPLUSPLUS-FACONNABLE-EXTENSIBLE-AVEC-ARCHITECTURE-EVENEMENTIELLE_44020.aspx)
et puis ça fait toujours plaisir ;)

allez a+ et bonne prog

Commentaire de xterminhate le 22/09/2007 10:48:55

Merci pour ton commentaire. Ton projet semble tres interessant. Bonne chance !

Commentaire de cmassaloux le 15/03/2008 19:05:27

Salut Xterm,

J'ai constaté que tu as apporté un correctif au bug que je t'avais remonté. Merci.
J'en profite pour te faire part d'une ou deux remarques que je me suis fait en relisant ton code.
1) Il y a plusieurs occurrences de conditions
    #if ( _MSC_VER > 1300 )
        current_key.clear();
    #else
        current_key = "";
    #endif

Pour ma part, je compile avec GCC sous Linux ou avec MinGW (donc GCC également) sous Windows.
Tout fonctionne bien, mais comme la macro _MSC_VER n'est pas définie, je pense que GCC doit systématiquement évaluer la condition comme fausse, alors que le code "current_key.clear();" est tout à fait valide pour GCC.

Tu pourrais modifier comme suit pour restreindre l'anomalie à MSVC versin <= 1300, et laisser le code par défaut pour tous les autres compilateurs:
    #if ( _MSC_VER <= 1300 )
        current_key = "";
    #else
        current_key.clear();
    #endif


D'autre part, il me semble que les deux fonctions t_xml_manip::cp() et t_xml_manip::mv() ont pratiquement le même code source, à part la suppression du node déplacé à la fin de t_xml_manip::mv()
    // free
    src_node->remove_child( src_keys.back() );

Je dis peut-être une connerie, mais il me semble plus judicieux de factoriser le code de la copie dans t_xml_manip::cp() et de coder t_xml_manip::mv() comme suit:

void t_xml_manip::mv( string const & src_path, string const & dst_path ) const
{
    this->cp(src_path, dst_path);
    // free
    src_node->remove_child( src_keys.back() );
}

Enfin, je vais avoir besoin d'utiliser des fonctionnalités de recherche de nodes à la "XPath".
Je crois que MinXL offre quelques fonctionnalité proche, via grâce à t_xml_manip::operator(), mais j'imagine que c'est quand même un peu limité.

D'ailleurs, pourquoi y a-t-il deux méthodes t_xml_manip::operator() ?
string const & t_xml_manip::operator()( string const & path ) const
string & t_xml_manip::operator()( string const & path )

Bref, Penses-tu possible d'implémenter quelques fonctionnalités basiques de XPath ?

Bon courage et merci

Christophe Massaloux

Commentaire de xterminhate le 16/03/2008 09:09:15

Bonjour Christophe,

D'abord, je te remercie pour tes commentaires et conseils au sujet de ce code source.

Apres diverses formalations assez complexe pour traiter de manière optimale tous les cas, j'ai finalement modifié mon code source de la façon suivante pour garantir le bon fonctionnement sous GCC et les dernières versions de Microsoft :

#if !defined( _MSC_VER )
    typedef std::size_t size_t;
#endif // !defined(_MSC_VER)


#if !defined( _MSC_VER )
    _tmp_str.clear();
#else
    _tmp_str = "";
#endif // !defined(_MSC_VER)

Concernant la factorisation de 'copy' et 'move', la modification est un peu plus compliquée car la partie 'free' prend en argument un résultat intermédiaire de 'copy'. J'ai factorisé 'cop' et 'move' en introduisant une fonction d'implémentation déclarée privée. J'ai aussi ajouté un test clair (18bis) dans xml_test.cpp pour vérifier le comportement de 'copy' et 'move'.

Langage Xpath est très intéressant pour la classe xml_manip. Je ne le connaissais pas à l'époque de la rédaction de ce code source. Par exemple, j'utilise le "." pour accéder un attribut alors que c'est un "@" dans Xpath. Et puis il y a les opérateur de recherche.... Intéressant mais il va me falloir trouver la motivation pour me replonger a fond dans mon code pour réaliser ces évolutions.

Concernant les deux opérateurs qui se ressemblent,
- le premier permet de retourner une référence constante (accès en lecture seul d'une valeur/attribut),
- le seconde retourne un référence vers une valeur/attribut (accès en lecteur et écrite).

GCC choisit automatique le bon opérateur en fonction du contexte appelant.

La premiere formulation permet de s'affranchir d'une copie dans la plupart des cas d'utilisation. La seconde formulation a pour but de pouvoir écrire le code suivant : xmlm( "/players/number" ) = "2";

Une mise à jour de MinXL est disponible dans quelques minutes.

Cordialement,
Xterm-in'Hate.

Commentaire de cmassaloux le 16/03/2008 15:49:25

Salut Xterm,

Merci pour tes réponses et ta réactivité.
Compris le pourquoi des deux t_xml_manip::operator().

S'il me venait l'envie d'apporter moi-même des fonctionnalités (XPath) à ton code, est-ce que tu acceptes les patches qu'on pourrait t'envoyer ?

Une autre question, tu annonces dans la description du projet:
"Une optimisation du code est en cours sans nuire à sa lisibilité (gain de rapidité de l'ordre de 500% actuellement, par rapport à la première release)."

Est-ce que cette optimisation est toujours en cours ou a-t-elle été implémentée dans le code actuel ?
(Auquel cas il conviendrait de corriger le text de description..)

Christophe

Commentaire de xterminhate le 16/03/2008 18:56:27

Bonjour,

L'optimisation dont il est question dans le texte d'introduction est terminée. J'en tiendrai compte pour la prochaine mise à jour.

Je souhaite avancer dans l'implémentation d'une API proche de Xpath pour xml_manip.

Ta contribution est la bienvenue. J'aimerais pouvoir en discuter avec toi par email (xterminhate@wanadoo.fr).

Cordialement,
Xterm-in'Hate.

Commentaire de jgelie le 24/07/2008 14:31:33

bonjour,

mon fichier xml est ecrit de la maniere suivante:
**************************************************************************************
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
</DocumentProperties>
<CustomDocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
</CustomDocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
</ExcelWorkbook>
<Worksheet ss:Name="Feuil1">
  <Table ss:ExpandedColumnCount="4" ss:ExpandedRowCount="59" x:FullColumns="1"
   x:FullRows="1" ss:DefaultColumnWidth="60">
   <Column ss:StyleID="s63" ss:AutoFitWidth="0" ss:Width="149.25"/>
   <Column ss:StyleID="s65" ss:AutoFitWidth="0" ss:Width="150"/>
   <Column ss:StyleID="s73" ss:AutoFitWidth="0" ss:Width="150"/>
   <Column ss:AutoFitWidth="0" ss:Width="360"/>
   <Row>
    <Cell ss:StyleID="s62"><Data ss:Type="String">FRENCH</Data></Cell>
    <Cell ss:StyleID="s66"><Data ss:Type="String">ENGLISH (US)</Data></Cell>
    <Cell ss:StyleID="s70"><Data ss:Type="String">ARABIC</Data></Cell>
    <Cell ss:StyleID="s62"><Data ss:Type="String">COMMENTAIRE</Data></Cell>
    </Row>
  </Table>
</Worksheet>
</Workbook>
*************************************************************************************


je souhaiterai recuperer uniquement les elements :
FRENCH
ENGLISH
ARABIC
se trouvant à: "/Workbook/Worksheet/Table/Row/cell/Data"

Pour cela, j'ai ecris les lignes de codes suivantes:
string s;
t_xml_node n;
t_xml_manip* k;
k= new t_xml_manip(n) ;
n.parse_from_file("traduction.xml");
s=k->read("/Workbook/Worksheet/Table/Row/Cell/Data");


on me renvoi la donnée FRENCH.

mon probleme est donc le suivant: Comment dois-je proceder pour acceder aux autres DATA ? je bloque totalement.
merci d'avance

Commentaire de xterminhate le 24/07/2008 17:38:16

s=k->read("/Workbook/Worksheet/Table/Row/Cell/Data:0");
s=k->read("/Workbook/Worksheet/Table/Row/Cell/Data:1");
s=k->read("/Workbook/Worksheet/Table/Row/Cell/Data:2");
etc....

Commentaire de shenron666 le 18/08/2008 18:01:23

bonjour,

j'ai voulu me servir de minxl pour charger un fichier de configuration d'une petite application d'exploration de fichiers mais après une bonne demi heure à me torturer l'esprit j'ai fini par laisser tomber et passer sur tinyxml

j'aimerai bien savoir comment vous gérez le chargement d'un simple petit fichier comme celui-ci :
<?xml version="1.0" encoding="ISO-8859-1"?>
<mediaterface>
<drives>
<drive label="[DRV]Sources" data="//nas/sources"/>
<drive label="[DRV]Demos" data="//nas/demos"/>
<drive label="[DRV]Jeux" data="d:/jeux"/>
</drives>
</mediaterface>

je cherche à récupérer les éléments "drive" afin de créer mon arborescence de base
je n'ai pas trouvé d'exemple qui me convienne dans le code

pour exemple, le code avec tinyxml :
void Config(void)
{
// initialize configuration file to load
TiXmlDocument config("explorer.cfg");
config.SetCondenseWhiteSpace(false);

// load configuration file
if(!config.LoadFile())
return;

// parse the xml configuration file
TiXmlHandle root(&config);
TiXmlElement* drive = root.FirstChildElement("mediaterface").FirstChildElement("drives").FirstChildElement("drive").Element();

// setup the drives
while(drive)
{
m_Root->Add(new CPathElement(CPathElement::eFolder, drive->Attribute("label"), drive->Attribute("data"), m_Root));
drive = drive->NextSiblingElement("drive");
}
}

Commentaire de xterminhate le 19/08/2008 11:22:08

Bonjour,

Je crée un nouveau projet C++. J'ajoute les fichiers xml.hpp et .cpp. J'écris le code source suivant :

#include <iostream>
using namespace std;
#include "xml.hpp"

int main()
{
    MinXL::t_xml_node root;
    root.parse_from_file( "test.xml" );

    MinXL::t_xml_node drives = root.child_at("drives");
    size_t drive_count = drives.nb_children();
    cout << drive_count << " drives!" << endl;

    for( size_t index = 0; index != drive_count; ++index )
        cout << "Drive #" << index << " = " << drives.child_at(index).attribute_value_at("data") << endl;

    return 0;
}

J'obtiens  l'affichage suivant :

3 drives!
Drive #0 = //nas/sources
Drive #1 = //nas/demos
Drive #2 = d:/jeux

Process returned 0 (0x0)   execution time : 0.015 s
Press any key to continue.

CQFD.

Pour utiliser TinyXML, il faut vraiment aimer les pointeurs dans tous les sens... ^^

Cordialement,
Xterminhate.

Commentaire de shenron666 le 19/08/2008 18:48:16

les pointeurs ne me dérangent pas, je dirait même que j'aime ça (enfin faut pas trop en abuser ^^)
tinyxml est aussi plus lourd côté code généré, mais on trouve plus facilement des tutos et surtout une doc doxygen
minxl mériterait une page dédiée avec tout ce qu'il faut pour l'utiliser sans se prendre la tête à plonger dans le code
en tout cas, merci pour votre aide, je vais adapter mon programme et voir quelle bibliothèque me convient le mieux ;)

Commentaire de shenron666 le 21/08/2008 10:17:29

Salut, alors j'ai adapté mon code à minxl avec succès
par contre, personnellement je trouve que gérer tous les échecs avec des exceptions alourdit énormément le code qui devient vite illisible
si on ne veux pas sortir de la lecture de l'arbre xml juste parcequ'un élément non critique n'a pas été trouvé on est obligé d'imbriquer des try catch à la pelle
à titre d'exemple, gérer la lecture de cet arbre xml :
<?xml version="1.0" encoding="ISO-8859-1"?>
<mediaterface>
  <drives>
    <drive label="[DRV]Programmation" data="d:/Programmation">
      <select label="[DIR]Code::Blocks">
      <select label="[DIR]MinGW">
      <select label="[Dir]Includes">
    </drive>
  </drives>
</mediaterface>

"drive" est un lecteur et les "select" servent à mémoriser le dernier emplacement parcouru

pour récupérer tout ça en code j'ai fait ceci :
// load configuration file
m_XmlFile.parse_from_file("test.xml");

try
{
  // parse the xml tree
  MinXL::t_xml_node drives = m_XmlFile.child_at("drives");

  for(size_t nDriveNb=0; nDriveNb < drives.nb_children(); ++nDriveNb)
  {
    MinXL::t_xml_node drive = drives.child_at(nDriveNb);
    if(drive.key() != "drive")
      continue;

    try
    {
      // create the drive
      CPathElementPtr drv = new CPathElement(CPathElement::eFolder, drive.attribute_value_at("label"), drive.attribute_value_at("data"), m_Root);
      // add the new drive to the root
      m_Root->Add(drv);
      drv->UpdateChildren();
      std::stringvector arSelection;

      try
      {
        for(size_t nSelectNb=0; nSelectNb < drive.nb_children(); ++nSelectNb)
        {
          MinXL::t_xml_node select = drive.child_at(nSelectNb);
          if(select.key() != "select")
            continue;
          arSelection.push_back(select.attribute_value_at("label"));
        }
      }
      catch(std::exception e)
      {
      }
      drv->SetSelection(arSelection);
    }
    catch(std::exception e)
    {
      continue;
    }
  }
}
catch(std::exception e)
{
}

si un élément n'est pas trouvé, je ne veux pas tout arrêter
je ne pense pas que je puisse m'en sortir autrement ?

Autre chose aussi, il manque une méthode pour supprimer tous les enfants d'un noeud
coller un foreach pour supprimer tous les enfants n'est pas très propre et pour des gros fichier ça risque de plomber les perfs

Commentaire de xterminhate le 21/08/2008 17:55:51

Bonjour,

MinXL utilise le gestionnaire d'exception afin de faciliter le traitement d'un fichier XML anormal / corrompu. A mon sens, tu ne devrais donc avoir qu'un seul et unique bloc try-catch, encadrant l'appel à la fonction de "configuration" de ton application.

A partir de ce point, on suppose le fichier XML parfaitement intègre et valide. Pour simplifier l'interprétation du fichier XML par l'application, on prendra soin de choisir une structuration XML systématique. Ainsi, aucun traitement d'exception n'est a implémenter au moment de l'analyse du fichier XML.

Par exemple, le noeud <drives> comprendra un certains nombre de fils <drive> et seulement <drive>, comprenant tous un attribut "data" (renseigné ou vide). Le noed <drive> comprendra un certain nombre de fils <select>, comprenant tous un attribut "label" (renseigné ou vide). Etc.

Par conséquent, en prenant soin d'utiliser les fonctions membres child_at( size_t ), nb_children(), attribute_at( size_t ) et nb_attributes(), aucune exception ne sera levée par MinXL. Cela tend à simplifier le code la fonction "configuration" de cette application.

Pour gérer les exceptions au fil de l'analyse du fichier, dans le but de résister à une corruption partielle du fichier XML, je ne vois pas d'autre solution que de gérer les exceptions à chaque appel à MinXL avec un bloc try-catch dédié. L'autre technique serait d'utiliser le principe du C avec un retour de fonction à 0 et une fonction globale du genre get_error() afin d'obtenir une information détaillée sur la nature de l'erreur...

Effectivement, il manque une fonction pour supprimer tous les enfants d'un noeud, par exemple remove_childS(). Pour l'instant, c'est à l'utilisateur de MinXL d'implémenter une éventuelle boucle. En outre, il n'y a pas d'autre solution que de faire un boucle pour supprimer les fils un par un. Néanmoins, il est possible d'utiliser la fonction remove_child() sur le père du noeud dont on veut supprimer les fils. Attention, cela supprime également le noeud en question.

Je vais réfléchir à intégrer la fonction remove_childs() et remove_attributes() dans une prochaine révision de MinXL.

Je suis preneur de proposition pour une gestion plus souple des exceptions.

Cordialement,
Xterminhate.










Commentaire de shenron666 le 21/08/2008 22:40:21

merci pour ta réponse, concernant les exceptions je n'entrevois pas de solution simple, changer ce principe c'est tout réécrire
quand à la suppression des enfants, j'ai ajouté la fonction à partir d'un std::for_each, je prendrai la nouvelle version de minxl lorsqu'elle sera disponible et je m'adapterai
vu que ça fonctionne bien je suis passé à autre chose niveau programme
cordialement,
Shenron

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Parseurs XML pour C++ [ par Direkt ] Bonjour tout le monde,Dans le cadre d'un developpement en C++, j'ai besoin d'un parseur XML qui fonctionne sous:- Linux (SLC3-SLC4. C'est le point le Parseur XML avec wxWidgets [ par badr16 ] Salut ,  je suis en train d'écrire un parseur XML avec wxWidgets pour parser un fichier XML.  Est ce qu'il y a quelqu'un qui posséde le code de Source parser un fichier xml [ par boualiasma ] Bonsoir, Je voulais parser mon fichier XML pouyr extraire certaines informations pour les utiliser dans mon programme C. J'ai trouvé la librairie li Parser avec description de format (xml) ? [ par RV2931 ] Bonjour,Je dois réaliser quelques parsers de fichiers, notament un parser de fichiers DXF, et d'autres formats propriétaires...J'ai entendu parler que XML C/C++ parser et EXCEL [ par Kurpeus1 ] Bonjour, Je voudrais savoir si quelqu'un a déjà parsé du xml à la sauce microsoft  Excel et si oui avec quel parser il l'a fait ? parser xml [ par khalil1982 ] Salut tlm,J'avais besoin d'un parseur Xml dans mon projet, qui est en C sous Unix mais de petite tailleet si c possible avec les deux approche SAX et parser XML [ par khalil1982 ] salut tlm,je veux parser un fichier XML en C sous Linux mais de petite taille( &lt; à 80k ), et est ce que c possible de trouver les deux approche DOM parser un document XML avec C++ [ par assiatoune ] bonjour tout le monde!ma question est la suivante:&nbsp;j'ai un document XML (un sch&#233;ma XML) et je veux extraire (avec C++) dante une structure d parser un schéma XML avec C++ [ par assiatoune ] Bonjour tout le monde, &nbsp;je vous remercie de m'avoir&nbsp;r&#233;pondu.&nbsp;&nbsp;mais mon probleme est que je suis d&#233;btante en visuel C++, décrire XML sous forme de graphe [ par convexe ] Bonjour, Je suis débutant en base de données et j'aurais besoin d'une classe C++ qui permetrait de décrire les fichiers xml sous la forme de graphe ,


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 1,108 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales