b311480e |
1 | // Created on: 2001-06-28 |
2 | // Created by: Alexander GRIGORIEV |
973c2be1 |
3 | // Copyright (c) 2001-2014 OPEN CASCADE SAS |
b311480e |
4 | // |
973c2be1 |
5 | // This file is part of Open CASCADE Technology software library. |
b311480e |
6 | // |
d5f74e42 |
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 |
973c2be1 |
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. |
b311480e |
12 | // |
973c2be1 |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
7fd59977 |
15 | |
16 | #include <LDOM_XmlWriter.hxx> |
17 | #include <LDOM_Document.hxx> |
18 | #include <LDOM_CharReference.hxx> |
19 | |
20 | #define chOpenAngle '<' |
21 | #define chCloseAngle '>' |
22 | #define chOpenSquare '[' |
23 | #define chCloseSquare ']' |
24 | #define chQuestion '?' |
25 | #define chForwardSlash '/' |
26 | #define chLF '\n' |
27 | #define chNull '\0' |
28 | #define chEqual '=' |
29 | #define chDash '-' |
30 | #define chBang '!' |
31 | #define chSpace ' ' |
32 | #define chDoubleQuote '\"' |
33 | #define chZero '0' |
34 | #define chOne '1' |
35 | #define chTwo '2' |
36 | #define chThree '3' |
37 | #define chFour '4' |
38 | #define chFive '5' |
39 | #define chSix '6' |
40 | #define chSeven '7' |
41 | #define chEight '8' |
42 | #define chNine '9' |
43 | #define chLatin_a 'a' |
44 | #define chLatin_b 'b' |
45 | #define chLatin_c 'c' |
46 | #define chLatin_d 'd' |
47 | #define chLatin_e 'e' |
48 | #define chLatin_f 'f' |
49 | #define chLatin_g 'g' |
50 | #define chLatin_h 'h' |
51 | #define chLatin_i 'i' |
52 | #define chLatin_j 'j' |
53 | #define chLatin_k 'k' |
54 | #define chLatin_l 'l' |
55 | #define chLatin_m 'm' |
56 | #define chLatin_n 'n' |
57 | #define chLatin_o 'o' |
58 | #define chLatin_p 'p' |
59 | #define chLatin_q 'q' |
60 | #define chLatin_r 'r' |
61 | #define chLatin_s 's' |
62 | #define chLatin_t 't' |
63 | #define chLatin_u 'u' |
64 | #define chLatin_v 'v' |
65 | #define chLatin_w 'w' |
66 | #define chLatin_x 'x' |
67 | #define chLatin_y 'y' |
68 | #define chLatin_z 'z' |
69 | #define chLatin_A 'A' |
70 | #define chLatin_B 'B' |
71 | #define chLatin_C 'C' |
72 | #define chLatin_D 'D' |
73 | #define chLatin_E 'E' |
74 | #define chLatin_F 'F' |
75 | #define chLatin_G 'G' |
76 | #define chLatin_H 'H' |
77 | #define chLatin_I 'I' |
78 | #define chLatin_J 'J' |
79 | #define chLatin_K 'K' |
80 | #define chLatin_L 'L' |
81 | #define chLatin_M 'M' |
82 | #define chLatin_N 'N' |
83 | #define chLatin_O 'O' |
84 | #define chLatin_P 'P' |
85 | #define chLatin_Q 'Q' |
86 | #define chLatin_R 'R' |
87 | #define chLatin_S 'S' |
88 | #define chLatin_T 'T' |
89 | #define chLatin_U 'U' |
90 | #define chLatin_V 'V' |
91 | #define chLatin_W 'W' |
92 | #define chLatin_X 'X' |
93 | #define chLatin_Y 'Y' |
94 | #define chLatin_Z 'Z' |
95 | |
4ff92abe |
96 | static const char gEndElement[] = { chOpenAngle, chForwardSlash, chNull }; |
97 | static const char gEndElement1[]= { chForwardSlash, chNull }; |
98 | |
99 | static const char gXMLDecl1[] = |
7fd59977 |
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 |
103 | }; |
4ff92abe |
104 | static const char gXMLDecl2[] = |
7fd59977 |
105 | { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c |
106 | , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual |
107 | , chDoubleQuote, chNull |
108 | }; |
4ff92abe |
109 | |
110 | static const char gXMLDecl4[] = |
7fd59977 |
111 | { chDoubleQuote, chQuestion, chCloseAngle |
112 | , chLF, chNull |
113 | }; |
4ff92abe |
114 | static const char gStartCDATA[] = |
7fd59977 |
115 | { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D, |
116 | chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull |
117 | }; |
4ff92abe |
118 | static const char gEndCDATA[] = |
7fd59977 |
119 | { chCloseSquare, chCloseSquare, chCloseAngle, chNull }; |
4ff92abe |
120 | static const char gStartComment[] = |
7fd59977 |
121 | { chOpenAngle, chBang, chDash, chDash, chNull }; |
4ff92abe |
122 | static const char gEndComment[] = |
7fd59977 |
123 | { chDash, chDash, chCloseAngle, chNull }; |
7fd59977 |
124 | |
4ff92abe |
125 | static char* getEncodingName (const char* theEncodingName) |
7fd59977 |
126 | { |
4ff92abe |
127 | const char* anEncoding = theEncodingName; |
7fd59977 |
128 | if (theEncodingName == NULL) |
129 | { |
4ff92abe |
130 | static const char anUTFEncoding [] = {chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull}; |
7fd59977 |
131 | anEncoding = anUTFEncoding; |
132 | } |
4ff92abe |
133 | |
7fd59977 |
134 | Standard_Integer aLen = 0; |
135 | while (anEncoding[aLen++] != chNull); |
4ff92abe |
136 | |
137 | char * aResult = new char [aLen]; |
138 | memcpy (aResult, anEncoding, aLen * sizeof (char)); |
139 | |
7fd59977 |
140 | return aResult; |
141 | } |
142 | |
143 | //======================================================================= |
4ff92abe |
144 | //function : LDOM_XmlWriter |
145 | //purpose : |
7fd59977 |
146 | //======================================================================= |
4ff92abe |
147 | LDOM_XmlWriter::LDOM_XmlWriter (const char * theEncoding) |
148 | : myEncodingName (::getEncodingName (theEncoding)), |
149 | myIndent (0), |
150 | myCurIndent (0), |
151 | myABuffer (NULL), |
152 | myABufferLen (0) |
153 | { |
154 | ; |
155 | } |
7fd59977 |
156 | |
157 | //======================================================================= |
158 | //function : ~LDOM_XmlWriter |
159 | //purpose : Destructor |
160 | //======================================================================= |
7fd59977 |
161 | LDOM_XmlWriter::~LDOM_XmlWriter () |
162 | { |
163 | delete [] myEncodingName; |
7fd59977 |
164 | |
4ff92abe |
165 | if (myABuffer != NULL) |
166 | { |
167 | delete [] myABuffer; |
7fd59977 |
168 | } |
7fd59977 |
169 | } |
170 | |
171 | //======================================================================= |
4ff92abe |
172 | //function : Write |
173 | //purpose : |
7fd59977 |
174 | //======================================================================= |
4ff92abe |
175 | void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOM_Document& aDoc) |
7fd59977 |
176 | { |
4ff92abe |
177 | Write (theOStream, gXMLDecl1); |
7fd59977 |
178 | |
4ff92abe |
179 | const char * anXMLversion = "1.0"; |
180 | Write (theOStream, anXMLversion); |
7fd59977 |
181 | |
4ff92abe |
182 | Write (theOStream, gXMLDecl2); |
183 | Write (theOStream, myEncodingName); |
184 | Write (theOStream, gXMLDecl4); |
7fd59977 |
185 | |
4ff92abe |
186 | Write (theOStream, aDoc.getDocumentElement()); |
7fd59977 |
187 | } |
188 | |
189 | //======================================================================= |
4ff92abe |
190 | //function : Write |
191 | //purpose : |
7fd59977 |
192 | //======================================================================= |
4ff92abe |
193 | void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOM_Node& theNode) |
7fd59977 |
194 | { |
195 | // Get the name and value out for convenience |
4ff92abe |
196 | LDOMString aNodeName = theNode.getNodeName(); |
197 | LDOMString aNodeValue = theNode.getNodeValue(); |
7fd59977 |
198 | |
4ff92abe |
199 | switch (theNode.getNodeType()) |
7fd59977 |
200 | { |
4ff92abe |
201 | case LDOM_Node::TEXT_NODE : |
202 | Write (theOStream, aNodeValue); |
7fd59977 |
203 | break; |
4ff92abe |
204 | case LDOM_Node::ELEMENT_NODE : |
7fd59977 |
205 | { |
206 | const int aMaxNSpaces = 40; |
4ff92abe |
207 | static char aSpaces [] = { |
7fd59977 |
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 }; |
4ff92abe |
214 | const char * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent]; |
215 | |
216 | if (anIndentString < &aSpaces[0]) |
217 | { |
218 | anIndentString = &aSpaces[0]; |
219 | } |
7fd59977 |
220 | |
221 | // Output the element start tag. |
4ff92abe |
222 | Write (theOStream, anIndentString); |
223 | Write (theOStream, aNodeName.GetString()); |
7fd59977 |
224 | |
4ff92abe |
225 | // Output any attributes of this element |
226 | const LDOM_Element& anElemToWrite = (const LDOM_Element&)theNode; |
227 | LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList(); |
7fd59977 |
228 | Standard_Integer aListInd = aListAtt.getLength(); |
4ff92abe |
229 | |
230 | while (aListInd--) |
231 | { |
7fd59977 |
232 | LDOM_Node aChild = aListAtt.item (aListInd); |
4ff92abe |
233 | WriteAttribute (theOStream, aChild); |
7fd59977 |
234 | } |
235 | |
236 | // Test for the presence of children |
4ff92abe |
237 | LDOM_Node aChild = theNode.getFirstChild(); |
7fd59977 |
238 | if (aChild != 0) |
239 | { |
240 | // There are children. Close start-tag, and output children. |
4ff92abe |
241 | Write (theOStream, chCloseAngle); |
7fd59977 |
242 | if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0) |
4ff92abe |
243 | { |
244 | Write(theOStream, chLF); |
245 | } |
246 | |
7fd59977 |
247 | Standard_Boolean isChildElem = Standard_False; |
248 | while( aChild != 0) |
249 | { |
250 | isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE); |
4ff92abe |
251 | if (isChildElem) |
252 | { |
253 | myCurIndent += myIndent; |
254 | } |
255 | |
256 | Write(theOStream, aChild); |
257 | |
258 | if (isChildElem) |
259 | { |
260 | myCurIndent -= myIndent; |
261 | } |
262 | |
263 | do |
264 | { |
265 | aChild = aChild.getNextSibling(); |
266 | } while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE); |
7fd59977 |
267 | } |
4ff92abe |
268 | |
7fd59977 |
269 | // Done with children. Output the end tag. |
7fd59977 |
270 | if (isChildElem) |
4ff92abe |
271 | { |
272 | Write (theOStream, anIndentString); |
273 | Write (theOStream, gEndElement1); |
274 | Write (theOStream, aNodeName.GetString()); |
275 | Write (theOStream, chCloseAngle); |
276 | } |
7fd59977 |
277 | else |
4ff92abe |
278 | { |
279 | Write (theOStream, gEndElement); |
280 | Write (theOStream, aNodeName.GetString()); |
281 | Write (theOStream, chCloseAngle); |
282 | } |
7fd59977 |
283 | } |
284 | else |
285 | { |
286 | // There were no children. Output the short form close of |
287 | // the element start tag, making it an empty-element tag. |
4ff92abe |
288 | Write (theOStream, chForwardSlash); |
289 | Write (theOStream, chCloseAngle); |
7fd59977 |
290 | } |
4ff92abe |
291 | |
7fd59977 |
292 | if (myIndent > 0) |
4ff92abe |
293 | { |
294 | Write (theOStream, chLF); |
295 | } |
7fd59977 |
296 | break; |
297 | } |
298 | case LDOM_Node::CDATA_SECTION_NODE: |
299 | { |
4ff92abe |
300 | Write (theOStream, gStartCDATA); |
301 | Write (theOStream, aNodeValue); |
302 | Write (theOStream, gEndCDATA); |
7fd59977 |
303 | break; |
304 | } |
305 | case LDOM_Node::COMMENT_NODE: |
306 | { |
4ff92abe |
307 | Write (theOStream, gStartComment); |
308 | Write (theOStream, aNodeValue); |
309 | Write (theOStream, gEndComment); |
7fd59977 |
310 | break; |
311 | } |
312 | default: |
57c28b61 |
313 | #ifndef _MSC_VER |
7fd59977 |
314 | cerr << "Unrecognized node type = " |
4ff92abe |
315 | << (long)theNode.getNodeType() << endl |
7fd59977 |
316 | #endif |
317 | ; } |
4ff92abe |
318 | } |
319 | |
320 | //======================================================================= |
321 | //function : |
322 | //purpose : Stream out an LDOMString |
323 | //======================================================================= |
324 | void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOMBasicString& theString) |
325 | { |
326 | switch (theString.Type()) |
327 | { |
328 | case LDOMBasicString::LDOM_Integer: |
329 | { |
330 | Standard_Integer aValue; |
331 | theString.GetInteger (aValue); |
332 | |
333 | TCollection_AsciiString aStrValue (aValue); |
334 | theOStream.write(aStrValue.ToCString(), strlen (aStrValue.ToCString())); |
335 | |
336 | break; |
337 | } |
338 | case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags |
339 | case LDOMBasicString::LDOM_AsciiDocClear: |
340 | { |
341 | const char* aStr = theString.GetString(); |
342 | if (aStr) |
343 | { |
344 | const Standard_Size aLen = strlen (aStr); |
345 | if (aLen > 0) |
346 | { |
347 | theOStream.write(aStr, aLen); |
348 | } |
349 | } |
350 | } |
351 | break; |
352 | case LDOMBasicString::LDOM_AsciiFree: |
353 | case LDOMBasicString::LDOM_AsciiDoc: |
354 | { |
355 | const char* aStr = theString.GetString(); |
356 | if (aStr) |
357 | { |
358 | Standard_Integer aLen; |
359 | char* encStr = LDOM_CharReference::Encode (aStr, aLen, Standard_False); |
360 | if (aLen > 0) |
361 | { |
362 | theOStream.write(encStr, aLen); |
363 | } |
364 | |
365 | if (encStr != aStr) |
366 | { |
367 | delete [] encStr; |
368 | } |
369 | } |
370 | } |
371 | default: ; |
372 | } |
373 | } |
374 | |
375 | //======================================================================= |
376 | //function : Write |
377 | //purpose : Stream out a char |
378 | //======================================================================= |
379 | void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const char theChar) |
380 | { |
381 | theOStream.write (&theChar, sizeof(char)); |
382 | } |
383 | |
384 | //======================================================================= |
385 | //function : Write |
386 | //purpose : Stream out a char * |
387 | //======================================================================= |
388 | void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const char * theString) |
389 | { |
390 | Standard_Size aLength = strlen (theString); |
391 | if (aLength > 0) |
392 | { |
393 | theOStream.write (theString, aLength); |
394 | } |
395 | } |
396 | |
397 | //======================================================================= |
398 | //function : WriteAttribute() |
399 | //purpose : Stream out an XML attribute. |
400 | //======================================================================= |
401 | void LDOM_XmlWriter::WriteAttribute (Standard_OStream& theOStream, const LDOM_Node& theAtt) |
402 | { |
403 | const char* aName = theAtt.getNodeName().GetString(); |
404 | const LDOMString aValueStr = theAtt.getNodeValue(); |
405 | |
406 | int aLength = 0; |
407 | |
408 | // Integer attribute value |
409 | if (aValueStr.Type() == LDOMBasicString::LDOM_Integer) |
410 | { |
411 | Standard_Integer anIntValue; |
412 | aValueStr.GetInteger (anIntValue); |
413 | |
414 | aLength = (Standard_Integer)(20 + strlen (aName)); |
415 | if (aLength > myABufferLen) |
416 | { |
417 | if (myABuffer != NULL) |
418 | { |
419 | delete [] myABuffer; |
420 | } |
421 | |
422 | myABuffer = new char [aLength+1]; |
423 | myABufferLen = aLength; |
424 | } |
425 | sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName, chEqual, chDoubleQuote, anIntValue, chDoubleQuote); |
426 | aLength = (Standard_Integer)strlen (myABuffer); |
427 | |
428 | |
429 | } |
430 | else // String attribute value |
431 | { |
432 | char* encStr; |
433 | const char* aValue = aValueStr.GetString(); |
434 | if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear) |
435 | { |
436 | encStr = (char *) aValue; |
437 | aLength = (Standard_Integer) (4 + strlen (aValue) + strlen (aName)); |
438 | } |
439 | else |
440 | { |
441 | encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True); |
442 | aLength += (Standard_Integer) (4 + strlen (aName)); |
443 | } |
444 | |
445 | if (aLength > myABufferLen) |
446 | { |
447 | if (myABuffer != NULL) |
448 | { |
449 | delete [] myABuffer; |
450 | } |
451 | |
452 | myABuffer = new char [aLength+1]; |
453 | myABufferLen = aLength; |
454 | } |
455 | |
456 | sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName, chEqual, chDoubleQuote, encStr, chDoubleQuote); |
457 | |
458 | if (encStr != aValue) |
459 | { |
460 | delete [] encStr; |
461 | } |
462 | } |
463 | |
464 | theOStream.write (myABuffer, aLength); |
7fd59977 |
465 | } |