rapidxml_print.hpp
Go to the documentation of this file.
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 $
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 
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  template<class OutIt, class Ch>
106  inline OutIt print_node(OutIt, const xml_node<Ch>*, int, int);
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; attribute = attribute->next_attribute())
122  {
123  if (attribute->name() && attribute->value())
124  {
125  // Print attribute name
126  *out = Ch(' '), ++out;
127  out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
128  *out = Ch('='), ++out;
129  // Print attribute value using appropriate quote type
130  if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
131  {
132  *out = Ch('\''), ++out;
133  out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
134  *out = Ch('\''), ++out;
135  }
136  else
137  {
138  *out = Ch('"'), ++out;
139  out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
140  *out = Ch('"'), ++out;
141  }
142  }
143  }
144  return out;
145  }
146 
147  // Print data node
148  template<class OutIt, class Ch>
149  inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
150  {
151  assert(node->type() == node_data);
152  if (!(flags & print_no_indenting))
153  out = fill_chars(out, indent, Ch('\t'));
154  out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
155  return out;
156  }
157 
158  // Print data node
159  template<class OutIt, class Ch>
160  inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
161  {
162  assert(node->type() == node_cdata);
163  if (!(flags & print_no_indenting))
164  out = fill_chars(out, indent, Ch('\t'));
165  *out = Ch('<'); ++out;
166  *out = Ch('!'); ++out;
167  *out = Ch('['); ++out;
168  *out = Ch('C'); ++out;
169  *out = Ch('D'); ++out;
170  *out = Ch('A'); ++out;
171  *out = Ch('T'); ++out;
172  *out = Ch('A'); ++out;
173  *out = Ch('['); ++out;
174  out = copy_chars(node->value(), node->value() + node->value_size(), out);
175  *out = Ch(']'); ++out;
176  *out = Ch(']'); ++out;
177  *out = Ch('>'); ++out;
178  return out;
179  }
180 
181  // Print element node
182  template<class OutIt, class Ch>
183  inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
184  {
185  assert(node->type() == node_element);
186 
187  // Print element name and attributes, if any
188  if (!(flags & print_no_indenting))
189  out = fill_chars(out, indent, Ch('\t'));
190  *out = Ch('<'), ++out;
191  out = copy_chars(node->name(), node->name() + node->name_size(), out);
192  out = print_attributes(out, node, flags);
193 
194  // If node is childless
195  if (node->value_size() == 0 && !node->first_node())
196  {
197  // Print childless node tag ending
198  *out = Ch('/'), ++out;
199  *out = Ch('>'), ++out;
200  }
201  else
202  {
203  // Print normal node tag ending
204  *out = Ch('>'), ++out;
205 
206  // Test if node contains a single data node only (and no other nodes)
207  xml_node<Ch> *child = node->first_node();
208  if (!child)
209  {
210  // If node has no children, only print its value without indenting
211  out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
212  }
213  else if (child->next_sibling() == 0 && child->type() == node_data)
214  {
215  // If node has a sole data child, only print its value without indenting
216  out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
217  }
218  else
219  {
220  // Print all children with full indenting
221  if (!(flags & print_no_indenting))
222  *out = Ch('\n'), ++out;
223  out = print_children(out, node, flags, indent + 1);
224  if (!(flags & print_no_indenting))
225  out = fill_chars(out, indent, Ch('\t'));
226  }
227 
228  // Print node end
229  *out = Ch('<'), ++out;
230  *out = Ch('/'), ++out;
231  out = copy_chars(node->name(), node->name() + node->name_size(), out);
232  *out = Ch('>'), ++out;
233  }
234  return out;
235  }
236 
237  // Print declaration node
238  template<class OutIt, class Ch>
239  inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
240  {
241  // Print declaration start
242  if (!(flags & print_no_indenting))
243  out = fill_chars(out, indent, Ch('\t'));
244  *out = Ch('<'), ++out;
245  *out = Ch('?'), ++out;
246  *out = Ch('x'), ++out;
247  *out = Ch('m'), ++out;
248  *out = Ch('l'), ++out;
249 
250  // Print attributes
251  out = print_attributes(out, node, flags);
252 
253  // Print declaration end
254  *out = Ch('?'), ++out;
255  *out = Ch('>'), ++out;
256 
257  return out;
258  }
259 
260  // Print comment node
261  template<class OutIt, class Ch>
262  inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
263  {
264  assert(node->type() == node_comment);
265  if (!(flags & print_no_indenting))
266  out = fill_chars(out, indent, Ch('\t'));
267  *out = Ch('<'), ++out;
268  *out = Ch('!'), ++out;
269  *out = Ch('-'), ++out;
270  *out = Ch('-'), ++out;
271  out = copy_chars(node->value(), node->value() + node->value_size(), out);
272  *out = Ch('-'), ++out;
273  *out = Ch('-'), ++out;
274  *out = Ch('>'), ++out;
275  return out;
276  }
277 
278  // Print doctype node
279  template<class OutIt, class Ch>
280  inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
281  {
282  assert(node->type() == node_doctype);
283  if (!(flags & print_no_indenting))
284  out = fill_chars(out, indent, Ch('\t'));
285  *out = Ch('<'), ++out;
286  *out = Ch('!'), ++out;
287  *out = Ch('D'), ++out;
288  *out = Ch('O'), ++out;
289  *out = Ch('C'), ++out;
290  *out = Ch('T'), ++out;
291  *out = Ch('Y'), ++out;
292  *out = Ch('P'), ++out;
293  *out = Ch('E'), ++out;
294  *out = Ch(' '), ++out;
295  out = copy_chars(node->value(), node->value() + node->value_size(), out);
296  *out = Ch('>'), ++out;
297  return out;
298  }
299 
300  // Print pi node
301  template<class OutIt, class Ch>
302  inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
303  {
304  assert(node->type() == node_pi);
305  if (!(flags & print_no_indenting))
306  out = fill_chars(out, indent, Ch('\t'));
307  *out = Ch('<'), ++out;
308  *out = Ch('?'), ++out;
309  out = copy_chars(node->name(), node->name() + node->name_size(), out);
310  *out = Ch(' '), ++out;
311  out = copy_chars(node->value(), node->value() + node->value_size(), out);
312  *out = Ch('?'), ++out;
313  *out = Ch('>'), ++out;
314  return out;
315  }
316 
317  // Print node
318  template<class OutIt, class Ch>
319  inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
320  {
321  // Print proper node type
322  switch (node->type())
323  {
324 
325  // Document
326  case node_document:
327  out = print_children(out, node, flags, indent);
328  break;
329 
330  // Element
331  case node_element:
332  out = print_element_node(out, node, flags, indent);
333  break;
334 
335  // Data
336  case node_data:
337  out = print_data_node(out, node, flags, indent);
338  break;
339 
340  // CDATA
341  case node_cdata:
342  out = print_cdata_node(out, node, flags, indent);
343  break;
344 
345  // Declaration
346  case node_declaration:
347  out = print_declaration_node(out, node, flags, indent);
348  break;
349 
350  // Comment
351  case node_comment:
352  out = print_comment_node(out, node, flags, indent);
353  break;
354 
355  // Doctype
356  case node_doctype:
357  out = print_doctype_node(out, node, flags, indent);
358  break;
359 
360  // Pi
361  case node_pi:
362  out = print_pi_node(out, node, flags, indent);
363  break;
364 
365  // Unknown
366  default:
367  assert(0);
368  break;
369  }
370 
371  // If indenting not disabled, add line break after node
372  if (!(flags & print_no_indenting))
373  *out = Ch('\n'), ++out;
374 
375  // Return modified iterator
376  return out;
377  }
378 
379  }
380 
382 
384  // Printing
385 
391  template<class OutIt, class Ch>
392  inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
393  {
394  return internal::print_node(out, &node, flags, 0);
395  }
396 
397 #ifndef RAPIDXML_NO_STREAMS
398 
404  template<class Ch>
405  inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
406  {
407  print(std::ostream_iterator<Ch>(out), node, flags);
408  return out;
409  }
410 
415  template<class Ch>
416  inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
417  {
418  return print(out, node);
419  }
420 
421 #endif
422 
423 }
424 
425 #endif
This file contains rapidxml parser and DOM implementation.
A PI node. Name contains target. Value contains instructions.
Definition: rapidxml.hpp:152
A CDATA node. Name is empty. Value contains data text.
Definition: rapidxml.hpp:148
A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
Definition: rapidxml.hpp:151
Ch * value() const
Definition: rapidxml.hpp:692
std::size_t name_size() const
Definition: rapidxml.hpp:681
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
OutIt print(OutIt out, const xml_node< Ch > &node, int flags=0)
Definition: rapidxml_print.hpp:392
A document node. Name and value are empty.
Definition: rapidxml.hpp:145
node_type type() const
Definition: rapidxml.hpp:913
A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalon...
Definition: rapidxml.hpp:150
Ch * name() const
Definition: rapidxml.hpp:673
const int print_no_indenting
Printer flag instructing the printer to suppress indenting of XML. See print() function.
Definition: rapidxml_print.hpp:23
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1025
Definition: rapidxml.hpp:138
xml_node< Ch > * next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1004
An element node. Name contains element name. Value contains text of first data node.
Definition: rapidxml.hpp:146
Definition: rapidxml.hpp:137
Definition: rapidxml.hpp:57
A comment node. Name is empty. Value contains comment text.
Definition: rapidxml.hpp:149
A data node. Name is empty. Value contains data text.
Definition: rapidxml.hpp:147
std::size_t value_size() const
Definition: rapidxml.hpp:700