1 // Created on: 2001-07-20
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 //AGV 060302: Input from std::istream
17 // AGV 130302: Return error if there are data after the root element
19 //#define LDOM_PARSER_TRACE
21 #include <LDOMParser.hxx>
22 #include <LDOM_MemManager.hxx>
23 #include <LDOM_XmlReader.hxx>
24 #include <LDOM_BasicText.hxx>
25 #include <LDOM_CharReference.hxx>
26 #include <TCollection_ExtendedString.hxx>
27 #include <OSD_OpenFile.hxx>
36 //=======================================================================
37 //function : ~LDOMParser
39 //=======================================================================
41 LDOMParser::~LDOMParser()
43 if (myReader) delete myReader;
46 //=======================================================================
47 //function : ReadRecord
48 //purpose : Take the next lexical element from XML stream
49 //=======================================================================
51 #ifdef LDOM_PARSER_TRACE
56 LDOM_XmlReader::RecordType ReadRecord (LDOM_XmlReader& aReader,
57 Standard_IStream& theIStream,
59 Standard_Boolean& theDocStart)
61 #ifdef LDOM_PARSER_TRACE
65 const LDOM_XmlReader::RecordType aType = aReader.ReadRecord (theIStream, aData, theDocStart);
66 #ifdef LDOM_PARSER_TRACE
67 static FILE * ff = NULL;
68 TCollection_AsciiString aTraceFileName;
70 aTraceFileName = TCollection_AsciiString (getenv("TEMP")) + "\\ldom.trace";
72 aTraceFileName = "/tmp/ldom.trace";
74 ff = fopen (aTraceFileName.ToCString(),ff ? "at": "wt");
75 const char * aDataType;
77 case LDOM_XmlReader::XML_UNKNOWN: aDataType= "XML_UNKNOWN "; break;
78 case LDOM_XmlReader::XML_HEADER: aDataType= "XML_HEADER "; break;
79 case LDOM_XmlReader::XML_DOCTYPE: aDataType= "XML_DOCTYPE "; break;
80 case LDOM_XmlReader::XML_COMMENT: aDataType= "XML_COMMENT "; break;
81 case LDOM_XmlReader::XML_START_ELEMENT: aDataType= "XML_START_ELEMENT"; break;
82 case LDOM_XmlReader::XML_END_ELEMENT: aDataType= "XML_END_ELEMENT "; break;
83 case LDOM_XmlReader::XML_FULL_ELEMENT: aDataType= "XML_FULL_ELEMENT "; break;
84 case LDOM_XmlReader::XML_TEXT: aDataType= "XML_TEXT "; break;
85 case LDOM_XmlReader::XML_CDATA: aDataType= "XML_CDATA "; break;
86 case LDOM_XmlReader::XML_EOF: aDataType= "XML_EOF ";
88 char * aStr = aData.str();
89 fprintf (ff, "%5d %s: %s\n", aCounter, aDataType, aStr);
96 //=======================================================================
98 //purpose : Return text describing a parsing error
99 //=======================================================================
101 const TCollection_AsciiString& LDOMParser::GetError
102 (TCollection_AsciiString& aData) const
104 char * aStr =(char *)myCurrentData.str();
110 //=======================================================================
112 //purpose : Returns the byte order mask defined at the start of a stream
113 //=======================================================================
115 LDOM_OSStream::BOMType LDOMParser::GetBOM() const
118 return myReader->GetBOM();
119 return LDOM_OSStream::BOM_UNDEFINED;
122 //=======================================================================
125 //=======================================================================
127 Standard_Boolean LDOMParser::parse (std::istream& anInput,
128 const Standard_Boolean theTagPerStep,
129 const Standard_Boolean theWithoutRoot)
131 // Open the DOM Document
132 myDocument = new LDOM_MemManager (20000);
135 // Create the Reader instance
136 if (myReader) delete myReader;
137 myReader = new LDOM_XmlReader (myDocument, myError, theTagPerStep);
140 return ParseDocument (anInput, theWithoutRoot);
143 //=======================================================================
146 //=======================================================================
148 Standard_Boolean LDOMParser::parse (const char * const aFileName)
150 std::ifstream aFileStream;
151 OSD_OpenStream (aFileStream, aFileName, std::ios::in);
153 if (aFileStream.good())
155 return parse (aFileStream);
159 myError = "Fatal XML error: Cannot open XML file";
160 return Standard_True;
164 //=======================================================================
165 //function : ParseDocument
166 //purpose : parse the whole document (abstracted from the XML source)
167 //=======================================================================
169 Standard_Boolean LDOMParser::ParseDocument (std::istream& theIStream, const Standard_Boolean theWithoutRoot)
171 Standard_Boolean isError = Standard_False;
172 Standard_Boolean isElement = Standard_False;
173 Standard_Boolean isDoctype = Standard_False;
175 Standard_Boolean isInsertFictRootElement = Standard_False;
176 Standard_Boolean aDocStart = Standard_True;
180 LDOM_XmlReader::RecordType aType = (theWithoutRoot && !isInsertFictRootElement ?
181 LDOM_XmlReader::XML_START_ELEMENT :
182 ReadRecord (*myReader, theIStream, myCurrentData, aDocStart));
184 case LDOM_XmlReader::XML_HEADER:
185 if (isDoctype || isElement) {
186 myError = "Unexpected XML declaration";
187 isError = Standard_True;
191 case LDOM_XmlReader::XML_DOCTYPE:
193 myError = "Unexpected DOCTYPE declaration";
194 isError = Standard_True;
197 isDoctype = Standard_True;
199 case LDOM_XmlReader::XML_COMMENT:
201 case LDOM_XmlReader::XML_FULL_ELEMENT:
202 if (isElement == Standard_False) {
203 isElement = Standard_True;
204 myDocument -> myRootElement = &myReader -> GetElement ();
205 if (startElement()) {
206 isError = Standard_True;
207 myError = "User abort at startElement()";
211 isError = Standard_True;
212 myError = "User abort at endElement()";
217 isError = Standard_True;
218 myError = "Expected comment or end-of-file";
220 case LDOM_XmlReader::XML_START_ELEMENT:
221 if (isElement == Standard_False) {
222 isElement = Standard_True;
224 if (theWithoutRoot && !isInsertFictRootElement)
226 isInsertFictRootElement = Standard_True;
228 // create fiction root element
229 TCollection_AsciiString aFicName ("document");
230 myReader->CreateElement (aFicName.ToCString(), aFicName.Length());
233 myDocument->myRootElement = &myReader->GetElement();
235 if (startElement()) {
236 isError = Standard_True;
237 myError = "User abort at startElement()";
240 isError = ParseElement (theIStream, aDocStart);
244 isError = Standard_True;
245 myError = "Expected comment or end-of-file";
247 case LDOM_XmlReader::XML_END_ELEMENT:
249 isError = Standard_True;
250 myError = "User abort at endElement()";
253 case LDOM_XmlReader::XML_EOF:
255 case LDOM_XmlReader::XML_UNKNOWN:
258 myError = "Unexpected data beyond the Document Element";
260 isError = Standard_True;
267 //=======================================================================
268 //function : ParseElement
269 //purpose : parse one element, given the type of its XML presentation
270 //=======================================================================
272 Standard_Boolean LDOMParser::ParseElement (Standard_IStream& theIStream, Standard_Boolean& theDocStart)
274 Standard_Boolean isError = Standard_False;
275 const LDOM_BasicElement * aParent = &myReader->GetElement();
276 const LDOM_BasicNode * aLastChild = NULL;
278 LDOM_Node::NodeType aLocType;
279 LDOMBasicString aTextValue;
281 LDOM_XmlReader::RecordType aType = ReadRecord (* myReader, theIStream, myCurrentData, theDocStart);
283 case LDOM_XmlReader::XML_UNKNOWN:
284 isError = Standard_True;
286 case LDOM_XmlReader::XML_FULL_ELEMENT:
287 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
288 if (startElement()) {
289 isError = Standard_True;
290 myError = "User abort at startElement()";
294 isError = Standard_True;
295 myError = "User abort at endElement()";
299 case LDOM_XmlReader::XML_START_ELEMENT:
300 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
301 if (startElement()) {
302 isError = Standard_True;
303 myError = "User abort at startElement()";
306 isError = ParseElement (theIStream, theDocStart);
308 case LDOM_XmlReader::XML_END_ELEMENT:
310 Standard_CString aParentName = Standard_CString(aParent->GetTagName());
311 aTextStr = (char *)myCurrentData.str();
312 if (strcmp(aTextStr, aParentName) != 0) {
313 myError = "Expected end tag \'";
314 myError += aParentName;
316 isError = Standard_True;
318 else if (endElement()) {
319 isError = Standard_True;
320 myError = "User abort at endElement()";
325 case LDOM_XmlReader::XML_TEXT:
326 aLocType = LDOM_Node::TEXT_NODE;
328 Standard_Integer aTextLen;
329 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
330 // try to convert to integer
331 if (IsDigit(aTextStr[0])) {
332 if (LDOM_XmlReader::getInteger (aTextValue, aTextStr,
333 aTextStr + aTextLen))
334 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
336 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
338 goto create_text_node;
339 case LDOM_XmlReader::XML_COMMENT:
340 aLocType = LDOM_Node::COMMENT_NODE;
342 Standard_Integer aTextLen;
343 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
344 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
346 goto create_text_node;
347 case LDOM_XmlReader::XML_CDATA:
348 aLocType = LDOM_Node::CDATA_SECTION_NODE;
349 aTextStr = (char *)myCurrentData.str();
350 aTextValue = LDOMBasicString(aTextStr,myCurrentData.Length(),myDocument);
353 LDOM_BasicNode& aTextNode =
354 LDOM_BasicText::Create (aLocType, aTextValue, myDocument);
355 aParent -> AppendChild (&aTextNode, aLastChild);
359 case LDOM_XmlReader::XML_EOF:
360 myError = "Inexpected end of file";
361 isError = Standard_True;
370 //=======================================================================
371 //function : startElement
372 //purpose : virtual hook on 'StartElement' event for descendant classes
373 //=======================================================================
375 Standard_Boolean LDOMParser::startElement ()
377 return Standard_False;
380 //=======================================================================
381 //function : endElement
382 //purpose : virtual hook on 'EndElement' event for descendant classes
383 //=======================================================================
385 Standard_Boolean LDOMParser::endElement ()
387 return Standard_False;
390 //=======================================================================
391 //function : getCurrentElement
393 //=======================================================================
395 LDOM_Element LDOMParser::getCurrentElement () const
397 return LDOM_Element (myReader -> GetElement(), myDocument);
400 //=======================================================================
401 //function : getDocument
403 //=======================================================================
405 LDOM_Document LDOMParser::getDocument ()
407 return myDocument -> Self();