NDDEM
rapidxml_print.hpp
Go to the documentation of this file.
1 #ifndef CEREAL_RAPIDXML_PRINT_HPP_INCLUDED
2 #define CEREAL_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 
8 #include "rapidxml.hpp"
9 
10 // Only include streams if not disabled
11 #ifndef CEREAL_RAPIDXML_NO_STREAMS
12  #include <ostream>
13  #include <iterator>
14 #endif
15 
16 namespace cereal {
17 namespace rapidxml
18 {
19 
21  // Printing flags
22 
23  const int print_no_indenting = 0x1;
24 
26  // Internal
27 
29  namespace internal
30  {
31 
33  // Internal character operations
34 
35  // Copy characters from given range to given output iterator
36  template<class OutIt, class Ch>
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>
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>
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>
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 
103  // Internal printing operations
104 
105  // Print node
106  template<class OutIt, class Ch>
107  inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
108 
109  // Print children of the node
110  template<class OutIt, class Ch>
111  inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
112  {
113  for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
114  out = print_node(out, child, flags, indent);
115  return out;
116  }
117 
118  // Print attributes of the node
119  template<class OutIt, class Ch>
120  inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int /*flags*/)
121  {
122  for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; 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(), Ch('"'), out);
135  *out = Ch('\''), ++out;
136  }
137  else
138  {
139  *out = Ch('"'), ++out;
140  out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
141  *out = Ch('"'), ++out;
142  }
143  }
144  }
145  return out;
146  }
147 
148  // Print data node
149  template<class OutIt, class Ch>
150  inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
151  {
152  assert(node->type() == node_data);
153  if (!(flags & print_no_indenting))
154  out = fill_chars(out, indent, Ch('\t'));
155  out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
156  return out;
157  }
158 
159  // Print data node
160  template<class OutIt, class Ch>
161  inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
162  {
163  assert(node->type() == node_cdata);
164  if (!(flags & print_no_indenting))
165  out = fill_chars(out, indent, Ch('\t'));
166  *out = Ch('<'); ++out;
167  *out = Ch('!'); ++out;
168  *out = Ch('['); ++out;
169  *out = Ch('C'); ++out;
170  *out = Ch('D'); ++out;
171  *out = Ch('A'); ++out;
172  *out = Ch('T'); ++out;
173  *out = Ch('A'); ++out;
174  *out = Ch('['); ++out;
175  out = copy_chars(node->value(), node->value() + node->value_size(), out);
176  *out = Ch(']'); ++out;
177  *out = Ch(']'); ++out;
178  *out = Ch('>'); ++out;
179  return out;
180  }
181 
182  // Print element node
183  template<class OutIt, class Ch>
184  inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
185  {
186  assert(node->type() == node_element);
187 
188  // Print element name and attributes, if any
189  if (!(flags & print_no_indenting))
190  out = fill_chars(out, indent, Ch('\t'));
191  *out = Ch('<'), ++out;
192  out = copy_chars(node->name(), node->name() + node->name_size(), out);
193  out = print_attributes(out, node, flags);
194 
195  // If node is childless
196  if (node->value_size() == 0 && !node->first_node())
197  {
198  // Print childless node tag ending
199  *out = Ch('/'), ++out;
200  *out = Ch('>'), ++out;
201  }
202  else
203  {
204  // Print normal node tag ending
205  *out = Ch('>'), ++out;
206 
207  // Test if node contains a single data node only (and no other nodes)
208  xml_node<Ch> *child = node->first_node();
209  if (!child)
210  {
211  // If node has no children, only print its value without indenting
212  out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
213  }
214  else if (child->next_sibling() == 0 && child->type() == node_data)
215  {
216  // If node has a sole data child, only print its value without indenting
217  out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
218  }
219  else
220  {
221  // Print all children with full indenting
222  if (!(flags & print_no_indenting))
223  *out = Ch('\n'), ++out;
224  out = print_children(out, node, flags, indent + 1);
225  if (!(flags & print_no_indenting))
226  out = fill_chars(out, indent, Ch('\t'));
227  }
228 
229  // Print node end
230  *out = Ch('<'), ++out;
231  *out = Ch('/'), ++out;
232  out = copy_chars(node->name(), node->name() + node->name_size(), out);
233  *out = Ch('>'), ++out;
234  }
235  return out;
236  }
237 
238  // Print declaration node
239  template<class OutIt, class Ch>
240  inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
241  {
242  // Print declaration start
243  if (!(flags & print_no_indenting))
244  out = fill_chars(out, indent, Ch('\t'));
245  *out = Ch('<'), ++out;
246  *out = Ch('?'), ++out;
247  *out = Ch('x'), ++out;
248  *out = Ch('m'), ++out;
249  *out = Ch('l'), ++out;
250 
251  // Print attributes
252  out = print_attributes(out, node, flags);
253 
254  // Print declaration end
255  *out = Ch('?'), ++out;
256  *out = Ch('>'), ++out;
257 
258  return out;
259  }
260 
261  // Print comment node
262  template<class OutIt, class Ch>
263  inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
264  {
265  assert(node->type() == node_comment);
266  if (!(flags & print_no_indenting))
267  out = fill_chars(out, indent, Ch('\t'));
268  *out = Ch('<'), ++out;
269  *out = Ch('!'), ++out;
270  *out = Ch('-'), ++out;
271  *out = Ch('-'), ++out;
272  out = copy_chars(node->value(), node->value() + node->value_size(), out);
273  *out = Ch('-'), ++out;
274  *out = Ch('-'), ++out;
275  *out = Ch('>'), ++out;
276  return out;
277  }
278 
279  // Print doctype node
280  template<class OutIt, class Ch>
281  inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
282  {
283  assert(node->type() == node_doctype);
284  if (!(flags & print_no_indenting))
285  out = fill_chars(out, indent, Ch('\t'));
286  *out = Ch('<'), ++out;
287  *out = Ch('!'), ++out;
288  *out = Ch('D'), ++out;
289  *out = Ch('O'), ++out;
290  *out = Ch('C'), ++out;
291  *out = Ch('T'), ++out;
292  *out = Ch('Y'), ++out;
293  *out = Ch('P'), ++out;
294  *out = Ch('E'), ++out;
295  *out = Ch(' '), ++out;
296  out = copy_chars(node->value(), node->value() + node->value_size(), out);
297  *out = Ch('>'), ++out;
298  return out;
299  }
300 
301  // Print pi node
302  template<class OutIt, class Ch>
303  inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
304  {
305  assert(node->type() == node_pi);
306  if (!(flags & print_no_indenting))
307  out = fill_chars(out, indent, Ch('\t'));
308  *out = Ch('<'), ++out;
309  *out = Ch('?'), ++out;
310  out = copy_chars(node->name(), node->name() + node->name_size(), out);
311  *out = Ch(' '), ++out;
312  out = copy_chars(node->value(), node->value() + node->value_size(), out);
313  *out = Ch('?'), ++out;
314  *out = Ch('>'), ++out;
315  return out;
316  }
317 
318  // Print node
319  template<class OutIt, class Ch>
320  inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
321  {
322  // Print proper node type
323  switch (node->type())
324  {
325 
326  // Document
327  case node_document:
328  out = print_children(out, node, flags, indent);
329  break;
330 
331  // Element
332  case node_element:
333  out = print_element_node(out, node, flags, indent);
334  break;
335 
336  // Data
337  case node_data:
338  out = print_data_node(out, node, flags, indent);
339  break;
340 
341  // CDATA
342  case node_cdata:
343  out = print_cdata_node(out, node, flags, indent);
344  break;
345 
346  // Declaration
347  case node_declaration:
348  out = print_declaration_node(out, node, flags, indent);
349  break;
350 
351  // Comment
352  case node_comment:
353  out = print_comment_node(out, node, flags, indent);
354  break;
355 
356  // Doctype
357  case node_doctype:
358  out = print_doctype_node(out, node, flags, indent);
359  break;
360 
361  // Pi
362  case node_pi:
363  out = print_pi_node(out, node, flags, indent);
364  break;
365 
366 #ifndef __GNUC__
367  // Unknown
368  default:
369  assert(0);
370  break;
371 #endif
372  }
373 
374  // If indenting not disabled, add line break after node
375  if (!(flags & print_no_indenting))
376  *out = Ch('\n'), ++out;
377 
378  // Return modified iterator
379  return out;
380  }
381 
382  }
384 
386  // Printing
387 
393  template<class OutIt, class Ch>
394  inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
395  {
396  return internal::print_node(out, &node, flags, 0);
397  }
398 
399 #ifndef CEREAL_RAPIDXML_NO_STREAMS
400 
406  template<class Ch>
407  inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
408  {
409  print(std::ostream_iterator<Ch>(out), node, flags);
410  return out;
411  }
412 
417  template<class Ch>
418  inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
419  {
420  return print(out, node);
421  }
422 
423 #endif
424 
425 }
426 } // namespace cereal
427 
428 #endif
xml_attribute< Ch > * next_attribute(const Ch *name_=0, std::size_t name_size_=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:869
std::size_t name_size() const
Definition: rapidxml.hpp:694
std::size_t value_size() const
Definition: rapidxml.hpp:713
Ch * name() const
Definition: rapidxml.hpp:686
Ch * value() const
Definition: rapidxml.hpp:705
xml_node< Ch > * next_sibling(const Ch *name_=0, std::size_t name_size_=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1017
node_type type() const
Definition: rapidxml.hpp:926
xml_node< Ch > * first_node(const Ch *name_=0, std::size_t name_size_=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:949
xml_attribute< Ch > * first_attribute(const Ch *name_=0, std::size_t name_size_=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1038
const int print_no_indenting
Printer flag instructing the printer to suppress indenting of XML. See print() function.
Definition: rapidxml_print.hpp:23
@ node_doctype
A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
Definition: rapidxml.hpp:156
@ node_document
A document node. Name and value are empty.
Definition: rapidxml.hpp:150
@ node_comment
A comment node. Name is empty. Value contains comment text.
Definition: rapidxml.hpp:154
@ node_declaration
A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalon...
Definition: rapidxml.hpp:155
@ node_data
A data node. Name is empty. Value contains data text.
Definition: rapidxml.hpp:152
@ node_cdata
A CDATA node. Name is empty. Value contains data text.
Definition: rapidxml.hpp:153
@ node_pi
A PI node. Name contains target. Value contains instructions.
Definition: rapidxml.hpp:157
@ node_element
An element node. Name contains element name. Value contains text of first data node.
Definition: rapidxml.hpp:151
std::basic_ostream< Ch > & operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node)
Definition: rapidxml_print.hpp:418
OutIt print(OutIt out, const xml_node< Ch > &node, int flags=0)
Definition: rapidxml_print.hpp:394
in certain simple scenarios. They should probably not be used if maximizing performance is the main o...
Definition: access.hpp:42
Definition: document.h:416
PUGI_IMPL_FN const char_t * find_char(const char_t *s, char_t c)
Definition: pugixml.cpp:8122