1 | #ifndef __XML_PARSER__ |
---|
2 | #define __XML_PARSER__ |
---|
3 | |
---|
4 | #include "xmlio_std.hpp" |
---|
5 | |
---|
6 | /// HISTORIQUE /// |
---|
7 | // <RV> 20/04/10 - 23/04/10 : Nouvelle implémentation parsing, création de la classe principale XmlIOServer::XML::XMLParser. |
---|
8 | // <RV> 23/04/10 : Création de la classe abstraite XmlIOServer::XML::XMLElement + ajout de quelques commentaires. |
---|
9 | // <RV> 26/04/10 : Ajout de la gestion simplifiée des héritages descendants + gestion des flux de sortie. |
---|
10 | // <RV> 29/04/10 : Ajout de la gestion simplifiée des attributs par défaut. |
---|
11 | // <RV> 30/04/10 : Création et Vérification de la classe de test XML XmlIOServer::XML::XMLClassTest. |
---|
12 | // <RV> 03/05/10 : Nouvelle implémentation classe de test + ajout de tous les commentaires. |
---|
13 | // <RV> 04/05/10 : Suppression documentation excessive + correction de 2 problÚmes de parsing sur situations particuliÚres non gérées. |
---|
14 | |
---|
15 | /** |
---|
16 | * \file XMLParser.hpp |
---|
17 | * \brief Ce fichier contient le code source permettant de parser un fichier de configuration xml pour le serveur d'E/S. |
---|
18 | * \author Ozdoba Hervé (contact: herve.ozdoba@glsce.ipsl.fr) |
---|
19 | * \author Meurdesoif Yann (contact Yann.Meurdesoif@cea.fr) |
---|
20 | * \version 0.1.0 |
---|
21 | * \date Avril - Mai 2010 |
---|
22 | */ |
---|
23 | |
---|
24 | // Utilisation de la STL |
---|
25 | using std::string; |
---|
26 | |
---|
27 | using std::pair; |
---|
28 | using std::vector; |
---|
29 | using std::deque; |
---|
30 | |
---|
31 | using std::ifstream; |
---|
32 | using std::ostream; |
---|
33 | |
---|
34 | // Utilisation de la biliothÚque POCO |
---|
35 | using Poco::XML::DOMParser; |
---|
36 | using Poco::XML::InputSource; |
---|
37 | |
---|
38 | using Poco::XML::Document; |
---|
39 | using Poco::XML::Node; |
---|
40 | using Poco::XML::Element; |
---|
41 | |
---|
42 | using Poco::XML::NamedNodeMap; |
---|
43 | |
---|
44 | //using Poco::XML::AutoPtr; |
---|
45 | |
---|
46 | using Poco::Exception; |
---|
47 | using Poco::HashMap; |
---|
48 | |
---|
49 | /** |
---|
50 | * \namespace XmlIOServer |
---|
51 | * \brief Cet espace de nommage regroupe l'intégralité des classes du serveur des E/S. |
---|
52 | * \see XmlIOServer::XML |
---|
53 | * |
---|
54 | * Espace de nommage général qui regroupe toutes les classes dont dépend le serveur de gestion des entrées/sorties |
---|
55 | * parallÚles avec configuration par fichier de données xml. |
---|
56 | */ |
---|
57 | namespace XmlIOServer |
---|
58 | { |
---|
59 | /** |
---|
60 | * \namespace XmlIOServer::XML |
---|
61 | * \brief Cet espace de nommage contient les classes permettant de parser le fichier de configuration XML. |
---|
62 | */ |
---|
63 | namespace XML |
---|
64 | { |
---|
65 | /** |
---|
66 | * \typedef pair<string, string> TAttribute |
---|
67 | * \brief Définition d'un type pair associant un nom d'attribut à sa valeur. |
---|
68 | * \see TListAttributes |
---|
69 | * |
---|
70 | * Ce type permet de récupérer une pair contenant : |
---|
71 | * \li Le nom de l'attribut; |
---|
72 | * \li La valeur associée à l'attribut sous forme de chaîne de caractÚres. |
---|
73 | */ |
---|
74 | typedef pair<string, string> TAttribute; |
---|
75 | |
---|
76 | /** |
---|
77 | * \typedef HashMap<string, string> THashAttributes |
---|
78 | * \brief Définition d'une HashMap de TAttribute. |
---|
79 | * \see TAttribute |
---|
80 | */ |
---|
81 | typedef HashMap<string, string> THashAttributes; |
---|
82 | |
---|
83 | /** |
---|
84 | * \enum TNodeType |
---|
85 | * \brief Définition d'un type de noeud xml. |
---|
86 | */ |
---|
87 | typedef enum |
---|
88 | { |
---|
89 | UNKNOWN = 0, CONTEXT = 1, |
---|
90 | FIELD_GROUP = 2, FILE_GROUP = 3, AXIS_GROUP = 4, GRID_GROUP = 5, |
---|
91 | FIELD = 6, FILE = 7, AXIS = 8, GRID = 9 |
---|
92 | |
---|
93 | } TNodeType; |
---|
94 | |
---|
95 | /** |
---|
96 | * \struct XmlIOServer::XML::_element |
---|
97 | * \brief Association d'un type de noeud avec un HashMap des attributs qui lui sont associés. |
---|
98 | */ |
---|
99 | |
---|
100 | /** |
---|
101 | * \typedef struct XmlIOServer::XML::_element TElement |
---|
102 | * \brief Redéfinition du type _element pour simplification d'écriture. |
---|
103 | * \see _element |
---|
104 | */ |
---|
105 | typedef struct _element |
---|
106 | { |
---|
107 | /** |
---|
108 | * \fn _element(TNodeType t, THashAttributes& l) |
---|
109 | * \brief Simple constructeur du structure. |
---|
110 | * \param t Un type d'élément. |
---|
111 | * \param l Une HashMap d'attributs associé à l'élément. |
---|
112 | */ |
---|
113 | _element(TNodeType t, THashAttributes& l) : type(t),list(l) |
---|
114 | { /* Ne rien faire de plus */}; |
---|
115 | |
---|
116 | /** |
---|
117 | * \var TNodeType type |
---|
118 | * \brief Type d'élément. |
---|
119 | */ |
---|
120 | TNodeType type; |
---|
121 | |
---|
122 | /** |
---|
123 | * \var THashAttributes list |
---|
124 | * \brief HashMap d'attributs. |
---|
125 | */ |
---|
126 | THashAttributes list; //< HashMap d'attributs. |
---|
127 | |
---|
128 | } TElement; |
---|
129 | |
---|
130 | |
---|
131 | /** |
---|
132 | * \typedef deque<TElement> TListElements |
---|
133 | * \brief Liste de TElement utilisée comme pile pour la gestion (optionnelle) |
---|
134 | * de l'héritage descendant dans la classe de parsing xml. |
---|
135 | * \see XmlIOServer::XML::XMLParser::path |
---|
136 | */ |
---|
137 | typedef deque<TElement> TListElements; |
---|
138 | |
---|
139 | /** |
---|
140 | * \typedef Document* PDocument |
---|
141 | * \brief Redéfinition du pointeur sur document xml pour simplification d'écriture. |
---|
142 | */ |
---|
143 | typedef Document* PDocument; |
---|
144 | |
---|
145 | /** |
---|
146 | * \typedef Node* PNode |
---|
147 | * \brief Redéfinition du pointeur sur noeud xml pour simplification d'écriture. |
---|
148 | * \see XmlIOServer::XML::cNode |
---|
149 | */ |
---|
150 | typedef Node* PNode; |
---|
151 | |
---|
152 | /** |
---|
153 | * \class XMLElement |
---|
154 | * \brief Classe abstraite pour parsing xml. |
---|
155 | * \see XmlIOServer::XML::XMLParser |
---|
156 | * |
---|
157 | * Les classes susceptibles d'être instanciées par parsing Xml doivent hériter des fonctions de celle-ci pour être |
---|
158 | * traoter par la classe XMLParser. |
---|
159 | */ |
---|
160 | class XMLElement |
---|
161 | { |
---|
162 | public : |
---|
163 | |
---|
164 | // TODO ? Enlever le param. name serait une bonne chose ? |
---|
165 | /** |
---|
166 | * \fn XMLElement* addChild(TNodeType type, string name, THashAttributes& attr) |
---|
167 | * \brief Fonction appelée par XMLParser signifiant l'ajout d'un fils à l'élément actuel. |
---|
168 | * \param type le type du noeud à ajouter. |
---|
169 | * \param name le nom du noeud à ajouter (lié au paramêtre <i>type</i>) |
---|
170 | * \param attr une HashMap des attributs associés à l'élément à ajouter. |
---|
171 | * \return Un pointeur sur l'élément fils nouvellement créé. |
---|
172 | */ |
---|
173 | virtual XMLElement* addChild(TNodeType type, TListElements& path, THashAttributes& attr) = 0; |
---|
174 | |
---|
175 | |
---|
176 | /** |
---|
177 | * \fn XMLElement* getPReference(void) |
---|
178 | * \brief Renvoie la référence au noeud parent e l'élément actuel. |
---|
179 | * \return la référence au noeud parent. |
---|
180 | * |
---|
181 | */ |
---|
182 | virtual XMLElement* getPReference(void) = 0; |
---|
183 | |
---|
184 | }; // class XMLElement |
---|
185 | |
---|
186 | /** |
---|
187 | * \class XMLClassTest |
---|
188 | * \brief Une classe de test pour le parsing xml. |
---|
189 | * |
---|
190 | * Une simple classe de test qui écrit les arguments reçus lors du parsing vers la console. |
---|
191 | */ |
---|
192 | class XMLClassTest : public XMLElement |
---|
193 | { |
---|
194 | public: |
---|
195 | |
---|
196 | /** |
---|
197 | * \fn XMLClassTest() |
---|
198 | * \brief Simple constructeur d'initialisation d'un élément racine. |
---|
199 | */ |
---|
200 | XMLClassTest(XMLElement* ref = NULL) |
---|
201 | { |
---|
202 | this->pref = ref; |
---|
203 | //std::cout << "[simulation]" << std::endl; |
---|
204 | } |
---|
205 | |
---|
206 | /** |
---|
207 | * \fn XMLClassTest(XMLClassTest* ref, TNodeType type, string& name, THashAttributes& attr) |
---|
208 | * \brief Constructeur pour tout autre élément que celui de la racine. |
---|
209 | * \param ref Référence à l'élement parent (théorique, celui qui appelle le constructeur via la méthode addChild). |
---|
210 | * \param type Le type du noeud à instancier. |
---|
211 | * \param name Le nom du noeud à instancier. |
---|
212 | * \param attr Une HashMap des attributs liés au noeud à instancier. |
---|
213 | */ |
---|
214 | XMLClassTest(XMLClassTest* ref, TNodeType type, THashAttributes& attr) |
---|
215 | { |
---|
216 | this->pref = ref; |
---|
217 | //for(int i = 0; i<INC; i++) std::cout << " "; |
---|
218 | /*std::cout << "[" << type; |
---|
219 | |
---|
220 | for (THashAttributes::Iterator it = attr.begin(); it != attr.end(); it++) |
---|
221 | std::cout << " "<< (*it).first<< "=\"" << (*it).second << "\""; |
---|
222 | |
---|
223 | std::cout << "]" << std::endl;*/ |
---|
224 | } |
---|
225 | |
---|
226 | friend ostream& operator<< (ostream& out, const XMLClassTest& c) |
---|
227 | { out << "[Non implémentée]" << std::endl; return out; } |
---|
228 | |
---|
229 | virtual XMLClassTest* addChild(TNodeType type, TListElements& path, THashAttributes& attr) |
---|
230 | { INC++; return (new XMLClassTest(this, type, attr)); } |
---|
231 | |
---|
232 | virtual XMLElement* getPReference(void) { INC--; return (this->pref); } |
---|
233 | |
---|
234 | /** |
---|
235 | * \fn ~XMLClassTest() |
---|
236 | * \brief Simple destructeur. |
---|
237 | */ |
---|
238 | ~XMLClassTest() { /* Ne rien faire de plus */ } |
---|
239 | |
---|
240 | protected: |
---|
241 | |
---|
242 | private: |
---|
243 | |
---|
244 | /** |
---|
245 | * \var XMLClassTest* pref |
---|
246 | * \brief Référence au parent de l'élÚment actuel (NULL si on se trouve à la racine). |
---|
247 | */ |
---|
248 | XMLElement* pref; // TODO Vérifier la gestion de la mémoire. |
---|
249 | |
---|
250 | /** |
---|
251 | * \var int INC |
---|
252 | * \brief Entier permettant de connaître le niveau d'incrémentation pour l'écriture sur la sortie standard. |
---|
253 | */ |
---|
254 | static int INC; |
---|
255 | |
---|
256 | }; // class XMLClassTest |
---|
257 | |
---|
258 | int XMLClassTest::INC = 0; |
---|
259 | |
---|
260 | /** |
---|
261 | * \class XMLParser |
---|
262 | * \brief Classe qui initie le parsing d'un fichier de configuration Xml. |
---|
263 | * |
---|
264 | * Cette classe permet de parser un document XML afin de configurer le serveur des E/S.\n |
---|
265 | * Cette méthode de récupération des paramÚtres est statique puisque le traitement est effectué une fois au |
---|
266 | * démarrage du serveur.\n Elle est complémentaire d'une seconde méthode, dynamique cette fois, consistant à paramétrer |
---|
267 | * l'application par remoting client-serveur à travers MPI. |
---|
268 | */ |
---|
269 | class XMLParser |
---|
270 | { |
---|
271 | public : |
---|
272 | |
---|
273 | XMLParser(const string& filename, const string& rootName = string("simulation")) |
---|
274 | { |
---|
275 | XMLParser(); |
---|
276 | ifstream istr( filename.data() , ifstream::in ); |
---|
277 | if ((istr.good())) |
---|
278 | { // S'il est possible de lire le flux en entrée ... |
---|
279 | InputSource src(istr); |
---|
280 | DOMParser parser; |
---|
281 | |
---|
282 | // On parse la source XML et on vérifie que le premier noeud (racine) est du type "Element" |
---|
283 | // ... et à pour valeur la chaîne rootName. |
---|
284 | PDocument pDoc = parser.parse(&src); |
---|
285 | if (!(pDoc->documentElement()->nodeName().compare(rootName))) |
---|
286 | { |
---|
287 | this->cNode = pDoc->documentElement(); |
---|
288 | this->goToChildElement(); |
---|
289 | } |
---|
290 | else |
---|
291 | std::cout << "L'élément racine doit avoir pour valeur <"<< rootName <<"> (\"" |
---|
292 | << (pDoc->documentElement()->nodeName()) <<"\" lue)"<< std::endl; |
---|
293 | |
---|
294 | } |
---|
295 | else |
---|
296 | std::cout << "Impossible de lire le flux du fichier en entrée !" << std::endl; |
---|
297 | } |
---|
298 | |
---|
299 | |
---|
300 | void parse(XMLElement* const root, ostream& log = std::cout) |
---|
301 | { |
---|
302 | XMLElement* current = root; |
---|
303 | THashAttributes attr; |
---|
304 | bool start = true; |
---|
305 | |
---|
306 | do{ |
---|
307 | if(!start)path.pop_back(); |
---|
308 | while((start) ? start : this->goToNextElement()) // PARCOURS SUR ELEMENT SUIVANT |
---|
309 | { |
---|
310 | // APPEL ADD PARENT |
---|
311 | if(!start)path.pop_back(); |
---|
312 | |
---|
313 | this->getAttributes(attr); |
---|
314 | path.push_back(TElement(this->getElementType(), attr)); |
---|
315 | current = current->addChild(this->getElementType(),this->getTreePath(), attr); |
---|
316 | attr.clear(); |
---|
317 | |
---|
318 | while (this->goToChildElement()) // PARCOURS SUR ELEMENT ENFANT |
---|
319 | { |
---|
320 | // APPEL ADD LOCAL |
---|
321 | this->getAttributes(attr); // ou getGlobalAttributes pour gestion de l'héritage descendant. |
---|
322 | path.push_back(TElement(this->getElementType(), attr)); |
---|
323 | current = current->addChild(this->getElementType(),this->getTreePath(), attr); |
---|
324 | attr.clear(); |
---|
325 | } |
---|
326 | |
---|
327 | current = current->getPReference(); |
---|
328 | |
---|
329 | if (start) start = false; |
---|
330 | } |
---|
331 | |
---|
332 | if(current == root ) break; |
---|
333 | else current = current->getPReference(); |
---|
334 | |
---|
335 | } while(this->goToParentElement()); // PARCOURS SUR ELEMENT PARENT |
---|
336 | |
---|
337 | return; |
---|
338 | } |
---|
339 | |
---|
340 | ~XMLParser() |
---|
341 | { /* Ne rien faire pour le moment*/ } |
---|
342 | |
---|
343 | static void ClassTest(const char* path) |
---|
344 | { |
---|
345 | try |
---|
346 | { |
---|
347 | // Instanciation du parseur. |
---|
348 | XMLParser parser(path); |
---|
349 | // Instanciation de l'objet racine. |
---|
350 | XMLClassTest root ; |
---|
351 | |
---|
352 | // Début du parsing XML ... |
---|
353 | parser.parse(&root); |
---|
354 | } |
---|
355 | catch (Exception& exc) |
---|
356 | { |
---|
357 | // TODO : Remplacer sorties vers cerr et cout par exception |
---|
358 | std::cerr << (exc.displayText()) << std::endl; |
---|
359 | } |
---|
360 | |
---|
361 | return; |
---|
362 | } |
---|
363 | |
---|
364 | TListElements& getTreePath() { return (this->path); } |
---|
365 | void setTreePath(const TListElements& p) { this->path = p; } |
---|
366 | |
---|
367 | protected : |
---|
368 | |
---|
369 | TNodeType getElementType(void) const |
---|
370 | { |
---|
371 | if(this->isElementName("context"))return (CONTEXT); |
---|
372 | |
---|
373 | // les groupes, quels qu'ils soient. |
---|
374 | if(this->isElementName("field_definition") or this->isElementName("field_group"))return (FIELD_GROUP); |
---|
375 | if(this->isElementName("file_definition") or this->isElementName("file_group")) return (FILE_GROUP); |
---|
376 | if(this->isElementName("axis_definition") or this->isElementName("axis_group")) return (AXIS_GROUP); |
---|
377 | if(this->isElementName("grid_definition") or this->isElementName("grid_group")) return (GRID_GROUP); |
---|
378 | |
---|
379 | // les éléments finaux (hormis "file"). |
---|
380 | if(this->isElementName("field"))return (FIELD); |
---|
381 | if(this->isElementName("file")) return (FILE); |
---|
382 | if(this->isElementName("axis")) return (AXIS); |
---|
383 | if(this->isElementName("grid")) return (GRID); |
---|
384 | |
---|
385 | return (UNKNOWN); |
---|
386 | } |
---|
387 | |
---|
388 | //////////////////////// PARSING ////////////////////////////// |
---|
389 | |
---|
390 | // TODO voir pour récupérer une référence. |
---|
391 | string getElementName(void) const {return (this->cNode->nodeName());} |
---|
392 | |
---|
393 | bool isElementName(const char* val) const {return !(this->getElementName().compare(string(val)));} |
---|
394 | |
---|
395 | bool goToNextElement(Node* nextElement = 0) |
---|
396 | { |
---|
397 | nextElement = (!nextElement)? this->cNode->nextSibling() : nextElement; |
---|
398 | |
---|
399 | // On parcourt la liste des "siblings" jusqu'à trouver un élément quelconque. |
---|
400 | for(; ; nextElement = nextElement->nextSibling()) |
---|
401 | if (nextElement == NULL) break; |
---|
402 | else if (nextElement->nodeType() == 1) |
---|
403 | {// Si l'un des noeuds est un élément... |
---|
404 | this->setCurrentNode(nextElement); |
---|
405 | return (true); |
---|
406 | } |
---|
407 | return (false); |
---|
408 | } |
---|
409 | |
---|
410 | bool goToChildElement(void) |
---|
411 | { |
---|
412 | // On parcourt la liste des enfants jusqu'à trouver un élément quelconque. |
---|
413 | if (this->cNode->firstChild()) |
---|
414 | if (this->goToNextElement(this->cNode->firstChild())) |
---|
415 | return (true); |
---|
416 | |
---|
417 | return (false); |
---|
418 | } |
---|
419 | |
---|
420 | bool goToParentElement(void) |
---|
421 | { |
---|
422 | // Pas de retour au parent si on est à la racine. |
---|
423 | if (!(this->getElementName().compare(string("simulation")))) return (false); |
---|
424 | this->setCurrentNode(this->cNode->parentNode()); |
---|
425 | return (true); |
---|
426 | } |
---|
427 | |
---|
428 | bool getAttributes(THashAttributes& attributes) |
---|
429 | { |
---|
430 | if(!this->cNode->hasAttributes()) return (false); |
---|
431 | NamedNodeMap* map = this->cNode->attributes(); |
---|
432 | |
---|
433 | for(unsigned int i = 0; i< map->length(); i++) |
---|
434 | attributes[map->item(i)->nodeName()] = map->item(i)->nodeValue(); |
---|
435 | |
---|
436 | return (true); |
---|
437 | } |
---|
438 | |
---|
439 | private : |
---|
440 | |
---|
441 | XMLParser() : path() //pDoc(), cNode() << Ancien |
---|
442 | { /* Ne rien faire de plus */ } |
---|
443 | |
---|
444 | bool setCurrentNode(PNode node){ if (!node) return false; this->cNode = node; return (true);} |
---|
445 | PNode getCurrentNode(void){return (this->cNode);} |
---|
446 | |
---|
447 | /** |
---|
448 | * \var AElement cNode |
---|
449 | * \brief Pointeur sur l'objet représentant l'élément courant. |
---|
450 | */ |
---|
451 | PNode cNode; |
---|
452 | |
---|
453 | TListElements path; |
---|
454 | |
---|
455 | };// class XMLParser |
---|
456 | |
---|
457 | };// namespace XML |
---|
458 | |
---|
459 | };// namespace XmlIOServer |
---|
460 | |
---|
461 | #endif //__XML_PARSER__ |
---|
462 | |
---|