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,
60 #ifdef LDOM_PARSER_TRACE
64 const LDOM_XmlReader::RecordType aType = aReader.ReadRecord (theIStream, aData);
65 #ifdef LDOM_PARSER_TRACE
66 static FILE * ff = NULL;
67 TCollection_AsciiString aTraceFileName;
69 aTraceFileName = TCollection_AsciiString (getenv("TEMP")) + "\\ldom.trace";
71 aTraceFileName = "/tmp/ldom.trace";
73 ff = fopen (aTraceFileName.ToCString(),ff ? "at": "wt");
74 const char * aDataType;
76 case LDOM_XmlReader::XML_UNKNOWN: aDataType= "XML_UNKNOWN "; break;
77 case LDOM_XmlReader::XML_HEADER: aDataType= "XML_HEADER "; break;
78 case LDOM_XmlReader::XML_DOCTYPE: aDataType= "XML_DOCTYPE "; break;
79 case LDOM_XmlReader::XML_COMMENT: aDataType= "XML_COMMENT "; break;
80 case LDOM_XmlReader::XML_START_ELEMENT: aDataType= "XML_START_ELEMENT"; break;
81 case LDOM_XmlReader::XML_END_ELEMENT: aDataType= "XML_END_ELEMENT "; break;
82 case LDOM_XmlReader::XML_FULL_ELEMENT: aDataType= "XML_FULL_ELEMENT "; break;
83 case LDOM_XmlReader::XML_TEXT: aDataType= "XML_TEXT "; break;
84 case LDOM_XmlReader::XML_CDATA: aDataType= "XML_CDATA "; break;
85 case LDOM_XmlReader::XML_EOF: aDataType= "XML_EOF ";
87 char * aStr = aData.str();
88 fprintf (ff, "%5d %s: %s\n", aCounter, aDataType, aStr);
95 //=======================================================================
97 //purpose : Return text describing a parsing error
98 //=======================================================================
100 const TCollection_AsciiString& LDOMParser::GetError
101 (TCollection_AsciiString& aData) const
103 char * aStr =(char *)myCurrentData.str();
109 //=======================================================================
111 //purpose : Returns the byte order mask defined at the start of a stream
112 //=======================================================================
114 LDOM_OSStream::BOMType LDOMParser::GetBOM() const
117 return myReader->GetBOM();
118 return LDOM_OSStream::BOM_UNDEFINED;
121 //=======================================================================
124 //=======================================================================
126 Standard_Boolean LDOMParser::parse (std::istream& anInput,
127 const Standard_Boolean theTagPerStep,
128 const Standard_Boolean theWithoutRoot)
130 // Open the DOM Document
131 myDocument = new LDOM_MemManager (20000);
134 // Create the Reader instance
135 if (myReader) delete myReader;
136 myReader = new LDOM_XmlReader (myDocument, myError, theTagPerStep);
139 return ParseDocument (anInput, theWithoutRoot);
142 //=======================================================================
145 //=======================================================================
147 Standard_Boolean LDOMParser::parse (const char * const aFileName)
149 std::ifstream aFileStream;
150 OSD_OpenStream (aFileStream, aFileName, std::ios::in);
152 if (aFileStream.good())
154 return parse (aFileStream);
158 myError = "Fatal XML error: Cannot open XML file";
159 return Standard_True;
163 //=======================================================================
164 //function : ParseDocument
165 //purpose : parse the whole document (abstracted from the XML source)
166 //=======================================================================
168 Standard_Boolean LDOMParser::ParseDocument (std::istream& theIStream, const Standard_Boolean theWithoutRoot)
170 Standard_Boolean isError = Standard_False;
171 Standard_Boolean isElement = Standard_False;
172 Standard_Boolean isDoctype = Standard_False;
174 Standard_Boolean isInsertFictRootElement = Standard_False;
177 LDOM_XmlReader::RecordType aType = (theWithoutRoot && !isInsertFictRootElement ?
178 LDOM_XmlReader::XML_START_ELEMENT :
179 ReadRecord (*myReader, theIStream, myCurrentData));
181 case LDOM_XmlReader::XML_HEADER:
182 if (isDoctype || isElement) {
183 myError = "Unexpected XML declaration";
184 isError = Standard_True;
188 case LDOM_XmlReader::XML_DOCTYPE:
190 myError = "Unexpected DOCTYPE declaration";
191 isError = Standard_True;
194 isDoctype = Standard_True;
196 case LDOM_XmlReader::XML_COMMENT:
198 case LDOM_XmlReader::XML_FULL_ELEMENT:
199 if (isElement == Standard_False) {
200 isElement = Standard_True;
201 myDocument -> myRootElement = &myReader -> GetElement ();
202 if (startElement()) {
203 isError = Standard_True;
204 myError = "User abort at startElement()";
208 isError = Standard_True;
209 myError = "User abort at endElement()";
214 isError = Standard_True;
215 myError = "Expected comment or end-of-file";
217 case LDOM_XmlReader::XML_START_ELEMENT:
218 if (isElement == Standard_False) {
219 isElement = Standard_True;
221 if (theWithoutRoot && !isInsertFictRootElement)
223 isInsertFictRootElement = Standard_True;
225 // create fiction root element
226 TCollection_AsciiString aFicName ("document");
227 myReader->CreateElement (aFicName.ToCString(), aFicName.Length());
230 myDocument->myRootElement = &myReader->GetElement();
232 if (startElement()) {
233 isError = Standard_True;
234 myError = "User abort at startElement()";
237 isError = ParseElement (theIStream);
241 isError = Standard_True;
242 myError = "Expected comment or end-of-file";
244 case LDOM_XmlReader::XML_END_ELEMENT:
246 isError = Standard_True;
247 myError = "User abort at endElement()";
250 case LDOM_XmlReader::XML_EOF:
252 case LDOM_XmlReader::XML_UNKNOWN:
255 myError = "Unexpected data beyond the Document Element";
257 isError = Standard_True;
264 //=======================================================================
265 //function : ParseElement
266 //purpose : parse one element, given the type of its XML presentation
267 //=======================================================================
269 Standard_Boolean LDOMParser::ParseElement (Standard_IStream& theIStream)
271 Standard_Boolean isError = Standard_False;
272 const LDOM_BasicElement * aParent = &myReader->GetElement();
273 const LDOM_BasicNode * aLastChild = NULL;
275 LDOM_Node::NodeType aLocType;
276 LDOMBasicString aTextValue;
278 LDOM_XmlReader::RecordType aType = ReadRecord (* myReader, theIStream, myCurrentData);
280 case LDOM_XmlReader::XML_UNKNOWN:
281 isError = Standard_True;
283 case LDOM_XmlReader::XML_FULL_ELEMENT:
284 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
285 if (startElement()) {
286 isError = Standard_True;
287 myError = "User abort at startElement()";
291 isError = Standard_True;
292 myError = "User abort at endElement()";
296 case LDOM_XmlReader::XML_START_ELEMENT:
297 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
298 if (startElement()) {
299 isError = Standard_True;
300 myError = "User abort at startElement()";
303 isError = ParseElement (theIStream);
305 case LDOM_XmlReader::XML_END_ELEMENT:
307 Standard_CString aParentName = Standard_CString(aParent->GetTagName());
308 aTextStr = (char *)myCurrentData.str();
309 if (strcmp(aTextStr, aParentName) != 0) {
310 myError = "Expected end tag \'";
311 myError += aParentName;
313 isError = Standard_True;
315 else if (endElement()) {
316 isError = Standard_True;
317 myError = "User abort at endElement()";
322 case LDOM_XmlReader::XML_TEXT:
323 aLocType = LDOM_Node::TEXT_NODE;
325 Standard_Integer aTextLen;
326 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
327 // try to convert to integer
328 if (IsDigit(aTextStr[0])) {
329 if (LDOM_XmlReader::getInteger (aTextValue, aTextStr,
330 aTextStr + aTextLen))
331 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
333 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
335 goto create_text_node;
336 case LDOM_XmlReader::XML_COMMENT:
337 aLocType = LDOM_Node::COMMENT_NODE;
339 Standard_Integer aTextLen;
340 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
341 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
343 goto create_text_node;
344 case LDOM_XmlReader::XML_CDATA:
345 aLocType = LDOM_Node::CDATA_SECTION_NODE;
346 aTextStr = (char *)myCurrentData.str();
347 aTextValue = LDOMBasicString(aTextStr,myCurrentData.Length(),myDocument);
350 LDOM_BasicNode& aTextNode =
351 LDOM_BasicText::Create (aLocType, aTextValue, myDocument);
352 aParent -> AppendChild (&aTextNode, aLastChild);
356 case LDOM_XmlReader::XML_EOF:
357 myError = "Inexpected end of file";
358 isError = Standard_True;
367 //=======================================================================
368 //function : startElement
369 //purpose : virtual hook on 'StartElement' event for descendant classes
370 //=======================================================================
372 Standard_Boolean LDOMParser::startElement ()
374 return Standard_False;
377 //=======================================================================
378 //function : endElement
379 //purpose : virtual hook on 'EndElement' event for descendant classes
380 //=======================================================================
382 Standard_Boolean LDOMParser::endElement ()
384 return Standard_False;
387 //=======================================================================
388 //function : getCurrentElement
390 //=======================================================================
392 LDOM_Element LDOMParser::getCurrentElement () const
394 return LDOM_Element (myReader -> GetElement(), myDocument);
397 //=======================================================================
398 //function : getDocument
400 //=======================================================================
402 LDOM_Document LDOMParser::getDocument ()
404 return myDocument -> Self();