Line data Source code
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 = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
24 :
25 : ///////////////////////////////////////////////////////////////////////
26 : // Internal
27 :
28 : //! \cond internal
29 : namespace internal
30 : {
31 :
32 : ///////////////////////////////////////////////////////////////////////////
33 : // Internal character operations
34 :
35 : // Copy characters from given range to given output iterator
36 : template<class OutIt, class Ch>
37 154438 : inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
38 : {
39 1061770 : while (begin != end)
40 907328 : *out++ = *begin++;
41 154438 : return out;
42 : }
43 :
44 : // Copy characters from given range to given output iterator and expand
45 : // characters into references (< > ' " &)
46 : template<class OutIt, class Ch>
47 135130 : inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
48 : {
49 1426100 : while (begin != end)
50 : {
51 1290970 : if (*begin == noexpand)
52 : {
53 0 : *out++ = *begin; // No expansion, copy character
54 : }
55 : else
56 : {
57 1290970 : switch (*begin)
58 : {
59 0 : case Ch('<'):
60 0 : *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
61 : break;
62 0 : case Ch('>'):
63 0 : *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
64 : break;
65 0 : case Ch('\''):
66 0 : *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
67 : break;
68 0 : case Ch('"'):
69 0 : *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
70 : break;
71 0 : case Ch('&'):
72 0 : *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
73 : break;
74 : default:
75 1290970 : *out++ = *begin; // No expansion, copy character
76 : }
77 : }
78 1290970 : ++begin; // Step to next character
79 : }
80 135130 : 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 38610 : for (int i = 0; i < n; ++i)
88 38610 : *out++ = ch;
89 19308 : return out;
90 : }
91 :
92 : // Find character
93 : template<class Ch, Ch ch>
94 135130 : inline bool find_char(const Ch *begin, const Ch *end)
95 : {
96 1426100 : while (begin != end)
97 1290970 : if (*begin++ == ch)
98 : return true;
99 : return false;
100 : }
101 :
102 : ///////////////////////////////////////////////////////////////////////////
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 3 : inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
112 : {
113 19309 : for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
114 19306 : out = print_node(out, child, flags, indent);
115 3 : return out;
116 : }
117 :
118 : // Print attributes of the node
119 : template<class OutIt, class Ch>
120 19306 : inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
121 : {
122 154436 : for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
123 : {
124 135130 : if (attribute->name() && attribute->value())
125 : {
126 : // Print attribute name
127 135130 : *out = Ch(' '), ++out;
128 270260 : out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
129 135130 : *out = Ch('='), ++out;
130 : // Print attribute value using appropriate quote type
131 405390 : if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
132 : {
133 0 : *out = Ch('\''), ++out;
134 0 : out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
135 0 : *out = Ch('\''), ++out;
136 : }
137 : else
138 : {
139 135130 : *out = Ch('"'), ++out;
140 270260 : out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
141 135130 : *out = Ch('"'), ++out;
142 : }
143 : }
144 : }
145 19306 : return out;
146 : }
147 :
148 : // Print data node
149 : template<class OutIt, class Ch>
150 0 : inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
151 : {
152 0 : assert(node->type() == node_data);
153 0 : if (!(flags & print_no_indenting))
154 0 : out = fill_chars(out, indent, Ch('\t'));
155 0 : out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
156 0 : return out;
157 : }
158 :
159 : // Print data node
160 : template<class OutIt, class Ch>
161 0 : inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
162 : {
163 0 : assert(node->type() == node_cdata);
164 0 : if (!(flags & print_no_indenting))
165 0 : out = fill_chars(out, indent, Ch('\t'));
166 0 : *out = Ch('<'); ++out;
167 0 : *out = Ch('!'); ++out;
168 0 : *out = Ch('['); ++out;
169 0 : *out = Ch('C'); ++out;
170 0 : *out = Ch('D'); ++out;
171 0 : *out = Ch('A'); ++out;
172 0 : *out = Ch('T'); ++out;
173 0 : *out = Ch('A'); ++out;
174 0 : *out = Ch('['); ++out;
175 0 : out = copy_chars(node->value(), node->value() + node->value_size(), out);
176 0 : *out = Ch(']'); ++out;
177 0 : *out = Ch(']'); ++out;
178 0 : *out = Ch('>'); ++out;
179 0 : return out;
180 : }
181 :
182 : // Print element node
183 : template<class OutIt, class Ch>
184 19306 : inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
185 : {
186 19306 : assert(node->type() == node_element);
187 :
188 : // Print element name and attributes, if any
189 19306 : if (!(flags & print_no_indenting))
190 57915 : out = fill_chars(out, indent, Ch('\t'));
191 19306 : *out = Ch('<'), ++out;
192 38612 : out = copy_chars(node->name(), node->name() + node->name_size(), out);
193 19306 : out = print_attributes(out, node, flags);
194 :
195 : // If node is childless
196 19306 : if (node->value_size() == 0 && !node->first_node())
197 : {
198 : // Print childless node tag ending
199 19304 : *out = Ch('/'), ++out;
200 19304 : *out = Ch('>'), ++out;
201 : }
202 : else
203 : {
204 : // Print normal node tag ending
205 2 : *out = Ch('>'), ++out;
206 :
207 : // Test if node contains a single data node only (and no other nodes)
208 2 : xml_node<Ch> *child = node->first_node();
209 2 : if (!child)
210 : {
211 : // If node has no children, only print its value without indenting
212 0 : out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
213 : }
214 2 : 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 0 : 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 2 : if (!(flags & print_no_indenting))
223 2 : *out = Ch('\n'), ++out;
224 2 : out = print_children(out, node, flags, indent + 1);
225 2 : if (!(flags & print_no_indenting))
226 3 : out = fill_chars(out, indent, Ch('\t'));
227 : }
228 :
229 : // Print node end
230 2 : *out = Ch('<'), ++out;
231 2 : *out = Ch('/'), ++out;
232 4 : out = copy_chars(node->name(), node->name() + node->name_size(), out);
233 2 : *out = Ch('>'), ++out;
234 : }
235 19306 : return out;
236 : }
237 :
238 : // Print declaration node
239 : template<class OutIt, class Ch>
240 0 : inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
241 : {
242 : // Print declaration start
243 0 : if (!(flags & print_no_indenting))
244 0 : out = fill_chars(out, indent, Ch('\t'));
245 0 : *out = Ch('<'), ++out;
246 0 : *out = Ch('?'), ++out;
247 0 : *out = Ch('x'), ++out;
248 0 : *out = Ch('m'), ++out;
249 0 : *out = Ch('l'), ++out;
250 :
251 : // Print attributes
252 0 : out = print_attributes(out, node, flags);
253 :
254 : // Print declaration end
255 0 : *out = Ch('?'), ++out;
256 0 : *out = Ch('>'), ++out;
257 :
258 0 : return out;
259 : }
260 :
261 : // Print comment node
262 : template<class OutIt, class Ch>
263 0 : inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
264 : {
265 0 : assert(node->type() == node_comment);
266 0 : if (!(flags & print_no_indenting))
267 0 : out = fill_chars(out, indent, Ch('\t'));
268 0 : *out = Ch('<'), ++out;
269 0 : *out = Ch('!'), ++out;
270 0 : *out = Ch('-'), ++out;
271 0 : *out = Ch('-'), ++out;
272 0 : out = copy_chars(node->value(), node->value() + node->value_size(), out);
273 0 : *out = Ch('-'), ++out;
274 0 : *out = Ch('-'), ++out;
275 0 : *out = Ch('>'), ++out;
276 0 : return out;
277 : }
278 :
279 : // Print doctype node
280 : template<class OutIt, class Ch>
281 0 : inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
282 : {
283 0 : assert(node->type() == node_doctype);
284 0 : if (!(flags & print_no_indenting))
285 0 : out = fill_chars(out, indent, Ch('\t'));
286 0 : *out = Ch('<'), ++out;
287 0 : *out = Ch('!'), ++out;
288 0 : *out = Ch('D'), ++out;
289 0 : *out = Ch('O'), ++out;
290 0 : *out = Ch('C'), ++out;
291 0 : *out = Ch('T'), ++out;
292 0 : *out = Ch('Y'), ++out;
293 0 : *out = Ch('P'), ++out;
294 0 : *out = Ch('E'), ++out;
295 0 : *out = Ch(' '), ++out;
296 0 : out = copy_chars(node->value(), node->value() + node->value_size(), out);
297 0 : *out = Ch('>'), ++out;
298 0 : return out;
299 : }
300 :
301 : // Print pi node
302 : template<class OutIt, class Ch>
303 0 : inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
304 : {
305 0 : assert(node->type() == node_pi);
306 0 : if (!(flags & print_no_indenting))
307 0 : out = fill_chars(out, indent, Ch('\t'));
308 0 : *out = Ch('<'), ++out;
309 0 : *out = Ch('?'), ++out;
310 0 : out = copy_chars(node->name(), node->name() + node->name_size(), out);
311 0 : *out = Ch(' '), ++out;
312 0 : out = copy_chars(node->value(), node->value() + node->value_size(), out);
313 0 : *out = Ch('?'), ++out;
314 0 : *out = Ch('>'), ++out;
315 0 : return out;
316 : }
317 :
318 : // Print literal node
319 : template<class OutIt, class Ch>
320 0 : inline OutIt print_literal_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
321 : {
322 0 : assert(node->type() == node_literal);
323 0 : if (!(flags & print_no_indenting))
324 0 : out = fill_chars(out, indent, Ch('\t'));
325 0 : out = copy_chars(node->value(), node->value() + node->value_size(), out);
326 0 : return out;
327 : }
328 :
329 : // Print node
330 : // Print node
331 : template<class OutIt, class Ch>
332 19307 : inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
333 : {
334 : // Print proper node type
335 19307 : switch (node->type())
336 : {
337 :
338 : // Document
339 1 : case node_document:
340 1 : out = print_children(out, node, flags, indent);
341 1 : break;
342 :
343 : // Element
344 19306 : case node_element:
345 19306 : out = print_element_node(out, node, flags, indent);
346 19306 : break;
347 :
348 : // Data
349 0 : case node_data:
350 0 : out = print_data_node(out, node, flags, indent);
351 0 : break;
352 :
353 : // CDATA
354 0 : case node_cdata:
355 0 : out = print_cdata_node(out, node, flags, indent);
356 0 : break;
357 :
358 : // Declaration
359 0 : case node_declaration:
360 0 : out = print_declaration_node(out, node, flags, indent);
361 0 : break;
362 :
363 : // Comment
364 0 : case node_comment:
365 0 : out = print_comment_node(out, node, flags, indent);
366 0 : break;
367 :
368 : // Doctype
369 0 : case node_doctype:
370 0 : out = print_doctype_node(out, node, flags, indent);
371 0 : break;
372 :
373 : // Pi
374 0 : case node_pi:
375 0 : out = print_pi_node(out, node, flags, indent);
376 0 : break;
377 :
378 0 : case node_literal:
379 0 : out = print_literal_node(out, node, flags, indent);
380 0 : break;
381 :
382 : // Unknown
383 0 : default:
384 0 : assert(0);
385 : break;
386 : }
387 :
388 : // If indenting not disabled, add line break after node
389 19307 : if (!(flags & print_no_indenting))
390 19307 : *out = Ch('\n'), ++out;
391 :
392 : // Return modified iterator
393 19307 : return out;
394 : }
395 :
396 : }
397 : //! \endcond
398 :
399 : ///////////////////////////////////////////////////////////////////////////
400 : // Printing
401 :
402 : //! Prints XML to given output iterator.
403 : //! \param out Output iterator 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 iterator pointing to position immediately after last character of printed text.
407 : template<class OutIt, class Ch>
408 1 : inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
409 : {
410 1 : return internal::print_node(out, &node, flags, 0);
411 : }
412 :
413 : #ifndef RAPIDXML_NO_STREAMS
414 :
415 : //! Prints XML to given output stream.
416 : //! \param out Output stream to print to.
417 : //! \param node Node to be printed. Pass xml_document to print entire document.
418 : //! \param flags Flags controlling how XML is printed.
419 : //! \return Output stream.
420 : template<class Ch>
421 1 : inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
422 : {
423 1 : print(std::ostream_iterator<Ch>(out), node, flags);
424 : return out;
425 : }
426 :
427 : //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
428 : //! \param out Output stream to print to.
429 : //! \param node Node to be printed.
430 : //! \return Output stream.
431 : template<class Ch>
432 1 : inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
433 : {
434 1 : return print(out, node);
435 : }
436 :
437 : #endif
438 :
439 : }
440 :
441 : #endif
|