1 // Copyright (C) 2006-2019 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, or (at your option) any later version.
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"
34 #include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
36 _xmlParserCtxt* xmlParserBase::_xmlParser;
37 void xmlParserBase::XML_SetUserData(_xmlParserCtxt* ctxt,
38 xmlParserBase* parser)
40 ctxt->userData = parser;
43 // --- generic part -----------------------------------------------------------
46 using YACS::Exception;
48 std::stack<xmlParserBase*> xmlParserBase::_stackParser;
49 std::list<xmlParserBase*> xmlParserBase::_garbage;
51 /*! callback usable only with libxml2
54 void XMLCALL xmlParserBase::start_document(void* userData)
56 //DEBTRACE("xmlParserBase::start_document");
57 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
60 /*! callback usable only with libxml2
63 void XMLCALL xmlParserBase::end_document (void* userData)
65 //DEBTRACE("xmlParserBase::end_document");
66 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
69 /*! callback called on start of an xml element: \verbatim <name> \endverbatim
72 void XMLCALL xmlParserBase::start_element (void* userData,
76 //DEBTRACE("xmlParserBase::start_element " << name);
78 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
79 const XML_Char *aName = tochar(name);
80 currentParser->incrCount(aName);
81 currentParser->onStart(aName, p);
85 /*! callback called on end of an xml element: \verbatim </name> \endverbatim
88 void XMLCALL xmlParserBase::end_element (void* userData,
91 //DEBTRACE("xmlParserBase::end_element");
92 const XML_Char *aName = tochar(name);
93 xmlParserBase *childParser = static_cast<xmlParserBase *> (userData);
94 _garbage.push_back(_stackParser.top());
95 DEBTRACE("xmlParserBase::end_element " << _garbage.size());
97 XML_SetUserData(_xmlParser, _stackParser.top());
98 childParser->onEnd(aName);
103 /*! callback called for significant characters inside tags: \verbatim <tag>content</tag> \endverbatim
104 * or outside tags, like space or new line;
105 * get also the CDATA tags: \verbatim <tag>![CDATA[content]]></tag> \endverbatim
108 void XMLCALL xmlParserBase::characters (void* userData,
112 //DEBTRACE("xmlParserBase::characters " << len);
113 xmlParserBase *currentParser = (xmlParserBase *) (userData);
114 string data((char*)ch,len);
115 currentParser->charData(data);
119 /*! callback usable only with libxml2
122 void XMLCALL xmlParserBase::comment (void* userData,
123 const xmlChar* value)
125 //DEBTRACE("xmlParserBase::comment");
126 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
130 /*! callback usable only with libxml2
133 void XMLCALL xmlParserBase::warning (void* userData,
134 const char* fmt, ...)
136 DEBTRACE("xmlParserBase::warning");
137 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
140 string format = "%s";
144 parv = va_arg(args, char*);
147 else cerr << __FILE__ << " [" << __LINE__ << "] : "
148 << "error format not taken into account: " << fmt << endl;
153 /*! callback usable only with libxml2
156 void XMLCALL xmlParserBase::error (void* userData,
157 const char* fmt, ...)
159 DEBTRACE("xmlParserBase::error");
160 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
163 string format = "%s";
167 parv = va_arg(args, char*);
169 xmlParserBase *currentParser = (xmlParserBase *) userData;
170 //cerr << currentParser->element << endl;
172 else cerr << __FILE__ << " [" << __LINE__ << "] : "
173 << "error format not taken into account: " << fmt << endl;
178 /*! callback usable only with libxml2
181 void XMLCALL xmlParserBase::fatal_error (void* userData,
182 const char* fmt, ...)
184 DEBTRACE("xmlParserBase::fatal_error");
185 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
188 string format = "%s";
192 parv = va_arg(args, char*);
195 else cerr << __FILE__ << " [" << __LINE__ << "] : "
196 << "error format not taken into account: " << fmt << endl;
200 /*! callback called for CDATA inside tags: \verbatim <tag>![CDATA[content]]></tag> \endverbatim
201 * used only by libxml2
204 void XMLCALL xmlParserBase::cdata_block (void* userData,
205 const xmlChar* value,
208 //DEBTRACE("xmlParserBase::cdata_block");
209 xmlParserBase *currentParser = static_cast<xmlParserBase *> (userData);
210 string data((char*)value,len);
211 currentParser->charData(data);
214 void xmlParserBase::cleanGarbage()
216 while (!_garbage.empty())
218 delete (_garbage.front());
219 _garbage.pop_front();
223 /*! Stores the tag attributes on a map. The map is an attribute of the parser
224 * object dedicated to the current xml tag
227 void xmlParserBase::getAttributes(const xmlChar** p)
231 string attributeName = (char*)*p;
232 //cerr << "attribute name " << attributeName << endl;
234 string attributeValue = (char*)*p;
235 //cerr << "attribute value " << attributeValue << endl;
237 _mapAttrib[attributeName] = attributeValue;
241 /*! Stores an attribute (key, value) on the map attribute.
242 * used for attributes defined at another tag level (child tags).
245 void xmlParserBase::setAttribute(std::string key, std::string value)
247 _mapAttrib[key] = value;
250 /*! Gets an attribute value given a string key.
251 * If the key does not exist, throws an Exception.
254 std::string xmlParserBase::getAttribute(std::string key)
256 if (_mapAttrib.find(key) == _mapAttrib.end())
258 string what = "Attribute does not exist: " + key;
259 throw Exception(what);
261 return _mapAttrib[key];
264 /*! Add data on the data attribute of the parser object dedicated to an xml tag
267 void xmlParserBase::addData(std::string value)
269 // DEBTRACE("xmlParserBase::addData()");
273 /*! all parsers must know their father parser (father tag), in order
274 * to set values or attributes in father.
277 void xmlParserBase::init (const xmlChar** p, xmlParserBase* father)
282 /*! to be specialized for each kind of xml tag
285 void xmlParserBase::onStart (const XML_Char* elem, const xmlChar** p)
289 /*! to be specialized for each kind of xml tag
292 void xmlParserBase::onEnd (const XML_Char* name)
296 /*! to be specialized following the kind of xml tag
299 void xmlParserBase::charData (std::string data)
303 /*! May be specialized for each kind of xml tag.
304 * Counts the number of tag occurences of a given type inside a context.
307 void xmlParserBase::incrCount(const XML_Char *elem)
309 if(counts.find(elem)==counts.end())
312 counts[elem]=counts[elem]+1;
315 /*! to be specialized for each kind of xml tag
318 void xmlParserBase::end()
322 /*! Throws an exception.
325 void xmlParserBase::stopParse(std::string what)
327 xmlStopParser(_xmlParser);
330 // ----------------------------------------------------------------------------
332 /*! libxml2 parser initialisation
333 * \param parser dedicated parser
336 xmlReader::xmlReader(xmlParserBase* parser): _rootParser(parser)
341 * \param xmlFile file to parse
344 void xmlReader::parse(std::string xmlFile)
346 _rootParser->init(0);
347 _rootParser->_stackParser.push(_rootParser);
349 xmlSAXHandler baseHandler =
351 0, // internal_subset,
353 0, // hasInternalSubset
354 0, // hasExternalSubset
361 0, // unparsedEntityDecl
362 0, // setDocumentLocator
363 xmlParserBase::start_document, // startDocument
364 xmlParserBase::end_document, // endDocument
365 xmlParserBase::start_element, // startElement
366 xmlParserBase::end_element, // endElement
368 xmlParserBase::characters, // characters
369 0, // ignorableWhitespace
370 0, // processingInstruction
371 xmlParserBase::comment, // comment
372 xmlParserBase::warning, // warning
373 xmlParserBase::error, // error
374 xmlParserBase::fatal_error, // fatalError
375 0, // getParameterEntity
376 xmlParserBase::cdata_block, // cdataBlock
380 // --- sequence from libxml++, to have a libxml context
382 _xmlParserCtxt* saxContext;
383 saxContext = xmlCreateFileParserCtxt(xmlFile.c_str());
386 _rootParser->cleanGarbage();
387 string what = "problem while trying to open the file for parsing " + xmlFile;
388 throw Exception(what);
390 xmlSAXHandlerPtr old_sax = saxContext->sax;
391 saxContext->sax = &baseHandler;
392 _rootParser->_xmlParser = saxContext;
393 saxContext->userData = _rootParser;
395 xmlParseDocument(saxContext);
396 _rootParser->cleanGarbage();
397 if ( saxContext->myDoc != NULL ) {
398 xmlFreeDoc( saxContext->myDoc );
399 saxContext->myDoc = NULL;
401 if ( saxContext != NULL ) {
402 saxContext->sax = old_sax;
403 xmlFreeParserCtxt( saxContext );
405 DEBTRACE("xmlParserBase::end of parse, garbage size = " << _rootParser->getGarbageSize());
408 // ----------------------------------------------------------------------------