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