2 #include "xmlParserBase.hxx"
3 #include "Exception.hxx"
11 #include "YacsTrace.hxx"
13 // --- specific part for libxml2 ----------------------------------------------
18 #include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
20 _xmlParserCtxt* xmlParserBase::_xmlParser;
21 void xmlParserBase::XML_SetUserData(_xmlParserCtxt* ctxt,
22 xmlParserBase* parser)
24 ctxt->userData = parser;
28 // --- specific part for expat ------------------------------------------------
31 XML_Parser xmlParserBase::_xmlParser;
34 // --- generic part -----------------------------------------------------------
37 using YACS::Exception;
39 std::stack<xmlParserBase*> xmlParserBase::_stackParser;
40 std::list<xmlParserBase*> xmlParserBase::_garbage;
42 /*! callback usable only with libxml2
45 void XMLCALL xmlParserBase::start_document(void* userData)
47 //DEBTRACE("xmlParserBase::start_document");
48 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
51 /*! callback usable only with libxml2
54 void XMLCALL xmlParserBase::end_document (void* userData)
56 //DEBTRACE("xmlParserBase::end_document");
57 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
60 /*! callback called on start of an xml element: <name>
63 void XMLCALL xmlParserBase::start_element (void* userData,
67 //DEBTRACE("xmlParserBase::start_element " << name);
69 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
70 const XML_Char *aName = tochar(name);
71 currentParser->incrCount(aName);
72 currentParser->onStart(aName, p);
76 /*! callback called on end of an xml element: </name>
79 void XMLCALL xmlParserBase::end_element (void* userData,
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());
88 XML_SetUserData(_xmlParser, _stackParser.top());
89 childParser->onEnd(aName);
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>
99 void XMLCALL xmlParserBase::characters (void* userData,
103 //DEBTRACE("xmlParserBase::characters " << len);
104 xmlParserBase *currentParser = (xmlParserBase *) (userData);
105 string data((char*)ch,len);
106 currentParser->charData(data);
110 /*! callback usable only with libxml2
113 void XMLCALL xmlParserBase::comment (void* userData,
114 const xmlChar* value)
116 //DEBTRACE("xmlParserBase::comment");
117 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
121 /*! callback usable only with libxml2
124 void XMLCALL xmlParserBase::warning (void* userData,
125 const char* fmt, ...)
127 DEBTRACE("xmlParserBase::warning");
128 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
131 string format = "%s";
135 parv = va_arg(args, char*);
138 else cerr << __FILE__ << " [" << __LINE__ << "] : "
139 << "error format not taken into account: " << fmt << endl;
144 /*! callback usable only with libxml2
147 void XMLCALL xmlParserBase::error (void* userData,
148 const char* fmt, ...)
150 DEBTRACE("xmlParserBase::error");
151 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
154 string format = "%s";
158 parv = va_arg(args, char*);
160 xmlParserBase *currentParser = (xmlParserBase *) userData;
161 //cerr << currentParser->element << endl;
163 else cerr << __FILE__ << " [" << __LINE__ << "] : "
164 << "error format not taken into account: " << fmt << endl;
169 /*! callback usable only with libxml2
172 void XMLCALL xmlParserBase::fatal_error (void* userData,
173 const char* fmt, ...)
175 DEBTRACE("xmlParserBase::fatal_error");
176 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
179 string format = "%s";
183 parv = va_arg(args, char*);
186 else cerr << __FILE__ << " [" << __LINE__ << "] : "
187 << "error format not taken into account: " << fmt << endl;
191 /*! callback called for CDATA inside tags: <tag>![CDATA[content]]></tag>
192 * used only by libxml2
195 void XMLCALL xmlParserBase::cdata_block (void* userData,
196 const xmlChar* value,
199 //DEBTRACE("xmlParserBase::cdata_block");
200 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
201 string data((char*)value,len);
202 currentParser->charData(data);
205 void xmlParserBase::cleanGarbage()
207 while (!_garbage.empty())
209 delete (_garbage.front());
210 _garbage.pop_front();
214 /*! Stores the tag attributes on a map. The map is an attribute of the parser
215 * object dedicated to the current xml tag
218 void xmlParserBase::getAttributes(const xmlChar** p)
222 string attributeName = (char*)*p;
223 //cerr << "attribute name " << attributeName << endl;
225 string attributeValue = (char*)*p;
226 //cerr << "attribute value " << attributeValue << endl;
228 _mapAttrib[attributeName] = attributeValue;
232 /*! Stores an attribute (key, value) on the map attribute.
233 * used for attributes defined at another tag level (child tags).
236 void xmlParserBase::setAttribute(std::string key, std::string value)
238 _mapAttrib[key] = value;
241 /*! Gets an attribute value given a string key.
242 * If the key does not exist, throws an Exception.
245 std::string xmlParserBase::getAttribute(std::string key)
247 if (_mapAttrib.find(key) == _mapAttrib.end())
249 string what = "Attribute does not exist: " + key;
250 throw Exception(what);
252 return _mapAttrib[key];
255 /*! Add data on the data attribute of the parser object dedicated to an xml tag
258 void xmlParserBase::addData(std::string value)
260 // DEBTRACE("xmlParserBase::addData()");
264 /*! all parsers must know their father parser (father tag), in order
265 * to set values or attributes in father.
268 void xmlParserBase::init (const xmlChar** p, xmlParserBase* father)
273 /*! to be specialized for each kind of xml tag
276 void xmlParserBase::onStart (const XML_Char* elem, const xmlChar** p)
280 /*! to be specialized for each kind of xml tag
283 void xmlParserBase::onEnd (const XML_Char* name)
287 /*! to be specialized following the kind of xml tag
290 void xmlParserBase::charData (std::string data)
294 /*! May be specialized for each kind of xml tag.
295 * Counts the number of tag occurences of a given type inside a context.
298 void xmlParserBase::incrCount(const XML_Char *elem)
300 if(counts.find(elem)==counts.end())
303 counts[elem]=counts[elem]+1;
306 /*! to be specialized for each kind of xml tag
309 void xmlParserBase::end()
313 /*! Throws an exception. different implementation with libxml2 and expat
316 void xmlParserBase::stopParse(std::string what)
319 xmlStopParser(_xmlParser);
322 throw Exception(what);
326 // ----------------------------------------------------------------------------
330 /*! libxml2 parser initialisation
331 * \param parser dedicated parser
334 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
339 * \param xmlFile file to parse
342 void xmlReader::parse(std::string xmlFile)
344 _rootParser->init(0);
345 _rootParser->_stackParser.push(_rootParser);
347 xmlSAXHandler baseHandler =
349 0, // internal_subset,
351 0, // hasInternalSubset
352 0, // hasExternalSubset
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
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
378 // --- sequence from libxml++, to have a libxml context
380 _xmlParserCtxt* saxContext;
381 saxContext = xmlCreateFileParserCtxt(xmlFile.c_str());
384 _rootParser->cleanGarbage();
385 string what = "problem while trying to open the file for parsing " + xmlFile;
386 throw Exception(what);
388 xmlSAXHandlerPtr old_sax = saxContext->sax;
389 saxContext->sax = &baseHandler;
390 _rootParser->_xmlParser = saxContext;
391 saxContext->userData = _rootParser;
393 xmlParseDocument(saxContext);
394 _rootParser->cleanGarbage();
395 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
399 // ----------------------------------------------------------------------------
404 char Buffer[SIZEBUF];
406 /*! expat parser initialisation
407 * \param parser dedicated parser
410 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
412 xmlParserBase::_xmlParser= XML_ParserCreate(NULL);
415 cerr << "Couldn't allocate memory for parser" << endl;
416 throw Exception("Couldn't allocate memory for parser");
421 * \param xmlFile file to parse
424 void xmlReader::parse(std::string xmlFile)
426 FILE* fin=fopen(xmlFile.c_str(),"r");
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");
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);
450 len = fread(Buffer, 1, SIZEBUF, fin);
453 std::cerr << "Read error" << std::endl;
454 throw Exception("Read error");
458 if (XML_Parse(xmlParserBase::_xmlParser, Buffer, len, done) == XML_STATUS_ERROR)
460 throw Exception(XML_ErrorString(XML_GetErrorCode(xmlParserBase::_xmlParser)));
466 XML_ParserFree (xmlParserBase::_xmlParser);
467 xmlParserBase::_xmlParser=0;
468 _rootParser->cleanGarbage();
469 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
473 _rootParser->cleanGarbage();
474 //get line number from XML parser
475 cerr << "Error at line: " << XML_GetCurrentLineNumber(xmlParserBase::_xmlParser) << endl;
481 // ----------------------------------------------------------------------------