1 #ifndef RAPIDXML_PRINT_HPP_INCLUDED
2 #define RAPIDXML_PRINT_HPP_INCLUDED
3 
4 // Copyright (C) 2006, 2009 Marcin Kalicinski
5 // Version 1.13
6 // Revision $DateTime: 2009/05/13 01:46:17 $
7 //! \file rapidxml_print.hpp This file contains rapidxml printer implementation
8 
9 #include "rapidxml.hpp"
10 
11 // Only include streams if not disabled
12 #ifndef RAPIDXML_NO_STREAMS
13     #include <ostream>
14     #include <iterator>
15 #endif
16 
17 namespace Wt {
18 namespace rapidxml
19 {
20 
21     ///////////////////////////////////////////////////////////////////////
22     // Printing flags
23 
24     const int print_no_indenting = 0x1;   //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
25 
26     ///////////////////////////////////////////////////////////////////////
27     // Internal
28 
29     //! \cond internal
30     namespace internal
31     {
32 
33         ///////////////////////////////////////////////////////////////////////////
34         // Internal character operations
35 
36         // Copy characters from given range to given output iterator
37         template<class OutIt, class Ch>
copy_chars(const Ch * begin,const Ch * end,OutIt out)38         inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
39         {
40             while (begin != end)
41                 *out++ = *begin++;
42             return out;
43         }
44 
45         // Copy characters from given range to given output iterator and expand
46         // characters into references (&lt; &gt; &apos; &quot; &amp;)
47         template<class OutIt, class Ch>
copy_and_expand_chars(const Ch * begin,const Ch * end,Ch noexpand,OutIt out,bool quotesToo)48         inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out, bool quotesToo)
49         {
50             while (begin != end)
51             {
52                 if (*begin == noexpand)
53                 {
54                     *out++ = *begin;    // No expansion, copy character
55                 }
56                 else
57                 {
58                     switch (*begin)
59                     {
60                     case Ch('<'):
61                         *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
62                         break;
63                     case Ch('>'):
64                         *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
65                         break;
66                     case Ch('\''):
67 		        if (quotesToo) {
68 			  *out++ = Ch('&'); *out++ = Ch('#'); *out++ = Ch('3'); *out++ = Ch('9'); *out++ = Ch(';');
69 			} else
70 			  *out++ = *begin;
71                         break;
72                     case Ch('"'):
73 		        if (quotesToo) {
74 			  *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
75 			} else
76 			  *out++ = *begin;
77                         break;
78                     case Ch('&'):
79                         *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
80                         break;
81                     default:
82                         *out++ = *begin;    // No expansion, copy character
83                     }
84                 }
85                 ++begin;    // Step to next character
86             }
87             return out;
88         }
89 
90         // Fill given output iterator with repetitions of the same character
91         template<class OutIt, class Ch>
fill_chars(OutIt out,int n,Ch ch)92         inline OutIt fill_chars(OutIt out, int n, Ch ch)
93         {
94             for (int i = 0; i < n; ++i)
95                 *out++ = ch;
96             return out;
97         }
98 
99         // Find character
100         template<class Ch, Ch ch>
find_char(const Ch * begin,const Ch * end)101         inline bool find_char(const Ch *begin, const Ch *end)
102         {
103             while (begin != end)
104                 if (*begin++ == ch)
105                     return true;
106             return false;
107         }
108 
109         ///////////////////////////////////////////////////////////////////////////
110         // Internal printing operations
111 
112         template<class OutIt, class Ch>
113         OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
114 
115         template<class OutIt, class Ch>
116         OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
117 
118         template<class OutIt, class Ch>
119         OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
120 
121         template<class OutIt, class Ch>
122         OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
123 
124         template<class OutIt, class Ch>
125         OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
126 
127         template<class OutIt, class Ch>
128         OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
129 
130         template<class OutIt, class Ch>
131         OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
132 
133         template<class OutIt, class Ch>
134         OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
135 
136         // Print node
137         template<class OutIt, class Ch>
print_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)138         inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
139         {
140             // Print proper node type
141             switch (node->type())
142             {
143 
144             // Document
145             case node_document:
146                 out = print_children(out, node, flags, indent);
147                 break;
148 
149             // Element
150             case node_element:
151                 out = print_element_node(out, node, flags, indent);
152                 break;
153 
154             // Data
155             case node_data:
156                 out = print_data_node(out, node, flags, indent);
157                 break;
158 
159             // CDATA
160             case node_cdata:
161                 out = print_cdata_node(out, node, flags, indent);
162                 break;
163 
164             // Declaration
165             case node_declaration:
166                 out = print_declaration_node(out, node, flags, indent);
167                 break;
168 
169             // Comment
170             case node_comment:
171                 out = print_comment_node(out, node, flags, indent);
172                 break;
173 
174             // Doctype
175             case node_doctype:
176                 out = print_doctype_node(out, node, flags, indent);
177                 break;
178 
179             // Pi
180             case node_pi:
181                 out = print_pi_node(out, node, flags, indent);
182                 break;
183 
184                 // Unknown
185             default:
186                 assert(0);
187                 break;
188             }
189 
190             // If indenting not disabled, add line break after node
191             if (!(flags & print_no_indenting))
192                 *out = Ch('\n'), ++out;
193 
194             // Return modified iterator
195             return out;
196         }
197 
198         // Print children of the node
199         template<class OutIt, class Ch>
print_children(OutIt out,const xml_node<Ch> * node,int flags,int indent)200         inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
201         {
202             for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
203                 out = print_node(out, child, flags, indent);
204             return out;
205         }
206 
207         // Print attributes of the node
208         template<class OutIt, class Ch>
print_attributes(OutIt out,const xml_node<Ch> * node,int flags)209         inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
210         {
211             for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
212             {
213                 if (attribute->name() && attribute->value())
214                 {
215                     // Print attribute name
216                     *out = Ch(' '), ++out;
217                     out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
218                     *out = Ch('='), ++out;
219                     // Print attribute value using appropriate quote type
220                     if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
221                     {
222                         *out = Ch('\''), ++out;
223                         out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out, true);
224                         *out = Ch('\''), ++out;
225                     }
226                     else
227                     {
228                         *out = Ch('"'), ++out;
229                         out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out, true);
230                         *out = Ch('"'), ++out;
231                     }
232                 }
233             }
234             return out;
235         }
236 
237         // Print data node
238         template<class OutIt, class Ch>
print_data_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)239         inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
240         {
241             assert(node->type() == node_data);
242             if (!(flags & print_no_indenting))
243                 out = fill_chars(out, indent, Ch('\t'));
244             out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out, false);
245             return out;
246         }
247 
248         // Print data node
249         template<class OutIt, class Ch>
print_cdata_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)250         inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
251         {
252             assert(node->type() == node_cdata);
253             if (!(flags & print_no_indenting))
254                 out = fill_chars(out, indent, Ch('\t'));
255             *out = Ch('<'); ++out;
256             *out = Ch('!'); ++out;
257             *out = Ch('['); ++out;
258             *out = Ch('C'); ++out;
259             *out = Ch('D'); ++out;
260             *out = Ch('A'); ++out;
261             *out = Ch('T'); ++out;
262             *out = Ch('A'); ++out;
263             *out = Ch('['); ++out;
264             out = copy_chars(node->value(), node->value() + node->value_size(), out);
265             *out = Ch(']'); ++out;
266             *out = Ch(']'); ++out;
267             *out = Ch('>'); ++out;
268             return out;
269         }
270 
271         // Print element node
272         template<class OutIt, class Ch>
print_element_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)273         inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
274         {
275             assert(node->type() == node_element);
276 
277             // Print element name and attributes, if any
278             if (!(flags & print_no_indenting))
279                 out = fill_chars(out, indent, Ch('\t'));
280             *out = Ch('<'), ++out;
281             out = copy_chars(node->name(), node->name() + node->name_size(), out);
282             out = print_attributes(out, node, flags);
283 
284             // If node is childless
285             if (node->value_size() == 0 && !node->first_node())
286             {
287                 // Print childless node tag ending
288                 *out = Ch('/'), ++out;
289                 *out = Ch('>'), ++out;
290             }
291             else
292             {
293                 // Print normal node tag ending
294                 *out = Ch('>'), ++out;
295 
296                 // Test if node contains a single data node only (and no other nodes)
297                 xml_node<Ch> *child = node->first_node();
298                 if (!child)
299                 {
300                     // If node has no children, only print its value without indenting
301 		  out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out, false);
302                 }
303                 else if (child->next_sibling() == 0 && child->type() == node_data)
304                 {
305                     // If node has a sole data child, only print its value without indenting
306 		  out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out, false);
307                 }
308                 else
309                 {
310                     // Print all children with full indenting
311                     if (!(flags & print_no_indenting))
312                         *out = Ch('\n'), ++out;
313                     out = print_children(out, node, flags, indent + 1);
314                     if (!(flags & print_no_indenting))
315                         out = fill_chars(out, indent, Ch('\t'));
316                 }
317 
318                 // Print node end
319                 *out = Ch('<'), ++out;
320                 *out = Ch('/'), ++out;
321                 out = copy_chars(node->name(), node->name() + node->name_size(), out);
322                 *out = Ch('>'), ++out;
323             }
324             return out;
325         }
326 
327         // Print declaration node
328         template<class OutIt, class Ch>
print_declaration_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)329         inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
330         {
331             // Print declaration start
332             if (!(flags & print_no_indenting))
333                 out = fill_chars(out, indent, Ch('\t'));
334             *out = Ch('<'), ++out;
335             *out = Ch('?'), ++out;
336             *out = Ch('x'), ++out;
337             *out = Ch('m'), ++out;
338             *out = Ch('l'), ++out;
339 
340             // Print attributes
341             out = print_attributes(out, node, flags);
342 
343             // Print declaration end
344             *out = Ch('?'), ++out;
345             *out = Ch('>'), ++out;
346 
347             return out;
348         }
349 
350         // Print comment node
351         template<class OutIt, class Ch>
print_comment_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)352         inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
353         {
354             assert(node->type() == node_comment);
355             if (!(flags & print_no_indenting))
356                 out = fill_chars(out, indent, Ch('\t'));
357             *out = Ch('<'), ++out;
358             *out = Ch('!'), ++out;
359             *out = Ch('-'), ++out;
360             *out = Ch('-'), ++out;
361             out = copy_chars(node->value(), node->value() + node->value_size(), out);
362             *out = Ch('-'), ++out;
363             *out = Ch('-'), ++out;
364             *out = Ch('>'), ++out;
365             return out;
366         }
367 
368         // Print doctype node
369         template<class OutIt, class Ch>
print_doctype_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)370         inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
371         {
372             assert(node->type() == node_doctype);
373             if (!(flags & print_no_indenting))
374                 out = fill_chars(out, indent, Ch('\t'));
375             *out = Ch('<'), ++out;
376             *out = Ch('!'), ++out;
377             *out = Ch('D'), ++out;
378             *out = Ch('O'), ++out;
379             *out = Ch('C'), ++out;
380             *out = Ch('T'), ++out;
381             *out = Ch('Y'), ++out;
382             *out = Ch('P'), ++out;
383             *out = Ch('E'), ++out;
384             *out = Ch(' '), ++out;
385             out = copy_chars(node->value(), node->value() + node->value_size(), out);
386             *out = Ch('>'), ++out;
387             return out;
388         }
389 
390         // Print pi node
391         template<class OutIt, class Ch>
print_pi_node(OutIt out,const xml_node<Ch> * node,int flags,int indent)392         inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
393         {
394             assert(node->type() == node_pi);
395             if (!(flags & print_no_indenting))
396                 out = fill_chars(out, indent, Ch('\t'));
397             *out = Ch('<'), ++out;
398             *out = Ch('?'), ++out;
399             out = copy_chars(node->name(), node->name() + node->name_size(), out);
400             *out = Ch(' '), ++out;
401             out = copy_chars(node->value(), node->value() + node->value_size(), out);
402             *out = Ch('?'), ++out;
403             *out = Ch('>'), ++out;
404             return out;
405         }
406 
407     }
408     //! \endcond
409 
410     ///////////////////////////////////////////////////////////////////////////
411     // Printing
412 
413     //! Prints XML to given output iterator.
414     //! \param out Output iterator to print to.
415     //! \param node Node to be printed. Pass xml_document to print entire document.
416     //! \param flags Flags controlling how XML is printed.
417     //! \return Output iterator pointing to position immediately after last character of printed text.
418     template<class OutIt, class Ch>
print(OutIt out,const xml_node<Ch> & node,int flags=0)419     inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
420     {
421         return internal::print_node(out, &node, flags, 0);
422     }
423 
424 #ifndef RAPIDXML_NO_STREAMS
425 
426     //! Prints XML to given output stream.
427     //! \param out Output stream to print to.
428     //! \param node Node to be printed. Pass xml_document to print entire document.
429     //! \param flags Flags controlling how XML is printed.
430     //! \return Output stream.
431     template<class Ch>
print(std::basic_ostream<Ch> & out,const xml_node<Ch> & node,int flags=0)432     inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
433     {
434         print(std::ostream_iterator<Ch>(out), node, flags);
435         return out;
436     }
437 
438     //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
439     //! \param out Output stream to print to.
440     //! \param node Node to be printed.
441     //! \return Output stream.
442     template<class Ch>
operator <<(std::basic_ostream<Ch> & out,const xml_node<Ch> & node)443     inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
444     {
445         return print(out, node);
446     }
447 
448 #endif
449 
450 }
451 }
452 
453 #endif
454