1 // Copyright (C) 2006-2008 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #include "xmlParserBase.hxx"
20 #include "Exception.hxx"
28 #include "YacsTrace.hxx"
30 // --- specific part for libxml2 ----------------------------------------------
35 #include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
37 _xmlParserCtxt* xmlParserBase::_xmlParser;
38 void xmlParserBase::XML_SetUserData(_xmlParserCtxt* ctxt,
39 xmlParserBase* parser)
41 ctxt->userData = parser;
45 // --- specific part for expat ------------------------------------------------
48 XML_Parser xmlParserBase::_xmlParser;
51 // --- generic part -----------------------------------------------------------
54 using YACS::Exception;
56 std::stack<xmlParserBase*> xmlParserBase::_stackParser;
57 std::list<xmlParserBase*> xmlParserBase::_garbage;
59 /*! callback usable only with libxml2
62 void XMLCALL xmlParserBase::start_document(void* userData)
64 //DEBTRACE("xmlParserBase::start_document");
65 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
68 /*! callback usable only with libxml2
71 void XMLCALL xmlParserBase::end_document (void* userData)
73 //DEBTRACE("xmlParserBase::end_document");
74 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
77 /*! callback called on start of an xml element: <name>
80 void XMLCALL xmlParserBase::start_element (void* userData,
84 //DEBTRACE("xmlParserBase::start_element " << name);
86 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
87 const XML_Char *aName = tochar(name);
88 currentParser->incrCount(aName);
89 currentParser->onStart(aName, p);
93 /*! callback called on end of an xml element: </name>
96 void XMLCALL xmlParserBase::end_element (void* userData,
99 //DEBTRACE("xmlParserBase::end_element");
100 const XML_Char *aName = tochar(name);
101 xmlParserBase *childParser = static_cast<xmlParserBase *> (userData);
102 _garbage.push_back(_stackParser.top());
103 DEBTRACE("xmlParserBase::end_element " << _garbage.size());
105 XML_SetUserData(_xmlParser, _stackParser.top());
106 childParser->onEnd(aName);
111 /*! callback called for significant characters inside tags: <tag>content</tag>
112 * or outside tags, like space or new line.
113 * with expat get also the CDATA tags: <tag>![CDATA[content]]></tag>
116 void XMLCALL xmlParserBase::characters (void* userData,
120 //DEBTRACE("xmlParserBase::characters " << len);
121 xmlParserBase *currentParser = (xmlParserBase *) (userData);
122 string data((char*)ch,len);
123 currentParser->charData(data);
127 /*! callback usable only with libxml2
130 void XMLCALL xmlParserBase::comment (void* userData,
131 const xmlChar* value)
133 //DEBTRACE("xmlParserBase::comment");
134 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
138 /*! callback usable only with libxml2
141 void XMLCALL xmlParserBase::warning (void* userData,
142 const char* fmt, ...)
144 DEBTRACE("xmlParserBase::warning");
145 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
148 string format = "%s";
152 parv = va_arg(args, char*);
155 else cerr << __FILE__ << " [" << __LINE__ << "] : "
156 << "error format not taken into account: " << fmt << endl;
161 /*! callback usable only with libxml2
164 void XMLCALL xmlParserBase::error (void* userData,
165 const char* fmt, ...)
167 DEBTRACE("xmlParserBase::error");
168 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
171 string format = "%s";
175 parv = va_arg(args, char*);
177 xmlParserBase *currentParser = (xmlParserBase *) userData;
178 //cerr << currentParser->element << endl;
180 else cerr << __FILE__ << " [" << __LINE__ << "] : "
181 << "error format not taken into account: " << fmt << endl;
186 /*! callback usable only with libxml2
189 void XMLCALL xmlParserBase::fatal_error (void* userData,
190 const char* fmt, ...)
192 DEBTRACE("xmlParserBase::fatal_error");
193 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
196 string format = "%s";
200 parv = va_arg(args, char*);
203 else cerr << __FILE__ << " [" << __LINE__ << "] : "
204 << "error format not taken into account: " << fmt << endl;
208 /*! callback called for CDATA inside tags: <tag>![CDATA[content]]></tag>
209 * used only by libxml2
212 void XMLCALL xmlParserBase::cdata_block (void* userData,
213 const xmlChar* value,
216 //DEBTRACE("xmlParserBase::cdata_block");
217 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
218 string data((char*)value,len);
219 currentParser->charData(data);
222 void xmlParserBase::cleanGarbage()
224 while (!_garbage.empty())
226 delete (_garbage.front());
227 _garbage.pop_front();
231 /*! Stores the tag attributes on a map. The map is an attribute of the parser
232 * object dedicated to the current xml tag
235 void xmlParserBase::getAttributes(const xmlChar** p)
239 string attributeName = (char*)*p;
240 //cerr << "attribute name " << attributeName << endl;
242 string attributeValue = (char*)*p;
243 //cerr << "attribute value " << attributeValue << endl;
245 _mapAttrib[attributeName] = attributeValue;
249 /*! Stores an attribute (key, value) on the map attribute.
250 * used for attributes defined at another tag level (child tags).
253 void xmlParserBase::setAttribute(std::string key, std::string value)
255 _mapAttrib[key] = value;
258 /*! Gets an attribute value given a string key.
259 * If the key does not exist, throws an Exception.
262 std::string xmlParserBase::getAttribute(std::string key)
264 if (_mapAttrib.find(key) == _mapAttrib.end())
266 string what = "Attribute does not exist: " + key;
267 throw Exception(what);
269 return _mapAttrib[key];
272 /*! Add data on the data attribute of the parser object dedicated to an xml tag
275 void xmlParserBase::addData(std::string value)
277 // DEBTRACE("xmlParserBase::addData()");
281 /*! all parsers must know their father parser (father tag), in order
282 * to set values or attributes in father.
285 void xmlParserBase::init (const xmlChar** p, xmlParserBase* father)
290 /*! to be specialized for each kind of xml tag
293 void xmlParserBase::onStart (const XML_Char* elem, const xmlChar** p)
297 /*! to be specialized for each kind of xml tag
300 void xmlParserBase::onEnd (const XML_Char* name)
304 /*! to be specialized following the kind of xml tag
307 void xmlParserBase::charData (std::string data)
311 /*! May be specialized for each kind of xml tag.
312 * Counts the number of tag occurences of a given type inside a context.
315 void xmlParserBase::incrCount(const XML_Char *elem)
317 if(counts.find(elem)==counts.end())
320 counts[elem]=counts[elem]+1;
323 /*! to be specialized for each kind of xml tag
326 void xmlParserBase::end()
330 /*! Throws an exception. different implementation with libxml2 and expat
333 void xmlParserBase::stopParse(std::string what)
336 xmlStopParser(_xmlParser);
339 throw Exception(what);
343 // ----------------------------------------------------------------------------
347 /*! libxml2 parser initialisation
348 * \param parser dedicated parser
351 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
356 * \param xmlFile file to parse
359 void xmlReader::parse(std::string xmlFile)
361 _rootParser->init(0);
362 _rootParser->_stackParser.push(_rootParser);
364 xmlSAXHandler baseHandler =
366 0, // internal_subset,
368 0, // hasInternalSubset
369 0, // hasExternalSubset
376 0, // unparsedEntityDecl
377 0, // setDocumentLocator
378 xmlParserBase::start_document, // startDocument
379 xmlParserBase::end_document, // endDocument
380 xmlParserBase::start_element, // startElement
381 xmlParserBase::end_element, // endElement
383 xmlParserBase::characters, // characters
384 0, // ignorableWhitespace
385 0, // processingInstruction
386 xmlParserBase::comment, // comment
387 xmlParserBase::warning, // warning
388 xmlParserBase::error, // error
389 xmlParserBase::fatal_error, // fatalError
390 0, // getParameterEntity
391 xmlParserBase::cdata_block, // cdataBlock
395 // --- sequence from libxml++, to have a libxml context
397 _xmlParserCtxt* saxContext;
398 saxContext = xmlCreateFileParserCtxt(xmlFile.c_str());
401 _rootParser->cleanGarbage();
402 string what = "problem while trying to open the file for parsing " + xmlFile;
403 throw Exception(what);
405 xmlSAXHandlerPtr old_sax = saxContext->sax;
406 saxContext->sax = &baseHandler;
407 _rootParser->_xmlParser = saxContext;
408 saxContext->userData = _rootParser;
410 xmlParseDocument(saxContext);
411 _rootParser->cleanGarbage();
412 xmlFileClose(saxContext);
413 xmlFreeParserCtxt(saxContext);
414 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
418 // ----------------------------------------------------------------------------
423 char Buffer[SIZEBUF];
425 /*! expat parser initialisation
426 * \param parser dedicated parser
429 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
431 xmlParserBase::_xmlParser= XML_ParserCreate(NULL);
434 cerr << "Couldn't allocate memory for parser" << endl;
435 throw Exception("Couldn't allocate memory for parser");
440 * \param xmlFile file to parse
443 void xmlReader::parse(std::string xmlFile)
445 FILE* fin=fopen(xmlFile.c_str(),"r");
448 std::cerr << "Couldn't open schema file" << std::endl;
449 throw std::invalid_argument("Couldn't open schema file");
450 //throw Exception("Couldn't open schema file");
453 XML_SetElementHandler(xmlParserBase::_xmlParser,
454 xmlParserBase::start_element,
455 xmlParserBase::end_element);
456 XML_SetCharacterDataHandler(xmlParserBase::_xmlParser,
457 xmlParserBase::characters );
458 XML_SetUserData(xmlParserBase::_xmlParser, _rootParser);
459 _rootParser->init(0);
460 _rootParser->_stackParser.push(_rootParser);
469 len = fread(Buffer, 1, SIZEBUF, fin);
472 std::cerr << "Read error" << std::endl;
473 throw Exception("Read error");
477 if (XML_Parse(xmlParserBase::_xmlParser, Buffer, len, done) == XML_STATUS_ERROR)
479 throw Exception(XML_ErrorString(XML_GetErrorCode(xmlParserBase::_xmlParser)));
485 XML_ParserFree (xmlParserBase::_xmlParser);
486 xmlParserBase::_xmlParser=0;
487 _rootParser->cleanGarbage();
488 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
492 _rootParser->cleanGarbage();
493 //get line number from XML parser
494 cerr << "Error at line: " << XML_GetCurrentLineNumber(xmlParserBase::_xmlParser) << endl;
500 // ----------------------------------------------------------------------------