Merge "Update snapshot history" into tizen
[platform/upstream/iotivity.git] / extlibs / rapidxml / rapidxml_print.hpp
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 =
24         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>
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>
48         inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
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                             *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s');
68                             *out++ = Ch(';');
69                             break;
70                         case Ch('"'):
71                             *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t');
72                             *out++ = Ch(';');
73                             break;
74                         case Ch('&'):
75                             *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
76                             break;
77                         default:
78                             *out++ = *begin;    // No expansion, copy character
79                     }
80                 }
81                 ++begin;    // Step to next character
82             }
83             return out;
84         }
85
86         // Fill given output iterator with repetitions of the same character
87         template<class OutIt, class Ch>
88         inline OutIt fill_chars(OutIt out, int n, Ch ch)
89         {
90             for (int i = 0; i < n; ++i)
91                 *out++ = ch;
92             return out;
93         }
94
95         // Find character
96         template<class Ch, Ch ch>
97         inline bool find_char(const Ch *begin, const Ch *end)
98         {
99             while (begin != end)
100                 if (*begin++ == ch)
101                     return true;
102             return false;
103         }
104
105         template<class OutIt, class Ch>
106         inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
107
108         // Print children of the node
109         template<class OutIt, class Ch>
110         inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
111         {
112             for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
113                 out = print_node(out, child, flags, indent);
114             return out;
115         }
116
117         // Print attributes of the node
118         template<class OutIt, class Ch>
119         inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
120         {
121             for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute;
122                  attribute = attribute->next_attribute())
123             {
124                 if (attribute->name() && attribute->value())
125                 {
126                     // Print attribute name
127                     *out = Ch(' '), ++out;
128                     out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
129                     *out = Ch('='), ++out;
130                     // Print attribute value using appropriate quote type
131                     if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
132                     {
133                         *out = Ch('\''), ++out;
134                         out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(),
135                                                     Ch('"'), out);
136                         *out = Ch('\''), ++out;
137                     }
138                     else
139                     {
140                         *out = Ch('"'), ++out;
141                         out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(),
142                                                     Ch('\''), out);
143                         *out = Ch('"'), ++out;
144                     }
145                 }
146             }
147             return out;
148         }
149
150         // Print data node
151         template<class OutIt, class Ch>
152         inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
153         {
154             assert(node->type() == node_data);
155             if (!(flags & print_no_indenting))
156                 out = fill_chars(out, indent, Ch('\t'));
157             out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
158             return out;
159         }
160
161         // Print data node
162         template<class OutIt, class Ch>
163         inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
164         {
165             assert(node->type() == node_cdata);
166             if (!(flags & print_no_indenting))
167                 out = fill_chars(out, indent, Ch('\t'));
168             *out = Ch('<'); ++out;
169             *out = Ch('!'); ++out;
170             *out = Ch('['); ++out;
171             *out = Ch('C'); ++out;
172             *out = Ch('D'); ++out;
173             *out = Ch('A'); ++out;
174             *out = Ch('T'); ++out;
175             *out = Ch('A'); ++out;
176             *out = Ch('['); ++out;
177             out = copy_chars(node->value(), node->value() + node->value_size(), out);
178             *out = Ch(']'); ++out;
179             *out = Ch(']'); ++out;
180             *out = Ch('>'); ++out;
181             return out;
182         }
183
184         // Print element node
185         template<class OutIt, class Ch>
186         inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
187         {
188             assert(node->type() == node_element);
189
190             // Print element name and attributes, if any
191             if (!(flags & print_no_indenting))
192                 out = fill_chars(out, indent, Ch('\t'));
193             *out = Ch('<'), ++out;
194             out = copy_chars(node->name(), node->name() + node->name_size(), out);
195             out = print_attributes(out, node, flags);
196
197             // If node is childless
198             if (node->value_size() == 0 && !node->first_node())
199             {
200                 // Print childless node tag ending
201                 *out = Ch('/'), ++out;
202                 *out = Ch('>'), ++out;
203             }
204             else
205             {
206                 // Print normal node tag ending
207                 *out = Ch('>'), ++out;
208
209                 // Test if node contains a single data node only (and no other nodes)
210                 xml_node<Ch> *child = node->first_node();
211                 if (!child)
212                 {
213                     // If node has no children, only print its value without indenting
214                     out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
215                 }
216                 else if (child->next_sibling() == 0 && child->type() == node_data)
217                 {
218                     // If node has a sole data child, only print its value without indenting
219                     out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
220                 }
221                 else
222                 {
223                     // Print all children with full indenting
224                     if (!(flags & print_no_indenting))
225                         *out = Ch('\n'), ++out;
226                     out = print_children(out, node, flags, indent + 1);
227                     if (!(flags & print_no_indenting))
228                         out = fill_chars(out, indent, Ch('\t'));
229                 }
230
231                 // Print node end
232                 *out = Ch('<'), ++out;
233                 *out = Ch('/'), ++out;
234                 out = copy_chars(node->name(), node->name() + node->name_size(), out);
235                 *out = Ch('>'), ++out;
236             }
237             return out;
238         }
239
240         // Print declaration node
241         template<class OutIt, class Ch>
242         inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
243         {
244             // Print declaration start
245             if (!(flags & print_no_indenting))
246                 out = fill_chars(out, indent, Ch('\t'));
247             *out = Ch('<'), ++out;
248             *out = Ch('?'), ++out;
249             *out = Ch('x'), ++out;
250             *out = Ch('m'), ++out;
251             *out = Ch('l'), ++out;
252
253             // Print attributes
254             out = print_attributes(out, node, flags);
255
256             // Print declaration end
257             *out = Ch('?'), ++out;
258             *out = Ch('>'), ++out;
259
260             return out;
261         }
262
263         // Print comment node
264         template<class OutIt, class Ch>
265         inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
266         {
267             assert(node->type() == node_comment);
268             if (!(flags & print_no_indenting))
269                 out = fill_chars(out, indent, Ch('\t'));
270             *out = Ch('<'), ++out;
271             *out = Ch('!'), ++out;
272             *out = Ch('-'), ++out;
273             *out = Ch('-'), ++out;
274             out = copy_chars(node->value(), node->value() + node->value_size(), out);
275             *out = Ch('-'), ++out;
276             *out = Ch('-'), ++out;
277             *out = Ch('>'), ++out;
278             return out;
279         }
280
281         // Print doctype node
282         template<class OutIt, class Ch>
283         inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
284         {
285             assert(node->type() == node_doctype);
286             if (!(flags & print_no_indenting))
287                 out = fill_chars(out, indent, Ch('\t'));
288             *out = Ch('<'), ++out;
289             *out = Ch('!'), ++out;
290             *out = Ch('D'), ++out;
291             *out = Ch('O'), ++out;
292             *out = Ch('C'), ++out;
293             *out = Ch('T'), ++out;
294             *out = Ch('Y'), ++out;
295             *out = Ch('P'), ++out;
296             *out = Ch('E'), ++out;
297             *out = Ch(' '), ++out;
298             out = copy_chars(node->value(), node->value() + node->value_size(), out);
299             *out = Ch('>'), ++out;
300             return out;
301         }
302
303         // Print pi node
304         template<class OutIt, class Ch>
305         inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
306         {
307             assert(node->type() == node_pi);
308             if (!(flags & print_no_indenting))
309                 out = fill_chars(out, indent, Ch('\t'));
310             *out = Ch('<'), ++out;
311             *out = Ch('?'), ++out;
312             out = copy_chars(node->name(), node->name() + node->name_size(), out);
313             *out = Ch(' '), ++out;
314             out = copy_chars(node->value(), node->value() + node->value_size(), out);
315             *out = Ch('?'), ++out;
316             *out = Ch('>'), ++out;
317             return out;
318         }
319         ///////////////////////////////////////////////////////////////////////////
320         // Internal printing operations
321
322         // Print node
323         template<class OutIt, class Ch>
324         inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
325         {
326             // Print proper node type
327             switch (node->type())
328             {
329
330                 // Document
331                 case node_document:
332                     out = print_children(out, node, flags, indent);
333                     break;
334
335                 // Element
336                 case node_element:
337                     out = print_element_node(out, node, flags, indent);
338                     break;
339
340                 // Data
341                 case node_data:
342                     out = print_data_node(out, node, flags, indent);
343                     break;
344
345                 // CDATA
346                 case node_cdata:
347                     out = print_cdata_node(out, node, flags, indent);
348                     break;
349
350                 // Declaration
351                 case node_declaration:
352                     out = print_declaration_node(out, node, flags, indent);
353                     break;
354
355                 // Comment
356                 case node_comment:
357                     out = print_comment_node(out, node, flags, indent);
358                     break;
359
360                 // Doctype
361                 case node_doctype:
362                     out = print_doctype_node(out, node, flags, indent);
363                     break;
364
365                 // Pi
366                 case node_pi:
367                     out = print_pi_node(out, node, flags, indent);
368                     break;
369
370                 // Unknown
371                 default:
372                     assert(0);
373                     break;
374             }
375
376             // If indenting not disabled, add line break after node
377             if (!(flags & print_no_indenting))
378                 *out = Ch('\n'), ++out;
379
380             // Return modified iterator
381             return out;
382         }
383     }
384     //! \endcond
385
386     ///////////////////////////////////////////////////////////////////////////
387     // Printing
388
389     //! Prints XML to given output iterator.
390     //! \param out Output iterator to print to.
391     //! \param node Node to be printed. Pass xml_document to print entire document.
392     //! \param flags Flags controlling how XML is printed.
393     //! \return Output iterator pointing to position immediately after last character of printed text.
394     template<class OutIt, class Ch>
395     inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
396     {
397         return internal::print_node(out, &node, flags, 0);
398     }
399
400 #ifndef RAPIDXML_NO_STREAMS
401
402     //! Prints XML to given output stream.
403     //! \param out Output stream to print to.
404     //! \param node Node to be printed. Pass xml_document to print entire document.
405     //! \param flags Flags controlling how XML is printed.
406     //! \return Output stream.
407     template<class Ch>
408     inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node,
409                                          int flags = 0)
410     {
411         print(std::ostream_iterator<Ch>(out), node, flags);
412         return out;
413     }
414
415     //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
416     //! \param out Output stream to print to.
417     //! \param node Node to be printed.
418     //! \return Output stream.
419     template<class Ch>
420     inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
421     {
422         return print(out, node);
423     }
424
425 #endif
426
427 }
428
429 #endif