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 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 //=======================================================================
112 //=======================================================================
114 Standard_Boolean LDOMParser::parse (istream& anInput,
115 const Standard_Boolean theTagPerStep,
116 const Standard_Boolean theWithoutRoot)
118 // Open the DOM Document
119 myDocument = new LDOM_MemManager (20000);
122 // Create the Reader instance
123 if (myReader) delete myReader;
124 myReader = new LDOM_XmlReader (myDocument, myError, theTagPerStep);
127 return ParseDocument (anInput, theWithoutRoot);
130 //=======================================================================
133 //=======================================================================
135 Standard_Boolean LDOMParser::parse (const char * const aFileName)
137 std::ifstream aFileStream;
138 OSD_OpenStream (aFileStream, aFileName, std::ios::in);
140 if (aFileStream.good())
142 return parse (aFileStream);
146 myError = "Fatal XML error: Cannot open XML file";
147 return Standard_True;
151 //=======================================================================
152 //function : ParseDocument
153 //purpose : parse the whole document (abstracted from the XML source)
154 //=======================================================================
156 Standard_Boolean LDOMParser::ParseDocument (istream& theIStream, const Standard_Boolean theWithoutRoot)
158 Standard_Boolean isError = Standard_False;
159 Standard_Boolean isElement = Standard_False;
160 Standard_Boolean isDoctype = Standard_False;
162 Standard_Boolean isInsertFictRootElement = Standard_False;
165 LDOM_XmlReader::RecordType aType = (theWithoutRoot && !isInsertFictRootElement ?
166 LDOM_XmlReader::XML_START_ELEMENT :
167 ReadRecord (*myReader, theIStream, myCurrentData));
169 case LDOM_XmlReader::XML_HEADER:
170 if (isDoctype || isElement) {
171 myError = "Unexpected XML declaration";
172 isError = Standard_True;
176 case LDOM_XmlReader::XML_DOCTYPE:
178 myError = "Unexpected DOCTYPE declaration";
179 isError = Standard_True;
182 isDoctype = Standard_True;
183 case LDOM_XmlReader::XML_COMMENT:
185 case LDOM_XmlReader::XML_FULL_ELEMENT:
186 if (isElement == Standard_False) {
187 isElement = Standard_True;
188 myDocument -> myRootElement = &myReader -> GetElement ();
189 if (startElement()) {
190 isError = Standard_True;
191 myError = "User abort at startElement()";
195 isError = Standard_True;
196 myError = "User abort at endElement()";
201 case LDOM_XmlReader::XML_START_ELEMENT:
202 if (isElement == Standard_False) {
203 isElement = Standard_True;
205 if (theWithoutRoot && !isInsertFictRootElement)
207 isInsertFictRootElement = Standard_True;
209 // create fiction root element
210 TCollection_AsciiString aFicName ("document");
211 myReader->CreateElement (aFicName.ToCString(), aFicName.Length());
214 myDocument->myRootElement = &myReader->GetElement();
216 if (startElement()) {
217 isError = Standard_True;
218 myError = "User abort at startElement()";
221 isError = ParseElement (theIStream);
225 isError = Standard_True;
226 myError = "Expected comment or end-of-file";
227 case LDOM_XmlReader::XML_END_ELEMENT:
229 isError = Standard_True;
230 myError = "User abort at endElement()";
232 case LDOM_XmlReader::XML_EOF:
234 case LDOM_XmlReader::XML_UNKNOWN:
237 myError = "Unexpected data beyond the Document Element";
239 isError = Standard_True;
246 //=======================================================================
247 //function : ParseElement
248 //purpose : parse one element, given the type of its XML presentation
249 //=======================================================================
251 Standard_Boolean LDOMParser::ParseElement (Standard_IStream& theIStream)
253 Standard_Boolean isError = Standard_False;
254 const LDOM_BasicElement * aParent = &myReader->GetElement();
255 const LDOM_BasicNode * aLastChild = NULL;
257 LDOM_Node::NodeType aLocType;
258 LDOMBasicString aTextValue;
260 LDOM_XmlReader::RecordType aType = ReadRecord (* myReader, theIStream, myCurrentData);
262 case LDOM_XmlReader::XML_UNKNOWN:
263 isError = Standard_True;
265 case LDOM_XmlReader::XML_FULL_ELEMENT:
266 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
267 if (startElement()) {
268 isError = Standard_True;
269 myError = "User abort at startElement()";
273 isError = Standard_True;
274 myError = "User abort at endElement()";
278 case LDOM_XmlReader::XML_START_ELEMENT:
279 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
280 if (startElement()) {
281 isError = Standard_True;
282 myError = "User abort at startElement()";
285 isError = ParseElement (theIStream);
287 case LDOM_XmlReader::XML_END_ELEMENT:
289 Standard_CString aParentName = Standard_CString(aParent->GetTagName());
290 aTextStr = (char *)myCurrentData.str();
291 if (strcmp(aTextStr, aParentName) != 0) {
292 myError = "Expected end tag \'";
293 myError += aParentName;
295 isError = Standard_True;
297 else if (endElement()) {
298 isError = Standard_True;
299 myError = "User abort at endElement()";
304 case LDOM_XmlReader::XML_TEXT:
305 aLocType = LDOM_Node::TEXT_NODE;
307 Standard_Integer aTextLen;
308 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
309 // try to convert to integer
310 if (IsDigit(aTextStr[0])) {
311 if (LDOM_XmlReader::getInteger (aTextValue, aTextStr,
312 aTextStr + aTextLen))
313 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
315 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
317 goto create_text_node;
318 case LDOM_XmlReader::XML_COMMENT:
319 aLocType = LDOM_Node::COMMENT_NODE;
321 Standard_Integer aTextLen;
322 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
323 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
325 goto create_text_node;
326 case LDOM_XmlReader::XML_CDATA:
327 aLocType = LDOM_Node::CDATA_SECTION_NODE;
328 aTextStr = (char *)myCurrentData.str();
329 aTextValue = LDOMBasicString(aTextStr,myCurrentData.Length(),myDocument);
332 LDOM_BasicNode& aTextNode =
333 LDOM_BasicText::Create (aLocType, aTextValue, myDocument);
334 aParent -> AppendChild (&aTextNode, aLastChild);
338 case LDOM_XmlReader::XML_EOF:
339 myError = "Inexpected end of file";
340 isError = Standard_True;
349 //=======================================================================
350 //function : startElement
351 //purpose : virtual hook on 'StartElement' event for descendant classes
352 //=======================================================================
354 Standard_Boolean LDOMParser::startElement ()
356 return Standard_False;
359 //=======================================================================
360 //function : endElement
361 //purpose : virtual hook on 'EndElement' event for descendant classes
362 //=======================================================================
364 Standard_Boolean LDOMParser::endElement ()
366 return Standard_False;
369 //=======================================================================
370 //function : getCurrentElement
372 //=======================================================================
374 LDOM_Element LDOMParser::getCurrentElement () const
376 return LDOM_Element (myReader -> GetElement(), myDocument);
379 //=======================================================================
380 //function : getDocument
382 //=======================================================================
384 LDOM_Document LDOMParser::getDocument ()
386 return myDocument -> Self();