]> SALOME platform Git repositories - modules/yacs.git/blob - src/yacsloader/xmlParserBase.cxx
Salome HOME
copy tag mergefrom_BR_V0_1_CC_Salome_04oct07
[modules/yacs.git] / src / yacsloader / xmlParserBase.cxx
1
2 #include "xmlParserBase.hxx"
3 #include "Exception.hxx"
4
5 #include <stdexcept>
6 #include <iostream>
7 #include <cstdarg>
8 #include <cassert>
9
10 //#define _DEVDEBUG_
11 #include "YacsTrace.hxx"
12
13 // --- specific part for libxml2 ----------------------------------------------
14
15 #ifdef USE_LIBXML2
16 extern "C"
17 {
18 #include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
19 }
20 _xmlParserCtxt* xmlParserBase::_xmlParser;
21 void xmlParserBase::XML_SetUserData(_xmlParserCtxt* ctxt,
22                                     xmlParserBase* parser)
23 {
24   ctxt->userData = parser;
25 }
26 #endif
27
28 // --- specific part for expat ------------------------------------------------
29
30 #ifdef USE_EXPAT
31 XML_Parser xmlParserBase::_xmlParser;
32 #endif
33
34 // --- generic part -----------------------------------------------------------
35
36 using namespace std;
37 using YACS::Exception;
38
39 std::stack<xmlParserBase*> xmlParserBase::_stackParser;
40 std::list<xmlParserBase*>  xmlParserBase::_garbage;
41
42 /*! callback usable only with libxml2
43  */
44
45 void XMLCALL xmlParserBase::start_document(void* userData)
46 {
47   //DEBTRACE("xmlParserBase::start_document");
48   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
49 }
50
51 /*! callback usable only with libxml2
52  */
53
54 void XMLCALL xmlParserBase::end_document  (void* userData)
55 {
56   //DEBTRACE("xmlParserBase::end_document");
57   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
58 }
59
60 /*! callback called on start of an xml element: <name>
61  */
62
63 void XMLCALL xmlParserBase::start_element (void* userData,
64                                            const xmlChar* name,
65                                            const xmlChar** p)
66 {
67   //DEBTRACE("xmlParserBase::start_element " << name);
68   cleanGarbage();
69   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
70   const XML_Char *aName = tochar(name);
71   currentParser->incrCount(aName);
72   currentParser->onStart(aName, p);
73 }
74
75
76 /*! callback called on end of an xml element: </name>
77  */
78
79 void XMLCALL xmlParserBase::end_element   (void* userData,
80                                            const xmlChar* name)
81 {
82   //DEBTRACE("xmlParserBase::end_element");
83   const XML_Char *aName = tochar(name);
84   xmlParserBase *childParser = static_cast<xmlParserBase *> (userData);
85   _garbage.push_back(_stackParser.top());
86   DEBTRACE("xmlParserBase::end_element " << _garbage.size());
87   _stackParser.pop();
88   XML_SetUserData(_xmlParser, _stackParser.top());
89   childParser->onEnd(aName);
90   childParser->end();
91  }
92
93
94 /*! callback called for significant characters inside tags: <tag>content</tag>
95  *  or outside tags, like space or new line. 
96  *  with expat get also the CDATA tags: <tag>![CDATA[content]]></tag>
97  */
98
99 void XMLCALL xmlParserBase::characters    (void* userData,
100                                            const xmlChar* ch,
101                                            int len)
102 {
103   //DEBTRACE("xmlParserBase::characters " << len);
104   xmlParserBase *currentParser = (xmlParserBase *) (userData);
105   string data((char*)ch,len);
106   currentParser->charData(data);
107 }
108
109
110 /*! callback usable only with libxml2
111  */
112
113 void XMLCALL xmlParserBase::comment       (void* userData,
114                                            const xmlChar* value)
115 {
116   //DEBTRACE("xmlParserBase::comment");
117   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
118 }
119
120
121 /*! callback usable only with libxml2
122  */
123
124 void XMLCALL xmlParserBase::warning       (void* userData,
125                                            const char* fmt, ...)
126 {
127   DEBTRACE("xmlParserBase::warning");
128   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
129   va_list args;
130   va_start(args, fmt);
131   string format = "%s";
132   if (format == fmt)
133     {
134       char* parv;
135       parv = va_arg(args, char*);
136       cerr << parv ;
137     }
138   else cerr << __FILE__ << " [" << __LINE__ << "] : " 
139             << "error format not taken into account: " << fmt << endl;
140   va_end(args);
141 }
142
143
144 /*! callback usable only with libxml2
145  */
146
147 void XMLCALL xmlParserBase::error         (void* userData,
148                                            const char* fmt, ...)
149 {
150   DEBTRACE("xmlParserBase::error");
151   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
152   va_list args;
153   va_start(args, fmt);
154   string format = "%s";
155   if (format == fmt)
156     {
157       char* parv;
158       parv = va_arg(args, char*);
159       cerr << parv ;
160       xmlParserBase *currentParser = (xmlParserBase *) userData;
161       //cerr << currentParser->element << endl;
162     }
163   else cerr << __FILE__ << " [" << __LINE__ << "] : " 
164             << "error format not taken into account: " << fmt << endl;
165   va_end(args);
166 }
167
168
169 /*! callback usable only with libxml2
170  */
171
172 void XMLCALL xmlParserBase::fatal_error   (void* userData,
173                                            const char* fmt, ...)
174 {
175   DEBTRACE("xmlParserBase::fatal_error");
176   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
177   va_list args;
178   va_start(args, fmt);
179   string format = "%s";
180   if (format == fmt)
181     {
182       char* parv;
183       parv = va_arg(args, char*);
184       cerr << parv ;
185     }
186   else cerr << __FILE__ << " [" << __LINE__ << "] : " 
187             << "error format not taken into account: " << fmt << endl;
188   va_end(args);
189 }
190
191 /*! callback called for CDATA inside tags: <tag>![CDATA[content]]></tag>
192  *  used only by libxml2
193  */
194
195 void XMLCALL xmlParserBase::cdata_block   (void* userData,
196                                            const xmlChar* value,
197                                            int len)
198 {
199   //DEBTRACE("xmlParserBase::cdata_block");
200   xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
201   string data((char*)value,len);
202   currentParser->charData(data);
203 }
204
205 void xmlParserBase::cleanGarbage()
206 {
207   while (!_garbage.empty())
208     {
209       delete (_garbage.front());
210       _garbage.pop_front();
211     }
212 }
213
214 /*! Stores the tag attributes on a map. The map is an attribute of the parser
215  *  object dedicated to the current xml tag
216  */
217
218 void xmlParserBase::getAttributes(const xmlChar** p)
219 {
220   if (p) while (*p)
221     {
222       string attributeName = (char*)*p;
223       //cerr << "attribute name " << attributeName << endl;
224       p++;
225       string attributeValue = (char*)*p;
226       //cerr << "attribute value " << attributeValue << endl;
227       p++;
228       _mapAttrib[attributeName] = attributeValue;
229     }
230 }
231
232 /*! Stores an attribute (key, value) on the map attribute.
233  *  used for attributes defined at another tag level (child tags). 
234  */
235
236 void xmlParserBase::setAttribute(std::string key, std::string value)
237 {
238   _mapAttrib[key] = value;
239 }
240
241 /*! Gets an attribute value given a string key.
242  *  If the key does not exist, throws an Exception.
243  */
244
245 std::string xmlParserBase::getAttribute(std::string key)
246 {
247   if (_mapAttrib.find(key) == _mapAttrib.end())
248     {
249       string what = "Attribute does not exist: " + key;
250       throw Exception(what);
251     }
252   return _mapAttrib[key];
253 }
254
255 /*! Add data on the data attribute of the parser object dedicated to an xml tag
256  */
257
258 void xmlParserBase::addData(std::string value)
259 {
260   //  DEBTRACE("xmlParserBase::addData()");
261   _data += value;
262 }
263
264 /*! all parsers must know their father parser (father tag), in order
265  *  to set values or attributes in father.
266  */
267
268 void xmlParserBase::init (const xmlChar** p, xmlParserBase* father)
269 {
270   _father = father;
271 }
272
273 /*! to be specialized for each kind of xml tag
274  */
275
276 void xmlParserBase::onStart  (const XML_Char* elem, const xmlChar** p)
277 {
278 }
279
280 /*! to be specialized for each kind of xml tag
281  */
282
283 void xmlParserBase::onEnd    (const XML_Char* name)
284 {
285 }
286
287 /*! to be specialized following the kind of xml tag
288  */
289
290 void xmlParserBase::charData (std::string data)
291 {
292 }
293
294 /*! May be specialized for each kind of xml tag.
295  *  Counts the number of tag occurences of a given type inside a context.
296  */
297
298 void xmlParserBase::incrCount(const XML_Char *elem)
299 {
300   if(counts.find(elem)==counts.end())
301     counts[elem]=1;
302   else
303     counts[elem]=counts[elem]+1;
304 }
305
306 /*! to be specialized for each kind of xml tag
307  */
308
309 void xmlParserBase::end()
310 {
311 }
312
313 /*! Throws an exception. different implementation with libxml2 and expat
314  */
315
316 void xmlParserBase::stopParse(std::string what)
317 {
318 #ifdef USE_LIBXML2
319   xmlStopParser(_xmlParser);
320 #endif
321 #ifdef USE_EXPAT
322   throw Exception(what);
323 #endif  
324 }
325
326 // ----------------------------------------------------------------------------
327
328 #ifdef USE_LIBXML2
329
330 /*! libxml2 parser initialisation
331  * \param parser dedicated parser
332  */
333
334 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
335 {
336 }
337
338 /*! libxml2 parse
339  * \param xmlFile file to parse
340  */
341
342 void xmlReader::parse(std::string xmlFile)
343 {
344   _rootParser->init(0);
345   _rootParser->_stackParser.push(_rootParser);
346
347   xmlSAXHandler baseHandler = 
348     {
349       0,  // internal_subset,
350       0,  // isStandalone
351       0,  // hasInternalSubset
352       0,  // hasExternalSubset
353       0,  // resolveEntity
354       0,  // getEntity
355       0,  // entityDecl
356       0,  // notationDecl
357       0,  // attributeDecl
358       0,  // elementDecl
359       0,  // unparsedEntityDecl
360       0,  // setDocumentLocator
361       xmlParserBase::start_document, // startDocument
362       xmlParserBase::end_document,   // endDocument
363       xmlParserBase::start_element,  // startElement
364       xmlParserBase::end_element,    // endElement
365       0,  // reference
366       xmlParserBase::characters,     // characters
367       0,  // ignorableWhitespace
368       0,  // processingInstruction
369       xmlParserBase::comment,        // comment
370       xmlParserBase::warning,        // warning
371       xmlParserBase::error,          // error
372       xmlParserBase::fatal_error,    // fatalError
373       0,  // getParameterEntity
374       xmlParserBase::cdata_block,    // cdataBlock
375       0  // externalSubset
376     };
377
378   // --- sequence from libxml++, to have a libxml context
379
380   _xmlParserCtxt* saxContext;
381   saxContext = xmlCreateFileParserCtxt(xmlFile.c_str());
382   if (!saxContext)
383     {
384       _rootParser->cleanGarbage();
385       string what = "problem while trying to open the file for parsing " + xmlFile;
386       throw Exception(what);
387     }
388   xmlSAXHandlerPtr old_sax = saxContext->sax;
389   saxContext->sax = &baseHandler;
390   _rootParser->_xmlParser = saxContext;
391   saxContext->userData = _rootParser;
392
393   xmlParseDocument(saxContext);
394   _rootParser->cleanGarbage();
395   DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
396 }
397 #endif
398
399 // ----------------------------------------------------------------------------
400
401 #ifdef USE_EXPAT
402
403 #define SIZEBUF        8192
404 char Buffer[SIZEBUF];
405
406 /*! expat parser initialisation
407  * \param parser dedicated parser
408  */
409
410 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
411 {
412   xmlParserBase::_xmlParser= XML_ParserCreate(NULL);
413   if (! _rootParser ) 
414     {
415       cerr << "Couldn't allocate memory for parser" << endl;
416       throw Exception("Couldn't allocate memory for parser");
417     }
418 }
419
420 /*! expat parse
421  * \param xmlFile file to parse
422  */
423
424 void xmlReader::parse(std::string xmlFile)
425 {
426   FILE* fin=fopen(xmlFile.c_str(),"r");
427   if (! fin) 
428     {
429       std::cerr << "Couldn't open schema file" << std::endl;
430       throw std::invalid_argument("Couldn't open schema file");
431       //throw Exception("Couldn't open schema file");
432     }
433
434   XML_SetElementHandler(xmlParserBase::_xmlParser,
435                         xmlParserBase::start_element,
436                         xmlParserBase::end_element);
437   XML_SetCharacterDataHandler(xmlParserBase::_xmlParser,
438                               xmlParserBase::characters );
439   XML_SetUserData(xmlParserBase::_xmlParser, _rootParser);
440   _rootParser->init(0);
441   _rootParser->_stackParser.push(_rootParser);
442
443   try
444     {
445       for (;;) 
446         {
447           int done;
448           int len;
449
450           len = fread(Buffer, 1, SIZEBUF, fin);
451           if (ferror(fin)) 
452             {
453               std::cerr << "Read error" << std::endl;
454               throw Exception("Read error");
455             }
456           done = feof(fin);
457
458           if (XML_Parse(xmlParserBase::_xmlParser, Buffer, len, done) == XML_STATUS_ERROR) 
459             {
460               throw Exception(XML_ErrorString(XML_GetErrorCode(xmlParserBase::_xmlParser)));
461             }
462
463           if (done)
464             break;
465         }
466       XML_ParserFree (xmlParserBase::_xmlParser);
467       xmlParserBase::_xmlParser=0;
468       _rootParser->cleanGarbage();
469       DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
470     }
471   catch(Exception& e)
472     {
473       _rootParser->cleanGarbage();
474       //get line number from XML parser
475       cerr << "Error at line: " << XML_GetCurrentLineNumber(xmlParserBase::_xmlParser) << endl;
476       throw e;
477     }
478 }
479 #endif
480
481 // ----------------------------------------------------------------------------