1 // Created on: 2001-06-28
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 #include <LDOM_XmlWriter.hxx>
17 #include <LDOM_Document.hxx>
18 #include <LDOM_CharReference.hxx>
20 #define chOpenAngle '<'
21 #define chCloseAngle '>'
22 #define chOpenSquare '['
23 #define chCloseSquare ']'
24 #define chQuestion '?'
25 #define chForwardSlash '/'
32 #define chDoubleQuote '\"'
96 static const LXMLCh gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
97 static const LXMLCh gEndElement1[]= { chForwardSlash, chNull };
98 //static const LXMLCh gEndPI[] = { chQuestion, chCloseAngle, chNull };
99 //static const LXMLCh gStartPI[] = { chOpenAngle, chQuestion, chNull };
100 static const LXMLCh gXMLDecl1[] =
101 { chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l
102 , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i
103 , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull
105 static const LXMLCh gXMLDecl2[] =
106 { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c
107 , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual
108 , chDoubleQuote, chNull
111 static const LXMLCh gXMLDecl3[] =
112 { chDoubleQuote, chSpace, chLatin_s, chLatin_t, chLatin_a
113 , chLatin_n, chLatin_d, chLatin_a, chLatin_l, chLatin_o
114 , chLatin_n, chLatin_e, chEqual, chDoubleQuote, chNull
117 static const LXMLCh gXMLDecl4[] =
118 { chDoubleQuote, chQuestion, chCloseAngle
121 static const LXMLCh gStartCDATA[] =
122 { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
123 chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
125 static const LXMLCh gEndCDATA[] =
126 { chCloseSquare, chCloseSquare, chCloseAngle, chNull };
127 static const LXMLCh gStartComment[] =
128 { chOpenAngle, chBang, chDash, chDash, chNull };
129 static const LXMLCh gEndComment[] =
130 { chDash, chDash, chCloseAngle, chNull };
132 static const LXMLCh gStartDoctype[] =
133 { chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T,
134 chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull
136 static const LXMLCh gPublic[] =
137 { chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I,
138 chLatin_C, chSpace, chDoubleQuote, chNull
140 static const LXMLCh gSystem[] =
141 { chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E,
142 chLatin_M, chSpace, chDoubleQuote, chNull
144 static const LXMLCh gStartEntity[] =
145 { chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I,
146 chLatin_T, chLatin_Y, chSpace, chNull
148 static const LXMLCh gNotation[] =
149 { chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A,
150 chSpace, chDoubleQuote, chNull
154 static LXMLCh * getEncodingName (const LXMLCh * theEncodingName)
156 const LXMLCh * anEncoding = theEncodingName;
157 if (theEncodingName == NULL)
159 // anEncoding = // US-ASCII
160 // { chLatin_U, chLatin_S, chDash, chLatin_A, chLatin_S, chLatin_C, chLatin_I,
161 // chLatin_I, chNull };
162 static const LXMLCh anUTFEncoding [] = // UTF-8
163 { chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull };
164 anEncoding = anUTFEncoding;
166 Standard_Integer aLen = 0;
167 while (anEncoding[aLen++] != chNull);
168 LXMLCh * aResult = new LXMLCh [aLen];
169 memcpy (aResult, anEncoding, aLen * sizeof (LXMLCh));
173 //=======================================================================
174 //function : LH3D_LXMLWriter()
175 //purpose : Constructor
176 //=======================================================================
177 LDOM_XmlWriter::LDOM_XmlWriter (FILE * aFile,
178 const LXMLCh * theEncoding)
180 myEncodingName (::getEncodingName (theEncoding)),
187 //=======================================================================
188 //function : ~LDOM_XmlWriter
189 //purpose : Destructor
190 //=======================================================================
192 LDOM_XmlWriter::~LDOM_XmlWriter ()
194 delete [] myEncodingName;
195 if (myABuffer != NULL) delete [] myABuffer;
198 //=======================================================================
199 //function : operator <<
201 //=======================================================================
203 LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LDOM_Document& aDoc)
205 const char * anXMLversion = "1.0";
206 * this << gXMLDecl1 << anXMLversion
207 << gXMLDecl2 << myEncodingName << gXMLDecl4;
209 return (* this << aDoc.getDocumentElement());
212 //=======================================================================
213 //function : operator <<
214 //purpose : Stream out an LDOMString
215 //=======================================================================
217 inline LDOM_XmlWriter& LDOM_XmlWriter::operator <<
218 (const LDOMBasicString& aString)
220 switch (aString.Type()) {
221 case LDOMBasicString::LDOM_Integer:
223 Standard_Integer aValue;
224 aString.GetInteger (aValue);
225 fprintf (myFile, "%d", aValue);
228 case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags
229 case LDOMBasicString::LDOM_AsciiDocClear:
231 const char * str = aString.GetString();
233 const Standard_Size aLen = strlen (str);
234 if (aLen > 0) fwrite (str, aLen, 1, myFile);
238 case LDOMBasicString::LDOM_AsciiFree:
239 case LDOMBasicString::LDOM_AsciiDoc:
241 const char * str = aString.GetString();
243 Standard_Integer aLen;
244 char * encStr = LDOM_CharReference::Encode(str, aLen, Standard_False);
245 if (aLen > 0) fwrite (encStr, aLen, 1, myFile);
246 if (encStr != str) delete [] encStr;
254 //=======================================================================
255 //function : operator<<()
256 //purpose : Stream out a char *.
257 //=======================================================================
258 inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh * aString)
260 Standard_Size aLength = strlen (aString);
261 if (aLength > 0) fwrite ((void *) aString, aLength, 1, myFile);
265 //=======================================================================
266 //function : operator<<()
267 //purpose : Stream out a character.
268 //=======================================================================
269 inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh aChar)
271 fputc (aChar, myFile);
275 //=======================================================================
276 //function : WriteAttribute()
277 //purpose : Stream out an XML attribute.
278 //=======================================================================
279 void LDOM_XmlWriter::WriteAttribute (const LDOM_Node& theAtt)
282 const char * aName = theAtt.getNodeName().GetString();
283 const LDOMString aValueStr = theAtt.getNodeValue();
285 // Integer attribute value
286 if (aValueStr.Type() == LDOMBasicString::LDOM_Integer) {
287 Standard_Integer anIntValue;
288 aValueStr.GetInteger (anIntValue);
289 aLength = (Standard_Integer) (20 + strlen (aName));
290 if (aLength > myABufferLen) {
291 if (myABuffer != NULL) delete [] myABuffer;
292 myABuffer = new char [aLength+1];
293 myABufferLen = aLength;
295 sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName,
296 chEqual, chDoubleQuote, anIntValue, chDoubleQuote);
297 aLength = (Standard_Integer) strlen (myABuffer);
299 // String attribute value
301 const char * aValue = aValueStr.GetString();
303 if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear) {
304 encStr = (char *) aValue;
305 aLength = (Standard_Integer) (4 + strlen (aValue) + strlen (aName));
307 encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True);
308 aLength += (Standard_Integer) (4 + strlen (aName));
310 if (aLength > myABufferLen) {
311 if (myABuffer != NULL) delete [] myABuffer;
312 myABuffer = new char [aLength+1];
313 myABufferLen = aLength;
315 sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName,
316 chEqual, chDoubleQuote, encStr, chDoubleQuote);
317 if (encStr != aValue) delete [] encStr;
319 fwrite ((void *) myABuffer, aLength, 1, myFile);
322 //=======================================================================
323 //function : operator<<()
324 //purpose : Stream out a DOM node, and, recursively, all of its children.
325 // This function is the heart of writing a DOM tree out as XML source.
326 // Give it a document node and it will do the whole thing.
327 //=======================================================================
328 LDOM_XmlWriter& LDOM_XmlWriter::operator<< (const LDOM_Node& theNodeToWrite)
330 // Get the name and value out for convenience
331 LDOMString aNodeName = theNodeToWrite.getNodeName();
332 LDOMString aNodeValue = theNodeToWrite.getNodeValue();
333 // unsigned long dwLent = aNodeValue.length();
335 switch (theNodeToWrite.getNodeType())
337 case LDOM_Node::TEXT_NODE :
338 * this << aNodeValue;
340 case LDOM_Node::ELEMENT_NODE :
342 const int aMaxNSpaces = 40;
343 static LXMLCh aSpaces [] = {
344 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
345 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
346 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
347 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
348 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
349 chOpenAngle, chNull };
350 const LXMLCh * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent];
351 if (anIndentString < &aSpaces[0]) anIndentString = &aSpaces[0];
353 // Output the element start tag.
354 * this << anIndentString << aNodeName.GetString();
356 // Output any attributes of this element
357 const LDOM_Element& anElemToWrite = (const LDOM_Element&) theNodeToWrite;
358 LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList ();
359 Standard_Integer aListInd = aListAtt.getLength();
361 LDOM_Node aChild = aListAtt.item (aListInd);
362 WriteAttribute (aChild);
365 // Test for the presence of children
366 LDOM_Node aChild = theNodeToWrite.getFirstChild();
369 // There are children. Close start-tag, and output children.
370 * this << chCloseAngle;
371 if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0)
373 Standard_Boolean isChildElem = Standard_False;
376 isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE);
377 if (isChildElem) myCurIndent += myIndent;
379 if (isChildElem) myCurIndent -= myIndent;
380 do aChild = aChild.getNextSibling();
381 while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE);
383 // Done with children. Output the end tag.
386 * this << anIndentString
387 << gEndElement1 << aNodeName.GetString() << chCloseAngle;
389 * this << gEndElement << aNodeName.GetString() << chCloseAngle;
393 // There were no children. Output the short form close of
394 // the element start tag, making it an empty-element tag.
395 * this << chForwardSlash << chCloseAngle;
401 case LDOM_Node::CDATA_SECTION_NODE:
403 * this << gStartCDATA << aNodeValue << gEndCDATA;
406 case LDOM_Node::COMMENT_NODE:
408 * this << gStartComment << aNodeValue << gEndComment;
413 cerr << "Unrecognized node type = "
414 << (long)theNodeToWrite.getNodeType() << endl