1 // Copyright (C) 2006-2013 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
20 #include "xmlParserBase.hxx"
21 #include "Exception.hxx"
30 #include "YacsTrace.hxx"
32 // --- specific part for libxml2 ----------------------------------------------
37 #include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
39 _xmlParserCtxt* xmlParserBase::_xmlParser;
40 void xmlParserBase::XML_SetUserData(_xmlParserCtxt* ctxt,
41 xmlParserBase* parser)
43 ctxt->userData = parser;
47 // --- specific part for expat ------------------------------------------------
50 XML_Parser xmlParserBase::_xmlParser;
53 // --- generic part -----------------------------------------------------------
56 using YACS::Exception;
58 std::stack<xmlParserBase*> xmlParserBase::_stackParser;
59 std::list<xmlParserBase*> xmlParserBase::_garbage;
61 /*! callback usable only with libxml2
64 void XMLCALL xmlParserBase::start_document(void* userData)
66 //DEBTRACE("xmlParserBase::start_document");
67 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
70 /*! callback usable only with libxml2
73 void XMLCALL xmlParserBase::end_document (void* userData)
75 //DEBTRACE("xmlParserBase::end_document");
76 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
79 /*! callback called on start of an xml element: \verbatim <name> \endverbatim
82 void XMLCALL xmlParserBase::start_element (void* userData,
86 //DEBTRACE("xmlParserBase::start_element " << name);
88 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
89 const XML_Char *aName = tochar(name);
90 currentParser->incrCount(aName);
91 currentParser->onStart(aName, p);
95 /*! callback called on end of an xml element: \verbatim </name> \endverbatim
98 void XMLCALL xmlParserBase::end_element (void* userData,
101 //DEBTRACE("xmlParserBase::end_element");
102 const XML_Char *aName = tochar(name);
103 xmlParserBase *childParser = static_cast<xmlParserBase *> (userData);
104 _garbage.push_back(_stackParser.top());
105 DEBTRACE("xmlParserBase::end_element " << _garbage.size());
107 XML_SetUserData(_xmlParser, _stackParser.top());
108 childParser->onEnd(aName);
113 /*! callback called for significant characters inside tags: \verbatim <tag>content</tag> \endverbatim
114 * or outside tags, like space or new line.
115 * with expat get also the CDATA tags: \verbatim <tag>![CDATA[content]]></tag> \endverbatim
118 void XMLCALL xmlParserBase::characters (void* userData,
122 //DEBTRACE("xmlParserBase::characters " << len);
123 xmlParserBase *currentParser = (xmlParserBase *) (userData);
124 string data((char*)ch,len);
125 currentParser->charData(data);
129 /*! callback usable only with libxml2
132 void XMLCALL xmlParserBase::comment (void* userData,
133 const xmlChar* value)
135 //DEBTRACE("xmlParserBase::comment");
136 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
140 /*! callback usable only with libxml2
143 void XMLCALL xmlParserBase::warning (void* userData,
144 const char* fmt, ...)
146 DEBTRACE("xmlParserBase::warning");
147 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
150 string format = "%s";
154 parv = va_arg(args, char*);
157 else cerr << __FILE__ << " [" << __LINE__ << "] : "
158 << "error format not taken into account: " << fmt << endl;
163 /*! callback usable only with libxml2
166 void XMLCALL xmlParserBase::error (void* userData,
167 const char* fmt, ...)
169 DEBTRACE("xmlParserBase::error");
170 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
173 string format = "%s";
177 parv = va_arg(args, char*);
179 xmlParserBase *currentParser = (xmlParserBase *) userData;
180 //cerr << currentParser->element << endl;
182 else cerr << __FILE__ << " [" << __LINE__ << "] : "
183 << "error format not taken into account: " << fmt << endl;
188 /*! callback usable only with libxml2
191 void XMLCALL xmlParserBase::fatal_error (void* userData,
192 const char* fmt, ...)
194 DEBTRACE("xmlParserBase::fatal_error");
195 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
198 string format = "%s";
202 parv = va_arg(args, char*);
205 else cerr << __FILE__ << " [" << __LINE__ << "] : "
206 << "error format not taken into account: " << fmt << endl;
210 /*! callback called for CDATA inside tags: \verbatim <tag>![CDATA[content]]></tag> \endverbatim
211 * used only by libxml2
214 void XMLCALL xmlParserBase::cdata_block (void* userData,
215 const xmlChar* value,
218 //DEBTRACE("xmlParserBase::cdata_block");
219 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
220 string data((char*)value,len);
221 currentParser->charData(data);
224 void xmlParserBase::cleanGarbage()
226 while (!_garbage.empty())
228 delete (_garbage.front());
229 _garbage.pop_front();
233 /*! Stores the tag attributes on a map. The map is an attribute of the parser
234 * object dedicated to the current xml tag
237 void xmlParserBase::getAttributes(const xmlChar** p)
241 string attributeName = (char*)*p;
242 //cerr << "attribute name " << attributeName << endl;
244 string attributeValue = (char*)*p;
245 //cerr << "attribute value " << attributeValue << endl;
247 _mapAttrib[attributeName] = attributeValue;
251 /*! Stores an attribute (key, value) on the map attribute.
252 * used for attributes defined at another tag level (child tags).
255 void xmlParserBase::setAttribute(std::string key, std::string value)
257 _mapAttrib[key] = value;
260 /*! Gets an attribute value given a string key.
261 * If the key does not exist, throws an Exception.
264 std::string xmlParserBase::getAttribute(std::string key)
266 if (_mapAttrib.find(key) == _mapAttrib.end())
268 string what = "Attribute does not exist: " + key;
269 throw Exception(what);
271 return _mapAttrib[key];
274 /*! Add data on the data attribute of the parser object dedicated to an xml tag
277 void xmlParserBase::addData(std::string value)
279 // DEBTRACE("xmlParserBase::addData()");
283 /*! all parsers must know their father parser (father tag), in order
284 * to set values or attributes in father.
287 void xmlParserBase::init (const xmlChar** p, xmlParserBase* father)
292 /*! to be specialized for each kind of xml tag
295 void xmlParserBase::onStart (const XML_Char* elem, const xmlChar** p)
299 /*! to be specialized for each kind of xml tag
302 void xmlParserBase::onEnd (const XML_Char* name)
306 /*! to be specialized following the kind of xml tag
309 void xmlParserBase::charData (std::string data)
313 /*! May be specialized for each kind of xml tag.
314 * Counts the number of tag occurences of a given type inside a context.
317 void xmlParserBase::incrCount(const XML_Char *elem)
319 if(counts.find(elem)==counts.end())
322 counts[elem]=counts[elem]+1;
325 /*! to be specialized for each kind of xml tag
328 void xmlParserBase::end()
332 /*! Throws an exception. different implementation with libxml2 and expat
335 void xmlParserBase::stopParse(std::string what)
338 xmlStopParser(_xmlParser);
341 throw Exception(what);
345 // ----------------------------------------------------------------------------
349 /*! libxml2 parser initialisation
350 * \param parser dedicated parser
353 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
358 * \param xmlFile file to parse
361 void xmlReader::parse(std::string xmlFile)
363 _rootParser->init(0);
364 _rootParser->_stackParser.push(_rootParser);
366 xmlSAXHandler baseHandler =
368 0, // internal_subset,
370 0, // hasInternalSubset
371 0, // hasExternalSubset
378 0, // unparsedEntityDecl
379 0, // setDocumentLocator
380 xmlParserBase::start_document, // startDocument
381 xmlParserBase::end_document, // endDocument
382 xmlParserBase::start_element, // startElement
383 xmlParserBase::end_element, // endElement
385 xmlParserBase::characters, // characters
386 0, // ignorableWhitespace
387 0, // processingInstruction
388 xmlParserBase::comment, // comment
389 xmlParserBase::warning, // warning
390 xmlParserBase::error, // error
391 xmlParserBase::fatal_error, // fatalError
392 0, // getParameterEntity
393 xmlParserBase::cdata_block, // cdataBlock
397 // --- sequence from libxml++, to have a libxml context
399 _xmlParserCtxt* saxContext;
400 saxContext = xmlCreateFileParserCtxt(xmlFile.c_str());
403 _rootParser->cleanGarbage();
404 string what = "problem while trying to open the file for parsing " + xmlFile;
405 throw Exception(what);
407 xmlSAXHandlerPtr old_sax = saxContext->sax;
408 saxContext->sax = &baseHandler;
409 _rootParser->_xmlParser = saxContext;
410 saxContext->userData = _rootParser;
412 xmlParseDocument(saxContext);
413 _rootParser->cleanGarbage();
414 xmlFileClose(saxContext);
415 xmlFreeParserCtxt(saxContext);
416 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
420 // ----------------------------------------------------------------------------
425 char Buffer[SIZEBUF];
427 /*! expat parser initialisation
428 * \param parser dedicated parser
431 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
433 xmlParserBase::_xmlParser= XML_ParserCreate(NULL);
436 cerr << "Couldn't allocate memory for parser" << endl;
437 throw Exception("Couldn't allocate memory for parser");
442 * \param xmlFile file to parse
445 void xmlReader::parse(std::string xmlFile)
447 FILE* fin=fopen(xmlFile.c_str(),"r");
450 std::cerr << "Couldn't open schema file" << std::endl;
451 throw std::invalid_argument("Couldn't open schema file");
452 //throw Exception("Couldn't open schema file");
455 XML_SetElementHandler(xmlParserBase::_xmlParser,
456 xmlParserBase::start_element,
457 xmlParserBase::end_element);
458 XML_SetCharacterDataHandler(xmlParserBase::_xmlParser,
459 xmlParserBase::characters );
460 XML_SetUserData(xmlParserBase::_xmlParser, _rootParser);
461 _rootParser->init(0);
462 _rootParser->_stackParser.push(_rootParser);
471 len = fread(Buffer, 1, SIZEBUF, fin);
474 std::cerr << "Read error" << std::endl;
475 throw Exception("Read error");
479 if (XML_Parse(xmlParserBase::_xmlParser, Buffer, len, done) == XML_STATUS_ERROR)
481 throw Exception(XML_ErrorString(XML_GetErrorCode(xmlParserBase::_xmlParser)));
487 XML_ParserFree (xmlParserBase::_xmlParser);
488 xmlParserBase::_xmlParser=0;
489 _rootParser->cleanGarbage();
490 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
494 _rootParser->cleanGarbage();
495 //get line number from XML parser
496 cerr << "Error at line: " << XML_GetCurrentLineNumber(xmlParserBase::_xmlParser) << endl;
502 // ----------------------------------------------------------------------------