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>
34 //=======================================================================
35 //function : ~LDOMParser
37 //=======================================================================
39 LDOMParser::~LDOMParser()
41 if (myReader) delete myReader;
44 //=======================================================================
45 //function : ReadRecord
46 //purpose : Take the next lexical element from XML stream
47 //=======================================================================
49 #ifdef LDOM_PARSER_TRACE
54 LDOM_XmlReader::RecordType ReadRecord (LDOM_XmlReader& aReader,
57 #ifdef LDOM_PARSER_TRACE
61 const LDOM_XmlReader::RecordType aType = aReader.ReadRecord (aData);
62 #ifdef LDOM_PARSER_TRACE
63 static FILE * ff = NULL;
64 TCollection_AsciiString aTraceFileName;
66 aTraceFileName = TCollection_AsciiString (getenv("TEMP")) + "\\ldom.trace";
68 aTraceFileName = "/tmp/ldom.trace";
70 ff = fopen (aTraceFileName.ToCString(),ff ? "at": "wt");
71 const char * aDataType;
73 case LDOM_XmlReader::XML_UNKNOWN: aDataType= "XML_UNKNOWN "; break;
74 case LDOM_XmlReader::XML_HEADER: aDataType= "XML_HEADER "; break;
75 case LDOM_XmlReader::XML_DOCTYPE: aDataType= "XML_DOCTYPE "; break;
76 case LDOM_XmlReader::XML_COMMENT: aDataType= "XML_COMMENT "; break;
77 case LDOM_XmlReader::XML_START_ELEMENT: aDataType= "XML_START_ELEMENT"; break;
78 case LDOM_XmlReader::XML_END_ELEMENT: aDataType= "XML_END_ELEMENT "; break;
79 case LDOM_XmlReader::XML_FULL_ELEMENT: aDataType= "XML_FULL_ELEMENT "; break;
80 case LDOM_XmlReader::XML_TEXT: aDataType= "XML_TEXT "; break;
81 case LDOM_XmlReader::XML_CDATA: aDataType= "XML_CDATA "; break;
82 case LDOM_XmlReader::XML_EOF: aDataType= "XML_EOF ";
84 char * aStr = aData.str();
85 fprintf (ff, "%5d %s: %s\n", aCounter, aDataType, aStr);
92 //=======================================================================
94 //purpose : Return text describing a parsing error
95 //=======================================================================
97 const TCollection_AsciiString& LDOMParser::GetError
98 (TCollection_AsciiString& aData) const
100 char * aStr =(char *)myCurrentData.str();
106 //=======================================================================
109 //=======================================================================
111 Standard_Boolean LDOMParser::parse (istream& anInput)
113 // Open the DOM Document
114 myDocument = new LDOM_MemManager (20000);
117 // Create the Reader instance
118 if (myReader) delete myReader;
119 myReader = new LDOM_XmlReader (anInput, myDocument, myError);
122 return ParseDocument();
125 //=======================================================================
128 //=======================================================================
130 Standard_Boolean LDOMParser::parse (const char * const aFileName)
132 // Open the DOM Document
133 myDocument = new LDOM_MemManager (20000);
137 int aFile = open (aFileName, O_RDONLY);
139 myError = "Fatal XML error: Cannot open XML file";
140 return Standard_True;
143 // Create the Reader instance
144 if (myReader) delete myReader;
145 myReader = new LDOM_XmlReader (aFile, myDocument, myError);
148 Standard_Boolean isError = ParseDocument();
153 //=======================================================================
154 //function : ParseDocument
155 //purpose : parse the whole document (abstracted from the XML source)
156 //=======================================================================
158 Standard_Boolean LDOMParser::ParseDocument ()
160 Standard_Boolean isError = Standard_False;
161 Standard_Boolean isElement = Standard_False;
162 Standard_Boolean isDoctype = Standard_False;
165 LDOM_XmlReader::RecordType aType = ReadRecord (*myReader, myCurrentData);
167 case LDOM_XmlReader::XML_HEADER:
168 if (isDoctype || isElement) {
169 myError = "Unexpected XML declaration";
170 isError = Standard_True;
174 case LDOM_XmlReader::XML_DOCTYPE:
176 myError = "Unexpected DOCTYPE declaration";
177 isError = Standard_True;
180 isDoctype = Standard_True;
181 case LDOM_XmlReader::XML_COMMENT:
183 case LDOM_XmlReader::XML_FULL_ELEMENT:
184 if (isElement == Standard_False) {
185 isElement = Standard_True;
186 myDocument -> myRootElement = &myReader -> GetElement ();
187 if (startElement()) {
188 isError = Standard_True;
189 myError = "User abort at startElement()";
193 isError = Standard_True;
194 myError = "User abort at endElement()";
199 case LDOM_XmlReader::XML_START_ELEMENT:
200 if (isElement == Standard_False) {
201 isElement = Standard_True;
202 myDocument -> myRootElement = &myReader -> GetElement ();
203 if (startElement()) {
204 isError = Standard_True;
205 myError = "User abort at startElement()";
208 isError = ParseElement ();
212 isError = Standard_True;
213 myError = "Expected comment or end-of-file";
214 case LDOM_XmlReader::XML_END_ELEMENT:
216 isError = Standard_True;
217 myError = "User abort at endElement()";
219 case LDOM_XmlReader::XML_EOF:
221 case LDOM_XmlReader::XML_UNKNOWN:
224 myError = "Unexpected data beyond the Document Element";
226 isError = Standard_True;
233 //=======================================================================
234 //function : ParseElement
235 //purpose : parse one element, given the type of its XML presentation
236 //=======================================================================
238 Standard_Boolean LDOMParser::ParseElement ()
240 Standard_Boolean isError = Standard_False;
241 const LDOM_BasicElement * aParent = &myReader->GetElement();
242 const LDOM_BasicNode * aLastChild = NULL;
244 LDOM_Node::NodeType aLocType;
245 LDOMBasicString aTextValue;
247 LDOM_XmlReader::RecordType aType = ReadRecord (* myReader, myCurrentData);
249 case LDOM_XmlReader::XML_UNKNOWN:
250 isError = Standard_True;
252 case LDOM_XmlReader::XML_FULL_ELEMENT:
253 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
254 if (startElement()) {
255 isError = Standard_True;
256 myError = "User abort at startElement()";
260 isError = Standard_True;
261 myError = "User abort at endElement()";
265 case LDOM_XmlReader::XML_START_ELEMENT:
266 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
267 if (startElement()) {
268 isError = Standard_True;
269 myError = "User abort at startElement()";
272 isError = ParseElement ();
274 case LDOM_XmlReader::XML_END_ELEMENT:
276 Standard_CString aParentName = Standard_CString(aParent->GetTagName());
277 aTextStr = (char *)myCurrentData.str();
278 if (strcmp(aTextStr, aParentName) != 0) {
279 myError = "Expected end tag \'";
280 myError += aParentName;
282 isError = Standard_True;
284 else if (endElement()) {
285 isError = Standard_True;
286 myError = "User abort at endElement()";
291 case LDOM_XmlReader::XML_TEXT:
292 aLocType = LDOM_Node::TEXT_NODE;
294 Standard_Integer aTextLen;
295 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
296 // try to convert to integer
297 if (IsDigit(aTextStr[0])) {
298 if (LDOM_XmlReader::getInteger (aTextValue, aTextStr,
299 aTextStr + aTextLen))
300 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
302 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
304 goto create_text_node;
305 case LDOM_XmlReader::XML_COMMENT:
306 aLocType = LDOM_Node::COMMENT_NODE;
308 Standard_Integer aTextLen;
309 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
310 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
312 goto create_text_node;
313 case LDOM_XmlReader::XML_CDATA:
314 aLocType = LDOM_Node::CDATA_SECTION_NODE;
315 aTextStr = (char *)myCurrentData.str();
316 aTextValue = LDOMBasicString(aTextStr,myCurrentData.Length(),myDocument);
319 LDOM_BasicNode& aTextNode =
320 LDOM_BasicText::Create (aLocType, aTextValue, myDocument);
321 aParent -> AppendChild (&aTextNode, aLastChild);
325 case LDOM_XmlReader::XML_EOF:
326 myError = "Inexpected end of file";
327 isError = Standard_True;
336 //=======================================================================
337 //function : startElement
338 //purpose : virtual hook on 'StartElement' event for descendant classes
339 //=======================================================================
341 Standard_Boolean LDOMParser::startElement ()
343 return Standard_False;
346 //=======================================================================
347 //function : endElement
348 //purpose : virtual hook on 'EndElement' event for descendant classes
349 //=======================================================================
351 Standard_Boolean LDOMParser::endElement ()
353 return Standard_False;
356 //=======================================================================
357 //function : getCurrentElement
359 //=======================================================================
361 LDOM_Element LDOMParser::getCurrentElement () const
363 return LDOM_Element (myReader -> GetElement(), myDocument);
366 //=======================================================================
367 //function : getDocument
369 //=======================================================================
371 LDOM_Document LDOMParser::getDocument ()
373 return myDocument -> Self();