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