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)
116 // Open the DOM Document
117 myDocument = new LDOM_MemManager (20000);
120 // Create the Reader instance
121 if (myReader) delete myReader;
122 myReader = new LDOM_XmlReader (myDocument, myError);
125 return ParseDocument (anInput);
128 //=======================================================================
131 //=======================================================================
133 Standard_Boolean LDOMParser::parse (const char * const aFileName)
135 std::ifstream aFileStream;
136 OSD_OpenStream (aFileStream, aFileName, std::ios::in);
138 if (aFileStream.good())
140 return parse (aFileStream);
144 myError = "Fatal XML error: Cannot open XML file";
145 return Standard_True;
149 //=======================================================================
150 //function : ParseDocument
151 //purpose : parse the whole document (abstracted from the XML source)
152 //=======================================================================
154 Standard_Boolean LDOMParser::ParseDocument (istream& theIStream)
156 Standard_Boolean isError = Standard_False;
157 Standard_Boolean isElement = Standard_False;
158 Standard_Boolean isDoctype = Standard_False;
161 LDOM_XmlReader::RecordType aType = ReadRecord (*myReader, theIStream, myCurrentData);
163 case LDOM_XmlReader::XML_HEADER:
164 if (isDoctype || isElement) {
165 myError = "Unexpected XML declaration";
166 isError = Standard_True;
170 case LDOM_XmlReader::XML_DOCTYPE:
172 myError = "Unexpected DOCTYPE declaration";
173 isError = Standard_True;
176 isDoctype = Standard_True;
177 case LDOM_XmlReader::XML_COMMENT:
179 case LDOM_XmlReader::XML_FULL_ELEMENT:
180 if (isElement == Standard_False) {
181 isElement = Standard_True;
182 myDocument -> myRootElement = &myReader -> GetElement ();
183 if (startElement()) {
184 isError = Standard_True;
185 myError = "User abort at startElement()";
189 isError = Standard_True;
190 myError = "User abort at endElement()";
195 case LDOM_XmlReader::XML_START_ELEMENT:
196 if (isElement == Standard_False) {
197 isElement = Standard_True;
198 myDocument -> myRootElement = &myReader -> GetElement ();
199 if (startElement()) {
200 isError = Standard_True;
201 myError = "User abort at startElement()";
204 isError = ParseElement (theIStream);
208 isError = Standard_True;
209 myError = "Expected comment or end-of-file";
210 case LDOM_XmlReader::XML_END_ELEMENT:
212 isError = Standard_True;
213 myError = "User abort at endElement()";
215 case LDOM_XmlReader::XML_EOF:
217 case LDOM_XmlReader::XML_UNKNOWN:
220 myError = "Unexpected data beyond the Document Element";
222 isError = Standard_True;
229 //=======================================================================
230 //function : ParseElement
231 //purpose : parse one element, given the type of its XML presentation
232 //=======================================================================
234 Standard_Boolean LDOMParser::ParseElement (Standard_IStream& theIStream)
236 Standard_Boolean isError = Standard_False;
237 const LDOM_BasicElement * aParent = &myReader->GetElement();
238 const LDOM_BasicNode * aLastChild = NULL;
240 LDOM_Node::NodeType aLocType;
241 LDOMBasicString aTextValue;
243 LDOM_XmlReader::RecordType aType = ReadRecord (* myReader, theIStream, myCurrentData);
245 case LDOM_XmlReader::XML_UNKNOWN:
246 isError = Standard_True;
248 case LDOM_XmlReader::XML_FULL_ELEMENT:
249 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
250 if (startElement()) {
251 isError = Standard_True;
252 myError = "User abort at startElement()";
256 isError = Standard_True;
257 myError = "User abort at endElement()";
261 case LDOM_XmlReader::XML_START_ELEMENT:
262 aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
263 if (startElement()) {
264 isError = Standard_True;
265 myError = "User abort at startElement()";
268 isError = ParseElement (theIStream);
270 case LDOM_XmlReader::XML_END_ELEMENT:
272 Standard_CString aParentName = Standard_CString(aParent->GetTagName());
273 aTextStr = (char *)myCurrentData.str();
274 if (strcmp(aTextStr, aParentName) != 0) {
275 myError = "Expected end tag \'";
276 myError += aParentName;
278 isError = Standard_True;
280 else if (endElement()) {
281 isError = Standard_True;
282 myError = "User abort at endElement()";
287 case LDOM_XmlReader::XML_TEXT:
288 aLocType = LDOM_Node::TEXT_NODE;
290 Standard_Integer aTextLen;
291 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
292 // try to convert to integer
293 if (IsDigit(aTextStr[0])) {
294 if (LDOM_XmlReader::getInteger (aTextValue, aTextStr,
295 aTextStr + aTextLen))
296 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
298 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
300 goto create_text_node;
301 case LDOM_XmlReader::XML_COMMENT:
302 aLocType = LDOM_Node::COMMENT_NODE;
304 Standard_Integer aTextLen;
305 aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
306 aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
308 goto create_text_node;
309 case LDOM_XmlReader::XML_CDATA:
310 aLocType = LDOM_Node::CDATA_SECTION_NODE;
311 aTextStr = (char *)myCurrentData.str();
312 aTextValue = LDOMBasicString(aTextStr,myCurrentData.Length(),myDocument);
315 LDOM_BasicNode& aTextNode =
316 LDOM_BasicText::Create (aLocType, aTextValue, myDocument);
317 aParent -> AppendChild (&aTextNode, aLastChild);
321 case LDOM_XmlReader::XML_EOF:
322 myError = "Inexpected end of file";
323 isError = Standard_True;
332 //=======================================================================
333 //function : startElement
334 //purpose : virtual hook on 'StartElement' event for descendant classes
335 //=======================================================================
337 Standard_Boolean LDOMParser::startElement ()
339 return Standard_False;
342 //=======================================================================
343 //function : endElement
344 //purpose : virtual hook on 'EndElement' event for descendant classes
345 //=======================================================================
347 Standard_Boolean LDOMParser::endElement ()
349 return Standard_False;
352 //=======================================================================
353 //function : getCurrentElement
355 //=======================================================================
357 LDOM_Element LDOMParser::getCurrentElement () const
359 return LDOM_Element (myReader -> GetElement(), myDocument);
362 //=======================================================================
363 //function : getDocument
365 //=======================================================================
367 LDOM_Document LDOMParser::getDocument ()
369 return myDocument -> Self();