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 char gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
97 static const char gEndElement1[]= { chForwardSlash, chNull };
99 static const char gXMLDecl1[] =
100 { chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l
101 , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i
102 , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull
104 static const char gXMLDecl2[] =
105 { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c
106 , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual
107 , chDoubleQuote, chNull
110 static const char gXMLDecl4[] =
111 { chDoubleQuote, chQuestion, chCloseAngle
114 static const char gStartCDATA[] =
115 { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
116 chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
118 static const char gEndCDATA[] =
119 { chCloseSquare, chCloseSquare, chCloseAngle, chNull };
120 static const char gStartComment[] =
121 { chOpenAngle, chBang, chDash, chDash, chNull };
122 static const char gEndComment[] =
123 { chDash, chDash, chCloseAngle, chNull };
125 static char* getEncodingName (const char* theEncodingName)
127 const char* anEncoding = theEncodingName;
128 if (theEncodingName == NULL)
130 static const char anUTFEncoding [] = {chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull};
131 anEncoding = anUTFEncoding;
134 Standard_Integer aLen = 0;
135 while (anEncoding[aLen++] != chNull);
137 char * aResult = new char [aLen];
138 memcpy (aResult, anEncoding, aLen * sizeof (char));
143 //=======================================================================
144 //function : LDOM_XmlWriter
146 //=======================================================================
147 LDOM_XmlWriter::LDOM_XmlWriter (const char * theEncoding)
148 : myEncodingName (::getEncodingName (theEncoding)),
157 //=======================================================================
158 //function : ~LDOM_XmlWriter
159 //purpose : Destructor
160 //=======================================================================
161 LDOM_XmlWriter::~LDOM_XmlWriter ()
163 delete [] myEncodingName;
165 if (myABuffer != NULL)
171 //=======================================================================
174 //=======================================================================
175 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOM_Document& aDoc)
177 Write (theOStream, gXMLDecl1);
179 const char * anXMLversion = "1.0";
180 Write (theOStream, anXMLversion);
182 Write (theOStream, gXMLDecl2);
183 Write (theOStream, myEncodingName);
184 Write (theOStream, gXMLDecl4);
186 Write (theOStream, aDoc.getDocumentElement());
189 //=======================================================================
192 //=======================================================================
193 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOM_Node& theNode)
195 // Get the name and value out for convenience
196 LDOMString aNodeName = theNode.getNodeName();
197 LDOMString aNodeValue = theNode.getNodeValue();
199 switch (theNode.getNodeType())
201 case LDOM_Node::TEXT_NODE :
202 Write (theOStream, aNodeValue);
204 case LDOM_Node::ELEMENT_NODE :
206 const int aMaxNSpaces = 40;
207 static char aSpaces [] = {
208 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
209 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
210 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
211 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
212 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
213 chOpenAngle, chNull };
214 const char * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent];
216 if (anIndentString < &aSpaces[0])
218 anIndentString = &aSpaces[0];
221 // Output the element start tag.
222 Write (theOStream, anIndentString);
223 Write (theOStream, aNodeName.GetString());
225 // Output any attributes of this element
226 const LDOM_Element& anElemToWrite = (const LDOM_Element&)theNode;
227 LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList();
228 Standard_Integer aListInd = aListAtt.getLength();
232 LDOM_Node aChild = aListAtt.item (aListInd);
233 WriteAttribute (theOStream, aChild);
236 // Test for the presence of children
237 LDOM_Node aChild = theNode.getFirstChild();
240 // There are children. Close start-tag, and output children.
241 Write (theOStream, chCloseAngle);
242 if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0)
244 Write(theOStream, chLF);
247 Standard_Boolean isChildElem = Standard_False;
250 isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE);
253 myCurIndent += myIndent;
256 Write(theOStream, aChild);
260 myCurIndent -= myIndent;
265 aChild = aChild.getNextSibling();
266 } while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE);
269 // Done with children. Output the end tag.
272 Write (theOStream, anIndentString);
273 Write (theOStream, gEndElement1);
274 Write (theOStream, aNodeName.GetString());
275 Write (theOStream, chCloseAngle);
279 Write (theOStream, gEndElement);
280 Write (theOStream, aNodeName.GetString());
281 Write (theOStream, chCloseAngle);
286 // There were no children. Output the short form close of
287 // the element start tag, making it an empty-element tag.
288 Write (theOStream, chForwardSlash);
289 Write (theOStream, chCloseAngle);
294 Write (theOStream, chLF);
298 case LDOM_Node::CDATA_SECTION_NODE:
300 Write (theOStream, gStartCDATA);
301 Write (theOStream, aNodeValue);
302 Write (theOStream, gEndCDATA);
305 case LDOM_Node::COMMENT_NODE:
307 Write (theOStream, gStartComment);
308 Write (theOStream, aNodeValue);
309 Write (theOStream, gEndComment);
314 std::cerr << "Unrecognized node type = "
315 << (long)theNode.getNodeType() << std::endl
320 //=======================================================================
322 //purpose : Stream out an LDOMString
323 //=======================================================================
324 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOMBasicString& theString)
326 switch (theString.Type())
328 case LDOMBasicString::LDOM_Integer:
330 Standard_Integer aValue;
331 theString.GetInteger (aValue);
333 TCollection_AsciiString aStrValue (aValue);
334 theOStream.write(aStrValue.ToCString(), strlen (aStrValue.ToCString()));
338 case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags
339 case LDOMBasicString::LDOM_AsciiDocClear:
341 const char* aStr = theString.GetString();
344 const Standard_Size aLen = strlen (aStr);
347 theOStream.write(aStr, aLen);
352 case LDOMBasicString::LDOM_AsciiFree:
353 case LDOMBasicString::LDOM_AsciiDoc:
355 const char* aStr = theString.GetString();
358 Standard_Integer aLen;
359 char* encStr = LDOM_CharReference::Encode (aStr, aLen, Standard_False);
362 theOStream.write(encStr, aLen);
375 //=======================================================================
377 //purpose : Stream out a char
378 //=======================================================================
379 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const char theChar)
381 theOStream.write (&theChar, sizeof(char));
384 //=======================================================================
386 //purpose : Stream out a char *
387 //=======================================================================
388 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const char * theString)
390 Standard_Size aLength = strlen (theString);
393 theOStream.write (theString, aLength);
397 //=======================================================================
398 //function : WriteAttribute()
399 //purpose : Stream out an XML attribute.
400 //=======================================================================
401 void LDOM_XmlWriter::WriteAttribute (Standard_OStream& theOStream, const LDOM_Node& theAtt)
403 const char* aName = theAtt.getNodeName().GetString();
404 const LDOMString aValueStr = theAtt.getNodeValue();
408 // Integer attribute value
409 if (aValueStr.Type() == LDOMBasicString::LDOM_Integer)
411 Standard_Integer anIntValue;
412 aValueStr.GetInteger (anIntValue);
414 aLength = (Standard_Integer)(20 + strlen (aName));
415 if (aLength > myABufferLen)
417 if (myABuffer != NULL)
422 myABuffer = new char [aLength+1];
423 myABufferLen = aLength;
425 sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName, chEqual, chDoubleQuote, anIntValue, chDoubleQuote);
426 aLength = (Standard_Integer)strlen (myABuffer);
430 else // String attribute value
433 const char* aValue = aValueStr.GetString();
434 if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear)
436 encStr = (char *) aValue;
437 aLength = (Standard_Integer) (4 + strlen (aValue) + strlen (aName));
441 encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True);
442 aLength += (Standard_Integer) (4 + strlen (aName));
445 if (aLength > myABufferLen)
447 if (myABuffer != NULL)
452 myABuffer = new char [aLength+1];
453 myABufferLen = aLength;
456 sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName, chEqual, chDoubleQuote, encStr, chDoubleQuote);
458 if (encStr != aValue)
464 theOStream.write (myABuffer, aLength);