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