1 // File: LDOM_XmlWriter.cxx
2 // Created: 28.06.01 10:32:53
3 // Author: Alexander GRIGORIEV
4 // Copyright: OpenCascade 2001
8 #include <LDOM_XmlWriter.hxx>
9 #include <LDOM_Document.hxx>
10 #include <LDOM_CharReference.hxx>
12 #define chOpenAngle '<'
13 #define chCloseAngle '>'
14 #define chOpenSquare '['
15 #define chCloseSquare ']'
16 #define chQuestion '?'
17 #define chForwardSlash '/'
24 #define chDoubleQuote '\"'
88 static const LXMLCh gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
89 static const LXMLCh gEndElement1[]= { chForwardSlash, chNull };
90 static const LXMLCh gEndPI[] = { chQuestion, chCloseAngle, chNull };
91 static const LXMLCh gStartPI[] = { chOpenAngle, chQuestion, chNull };
92 static const LXMLCh gXMLDecl1[] =
93 { chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l
94 , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i
95 , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull
97 static const LXMLCh gXMLDecl2[] =
98 { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c
99 , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual
100 , chDoubleQuote, chNull
102 static const LXMLCh gXMLDecl3[] =
103 { chDoubleQuote, chSpace, chLatin_s, chLatin_t, chLatin_a
104 , chLatin_n, chLatin_d, chLatin_a, chLatin_l, chLatin_o
105 , chLatin_n, chLatin_e, chEqual, chDoubleQuote, chNull
107 static const LXMLCh gXMLDecl4[] =
108 { chDoubleQuote, chQuestion, chCloseAngle
111 static const LXMLCh gStartCDATA[] =
112 { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
113 chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
115 static const LXMLCh gEndCDATA[] =
116 { chCloseSquare, chCloseSquare, chCloseAngle, chNull };
117 static const LXMLCh gStartComment[] =
118 { chOpenAngle, chBang, chDash, chDash, chNull };
119 static const LXMLCh gEndComment[] =
120 { chDash, chDash, chCloseAngle, chNull };
121 static const LXMLCh gStartDoctype[] =
122 { chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T,
123 chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull
125 static const LXMLCh gPublic[] =
126 { chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I,
127 chLatin_C, chSpace, chDoubleQuote, chNull
129 static const LXMLCh gSystem[] =
130 { chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E,
131 chLatin_M, chSpace, chDoubleQuote, chNull
133 static const LXMLCh gStartEntity[] =
134 { chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I,
135 chLatin_T, chLatin_Y, chSpace, chNull
137 static const LXMLCh gNotation[] =
138 { chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A,
139 chSpace, chDoubleQuote, chNull
142 static LXMLCh * getEncodingName (const LXMLCh * theEncodingName)
144 const LXMLCh * anEncoding = theEncodingName;
145 if (theEncodingName == NULL)
147 // anEncoding = // US-ASCII
148 // { chLatin_U, chLatin_S, chDash, chLatin_A, chLatin_S, chLatin_C, chLatin_I,
149 // chLatin_I, chNull };
150 static const LXMLCh anUTFEncoding [] = // UTF-8
151 { chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull };
152 anEncoding = anUTFEncoding;
154 Standard_Integer aLen = 0;
155 while (anEncoding[aLen++] != chNull);
156 LXMLCh * aResult = new LXMLCh [aLen];
157 memcpy (aResult, anEncoding, aLen * sizeof (LXMLCh));
161 //=======================================================================
162 //function : LH3D_LXMLWriter()
163 //purpose : Constructor
164 //=======================================================================
165 LDOM_XmlWriter::LDOM_XmlWriter (FILE * aFile,
166 const LXMLCh * theEncoding)
168 myEncodingName (::getEncodingName (theEncoding)),
175 //=======================================================================
176 //function : ~LDOM_XmlWriter
177 //purpose : Destructor
178 //=======================================================================
180 LDOM_XmlWriter::~LDOM_XmlWriter ()
182 delete [] myEncodingName;
183 if (myABuffer != NULL) delete [] myABuffer;
186 //=======================================================================
187 //function : operator <<
189 //=======================================================================
191 LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LDOM_Document& aDoc)
193 const char * anXMLversion = "1.0";
194 * this << gXMLDecl1 << anXMLversion
195 << gXMLDecl2 << myEncodingName << gXMLDecl4;
197 return (* this << aDoc.getDocumentElement());
200 //=======================================================================
201 //function : operator <<
202 //purpose : Stream out an LDOMString
203 //=======================================================================
205 inline LDOM_XmlWriter& LDOM_XmlWriter::operator <<
206 (const LDOMBasicString& aString)
208 switch (aString.Type()) {
209 case LDOMBasicString::LDOM_Integer:
211 Standard_Integer aValue;
212 aString.GetInteger (aValue);
213 fprintf (myFile, "%d", aValue);
216 case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags
217 case LDOMBasicString::LDOM_AsciiDocClear:
219 const char * str = aString.GetString();
221 const Standard_Integer aLen = strlen (str);
222 if (aLen > 0) fwrite (str, aLen, 1, myFile);
226 case LDOMBasicString::LDOM_AsciiFree:
227 case LDOMBasicString::LDOM_AsciiDoc:
229 const char * str = aString.GetString();
231 Standard_Integer aLen;
232 char * encStr = LDOM_CharReference::Encode(str, aLen, Standard_False);
233 if (aLen > 0) fwrite (encStr, aLen, 1, myFile);
234 if (encStr != str) delete [] encStr;
242 //=======================================================================
243 //function : operator<<()
244 //purpose : Stream out a char *.
245 //=======================================================================
246 inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh * aString)
248 unsigned int aLength = strlen (aString);
249 if (aLength > 0) fwrite ((void *) aString, aLength, 1, myFile);
253 //=======================================================================
254 //function : operator<<()
255 //purpose : Stream out a character.
256 //=======================================================================
257 inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh aChar)
259 fputc (aChar, myFile);
263 //=======================================================================
264 //function : WriteAttribute()
265 //purpose : Stream out an XML attribute.
266 //=======================================================================
267 void LDOM_XmlWriter::WriteAttribute (const LDOM_Node& theAtt)
270 const char * aName = theAtt.getNodeName().GetString();
271 const LDOMString aValueStr = theAtt.getNodeValue();
273 // Integer attribute value
274 if (aValueStr.Type() == LDOMBasicString::LDOM_Integer) {
275 Standard_Integer anIntValue;
276 aValueStr.GetInteger (anIntValue);
277 aLength = 20 + strlen (aName);
278 if (aLength > myABufferLen) {
279 if (myABuffer != NULL) delete [] myABuffer;
280 myABuffer = new char [aLength+1];
281 myABufferLen = aLength;
283 sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName,
284 chEqual, chDoubleQuote, anIntValue, chDoubleQuote);
285 aLength = strlen (myABuffer);
287 // String attribute value
289 const char * aValue = aValueStr.GetString();
291 if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear) {
292 encStr = (char *) aValue;
293 aLength = 4 + strlen (aValue) + strlen (aName);
295 encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True);
296 aLength += 4 + strlen (aName);
298 if (aLength > myABufferLen) {
299 if (myABuffer != NULL) delete [] myABuffer;
300 myABuffer = new char [aLength+1];
301 myABufferLen = aLength;
303 sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName,
304 chEqual, chDoubleQuote, encStr, chDoubleQuote);
305 if (encStr != aValue) delete [] encStr;
307 fwrite ((void *) myABuffer, aLength, 1, myFile);
310 //=======================================================================
311 //function : operator<<()
312 //purpose : Stream out a DOM node, and, recursively, all of its children.
313 // This function is the heart of writing a DOM tree out as XML source.
314 // Give it a document node and it will do the whole thing.
315 //=======================================================================
316 LDOM_XmlWriter& LDOM_XmlWriter::operator<< (const LDOM_Node& theNodeToWrite)
318 // Get the name and value out for convenience
319 LDOMString aNodeName = theNodeToWrite.getNodeName();
320 LDOMString aNodeValue = theNodeToWrite.getNodeValue();
321 // unsigned long dwLent = aNodeValue.length();
323 switch (theNodeToWrite.getNodeType())
325 case LDOM_Node::TEXT_NODE :
326 * this << aNodeValue;
328 case LDOM_Node::ELEMENT_NODE :
330 const int aMaxNSpaces = 40;
331 static LXMLCh aSpaces [] = {
332 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
333 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
334 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
335 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
336 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
337 chOpenAngle, chNull };
338 const LXMLCh * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent];
339 if (anIndentString < &aSpaces[0]) anIndentString = &aSpaces[0];
341 // Output the element start tag.
342 * this << anIndentString << aNodeName.GetString();
344 // Output any attributes of this element
345 const LDOM_Element& anElemToWrite = (const LDOM_Element&) theNodeToWrite;
346 LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList ();
347 Standard_Integer aListInd = aListAtt.getLength();
349 LDOM_Node aChild = aListAtt.item (aListInd);
350 WriteAttribute (aChild);
353 // Test for the presence of children
354 LDOM_Node aChild = theNodeToWrite.getFirstChild();
357 // There are children. Close start-tag, and output children.
358 * this << chCloseAngle;
359 if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0)
361 Standard_Boolean isChildElem = Standard_False;
364 isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE);
365 if (isChildElem) myCurIndent += myIndent;
367 if (isChildElem) myCurIndent -= myIndent;
368 do aChild = aChild.getNextSibling();
369 while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE);
371 // Done with children. Output the end tag.
374 * this << anIndentString
375 << gEndElement1 << aNodeName.GetString() << chCloseAngle;
377 * this << gEndElement << aNodeName.GetString() << chCloseAngle;
381 // There were no children. Output the short form close of
382 // the element start tag, making it an empty-element tag.
383 * this << chForwardSlash << chCloseAngle;
389 case LDOM_Node::CDATA_SECTION_NODE:
391 * this << gStartCDATA << aNodeValue << gEndCDATA;
394 case LDOM_Node::COMMENT_NODE:
396 * this << gStartComment << aNodeValue << gEndComment;
401 cerr << "Unrecognized node type = "
402 << (long)theNodeToWrite.getNodeType() << endl