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 : inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
38 : {
39 0 : while (begin != end)
40 0 : *out++ = *begin++;
41 : 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 0 : inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
48 : {
49 0 : while (begin != end)
50 : {
51 0 : if (*begin == noexpand)
52 : {
53 0 : *out++ = *begin; // No expansion, copy character
54 : }
55 : else
56 : {
57 0 : switch (*begin)
58 : {
59 0 : case Ch('<'):
60 0 : *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
61 0 : break;
62 0 : case Ch('>'):
63 0 : *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
64 0 : break;
65 0 : case Ch('\''):
66 0 : *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
67 0 : break;
68 0 : case Ch('"'):
69 0 : *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
70 0 : break;
71 0 : case Ch('&'):
72 0 : *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
73 0 : break;
74 : default:
75 0 : *out++ = *begin; // No expansion, copy character
76 : }
77 : }
78 0 : ++begin; // Step to next character
79 : }
80 0 : 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 0 : for (int i = 0; i < n; ++i)
88 0 : *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 0 : while (begin != end)
97 0 : if (*begin++ == ch)
98 : return true;
99 : return false;
100 : }
101 :
102 : ///////////////////////////////////////////////////////////////////////////
103 : // Internal printing operations
104 :
105 : // predeclaration
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 0 : inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
112 : {
113 0 : for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
114 0 : out = print_node(out, child, flags, indent);
115 0 : return out;
116 : }
117 :
118 : // Print attributes of the node
119 : template<class OutIt, class Ch>
120 0 : inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
121 : {
122 0 : 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 0 : *out = Ch(' '), ++out;
128 0 : out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
129 0 : *out = Ch('='), ++out;
130 : // Print attribute value using appropriate quote type
131 0 : 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 0 : *out = Ch('"'), ++out;
140 0 : out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
141 0 : *out = Ch('"'), ++out;
142 : }
143 : }
144 : }
145 0 : 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 : 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 : 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 0 : 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 0 : if (!(flags & print_no_indenting))
190 0 : out = fill_chars(out, indent, Ch('\t'));
191 0 : *out = Ch('<'), ++out;
192 0 : out = copy_chars(node->name(), node->name() + node->name_size(), out);
193 0 : out = print_attributes(out, node, flags);
194 :
195 : // If node is childless
196 0 : if (node->value_size() == 0 && !node->first_node())
197 : {
198 : // Print childless node tag ending
199 0 : *out = Ch('/'), ++out;
200 0 : *out = Ch('>'), ++out;
201 : }
202 : else
203 : {
204 : // Print normal node tag ending
205 0 : *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 0 : 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 0 : 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 0 : if (!(flags & print_no_indenting))
223 0 : *out = Ch('\n'), ++out;
224 0 : out = print_children(out, node, flags, indent + 1);
225 0 : if (!(flags & print_no_indenting))
226 0 : out = fill_chars(out, indent, Ch('\t'));
227 : }
228 :
229 : // Print node end
230 0 : *out = Ch('<'), ++out;
231 0 : *out = Ch('/'), ++out;
232 0 : out = copy_chars(node->name(), node->name() + node->name_size(), out);
233 0 : *out = Ch('>'), ++out;
234 : }
235 0 : 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 : 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 : 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 : 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 node
319 : template<class OutIt, class Ch>
320 0 : inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
321 : {
322 : // Print proper node type
323 0 : switch (node->type())
324 : {
325 :
326 : // Document
327 : case node_document:
328 0 : out = print_children(out, node, flags, indent);
329 0 : break;
330 :
331 : // Element
332 : case node_element:
333 0 : out = print_element_node(out, node, flags, indent);
334 0 : break;
335 :
336 : // Data
337 : case node_data:
338 0 : out = print_data_node(out, node, flags, indent);
339 0 : break;
340 :
341 : // CDATA
342 : case node_cdata:
343 0 : out = print_cdata_node(out, node, flags, indent);
344 0 : break;
345 :
346 : // Declaration
347 : case node_declaration:
348 0 : out = print_declaration_node(out, node, flags, indent);
349 0 : break;
350 :
351 : // Comment
352 : case node_comment:
353 0 : out = print_comment_node(out, node, flags, indent);
354 0 : break;
355 :
356 : // Doctype
357 : case node_doctype:
358 0 : out = print_doctype_node(out, node, flags, indent);
359 0 : break;
360 :
361 : // Pi
362 : case node_pi:
363 0 : out = print_pi_node(out, node, flags, indent);
364 0 : break;
365 :
366 : // Unknown
367 : default:
368 : assert(0);
369 : break;
370 : }
371 :
372 : // If indenting not disabled, add line break after node
373 0 : if (!(flags & print_no_indenting))
374 0 : *out = Ch('\n'), ++out;
375 :
376 : // Return modified iterator
377 0 : return out;
378 : }
379 : }
380 : //! \endcond
381 :
382 : ///////////////////////////////////////////////////////////////////////////
383 : // Printing
384 :
385 : //! Prints XML to given output iterator.
386 : //! \param out Output iterator to print to.
387 : //! \param node Node to be printed. Pass xml_document to print entire document.
388 : //! \param flags Flags controlling how XML is printed.
389 : //! \return Output iterator pointing to position immediately after last character of printed text.
390 : template<class OutIt, class Ch>
391 : inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
392 : {
393 0 : return internal::print_node(out, &node, flags, 0);
394 : }
395 :
396 : #ifndef RAPIDXML_NO_STREAMS
397 :
398 : //! Prints XML to given output stream.
399 : //! \param out Output stream to print to.
400 : //! \param node Node to be printed. Pass xml_document to print entire document.
401 : //! \param flags Flags controlling how XML is printed.
402 : //! \return Output stream.
403 : template<class Ch>
404 : inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
405 : {
406 0 : print(std::ostream_iterator<Ch>(out), node, flags);
407 : return out;
408 : }
409 :
410 : //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
411 : //! \param out Output stream to print to.
412 : //! \param node Node to be printed.
413 : //! \return Output stream.
414 : template<class Ch>
415 : inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
416 : {
417 : return print(out, node);
418 : }
419 :
420 : #endif
421 :
422 : }
423 :
424 : #endif
|