1 #ifndef RAPIDXML_PRINT_HPP_INCLUDED
2 #define RAPIDXML_PRINT_HPP_INCLUDED
4 // Copyright (C) 2006, 2009 Marcin Kalicinski
6 // Revision $DateTime: 2009/05/13 01:46:17 $
7 //! \file rapidxml_print.hpp This file contains rapidxml printer implementation
9 #include "rapidxml.hpp"
11 // Only include streams if not disabled
12 #ifndef RAPIDXML_NO_STREAMS
20 ///////////////////////////////////////////////////////////////////////
23 const int print_no_indenting
= 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
25 ///////////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////////////
33 // Internal character operations
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
)
44 // Copy characters from given range to given output iterator and expand
45 // characters into references (< > ' " &)
46 template<class OutIt
, class Ch
>
47 inline OutIt
copy_and_expand_chars(const Ch
*begin
, const Ch
*end
, Ch noexpand
, OutIt out
)
51 if (*begin
== noexpand
)
53 *out
++ = *begin
; // No expansion, copy character
60 *out
++ = Ch('&'); *out
++ = Ch('l'); *out
++ = Ch('t'); *out
++ = Ch(';');
63 *out
++ = Ch('&'); *out
++ = Ch('g'); *out
++ = Ch('t'); *out
++ = Ch(';');
66 *out
++ = Ch('&'); *out
++ = Ch('a'); *out
++ = Ch('p'); *out
++ = Ch('o'); *out
++ = Ch('s'); *out
++ = Ch(';');
69 *out
++ = Ch('&'); *out
++ = Ch('q'); *out
++ = Ch('u'); *out
++ = Ch('o'); *out
++ = Ch('t'); *out
++ = Ch(';');
72 *out
++ = Ch('&'); *out
++ = Ch('a'); *out
++ = Ch('m'); *out
++ = Ch('p'); *out
++ = Ch(';');
75 *out
++ = *begin
; // No expansion, copy character
78 ++begin
; // Step to next character
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
)
87 for (int i
= 0; i
< n
; ++i
)
93 template<class Ch
, Ch ch
>
94 inline bool find_char(const Ch
*begin
, const Ch
*end
)
102 ///////////////////////////////////////////////////////////////////////////
103 // Internal printing operations
106 template<class OutIt
, class Ch
>
107 inline OutIt
print_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
109 // Print proper node type
110 switch (node
->type())
115 out
= print_children(out
, node
, flags
, indent
);
120 out
= print_element_node(out
, node
, flags
, indent
);
125 out
= print_data_node(out
, node
, flags
, indent
);
130 out
= print_cdata_node(out
, node
, flags
, indent
);
134 case node_declaration
:
135 out
= print_declaration_node(out
, node
, flags
, indent
);
140 out
= print_comment_node(out
, node
, flags
, indent
);
145 out
= print_doctype_node(out
, node
, flags
, indent
);
150 out
= print_pi_node(out
, node
, flags
, indent
);
159 // If indenting not disabled, add line break after node
160 if (!(flags
& print_no_indenting
))
161 *out
= Ch('\n'), ++out
;
163 // Return modified iterator
167 // Print children of the node
168 template<class OutIt
, class Ch
>
169 inline OutIt
print_children(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
171 for (xml_node
<Ch
> *child
= node
->first_node(); child
; child
= child
->next_sibling())
172 out
= print_node(out
, child
, flags
, indent
);
176 // Print attributes of the node
177 template<class OutIt
, class Ch
>
178 inline OutIt
print_attributes(OutIt out
, const xml_node
<Ch
> *node
, int flags
)
180 for (xml_attribute
<Ch
> *attribute
= node
->first_attribute(); attribute
; attribute
= attribute
->next_attribute())
182 if (attribute
->name() && attribute
->value())
184 // Print attribute name
185 *out
= Ch(' '), ++out
;
186 out
= copy_chars(attribute
->name(), attribute
->name() + attribute
->name_size(), out
);
187 *out
= Ch('='), ++out
;
188 // Print attribute value using appropriate quote type
189 if (find_char
<Ch
, Ch('"')>(attribute
->value(), attribute
->value() + attribute
->value_size()))
191 *out
= Ch('\''), ++out
;
192 out
= copy_and_expand_chars(attribute
->value(), attribute
->value() + attribute
->value_size(), Ch('"'), out
);
193 *out
= Ch('\''), ++out
;
197 *out
= Ch('"'), ++out
;
198 out
= copy_and_expand_chars(attribute
->value(), attribute
->value() + attribute
->value_size(), Ch('\''), out
);
199 *out
= Ch('"'), ++out
;
207 template<class OutIt
, class Ch
>
208 inline OutIt
print_data_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
210 assert(node
->type() == node_data
);
211 if (!(flags
& print_no_indenting
))
212 out
= fill_chars(out
, indent
, Ch('\t'));
213 out
= copy_and_expand_chars(node
->value(), node
->value() + node
->value_size(), Ch(0), out
);
218 template<class OutIt
, class Ch
>
219 inline OutIt
print_cdata_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
221 assert(node
->type() == node_cdata
);
222 if (!(flags
& print_no_indenting
))
223 out
= fill_chars(out
, indent
, Ch('\t'));
224 *out
= Ch('<'); ++out
;
225 *out
= Ch('!'); ++out
;
226 *out
= Ch('['); ++out
;
227 *out
= Ch('C'); ++out
;
228 *out
= Ch('D'); ++out
;
229 *out
= Ch('A'); ++out
;
230 *out
= Ch('T'); ++out
;
231 *out
= Ch('A'); ++out
;
232 *out
= Ch('['); ++out
;
233 out
= copy_chars(node
->value(), node
->value() + node
->value_size(), out
);
234 *out
= Ch(']'); ++out
;
235 *out
= Ch(']'); ++out
;
236 *out
= Ch('>'); ++out
;
240 // Print element node
241 template<class OutIt
, class Ch
>
242 inline OutIt
print_element_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
244 assert(node
->type() == node_element
);
246 // Print element name and attributes, if any
247 if (!(flags
& print_no_indenting
))
248 out
= fill_chars(out
, indent
, Ch('\t'));
249 *out
= Ch('<'), ++out
;
250 out
= copy_chars(node
->name(), node
->name() + node
->name_size(), out
);
251 out
= print_attributes(out
, node
, flags
);
253 // If node is childless
254 if (node
->value_size() == 0 && !node
->first_node())
256 // Print childless node tag ending
257 *out
= Ch('/'), ++out
;
258 *out
= Ch('>'), ++out
;
262 // Print normal node tag ending
263 *out
= Ch('>'), ++out
;
265 // Test if node contains a single data node only (and no other nodes)
266 xml_node
<Ch
> *child
= node
->first_node();
269 // If node has no children, only print its value without indenting
270 out
= copy_and_expand_chars(node
->value(), node
->value() + node
->value_size(), Ch(0), out
);
272 else if (child
->next_sibling() == 0 && child
->type() == node_data
)
274 // If node has a sole data child, only print its value without indenting
275 out
= copy_and_expand_chars(child
->value(), child
->value() + child
->value_size(), Ch(0), out
);
279 // Print all children with full indenting
280 if (!(flags
& print_no_indenting
))
281 *out
= Ch('\n'), ++out
;
282 out
= print_children(out
, node
, flags
, indent
+ 1);
283 if (!(flags
& print_no_indenting
))
284 out
= fill_chars(out
, indent
, Ch('\t'));
288 *out
= Ch('<'), ++out
;
289 *out
= Ch('/'), ++out
;
290 out
= copy_chars(node
->name(), node
->name() + node
->name_size(), out
);
291 *out
= Ch('>'), ++out
;
296 // Print declaration node
297 template<class OutIt
, class Ch
>
298 inline OutIt
print_declaration_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
300 // Print declaration start
301 if (!(flags
& print_no_indenting
))
302 out
= fill_chars(out
, indent
, Ch('\t'));
303 *out
= Ch('<'), ++out
;
304 *out
= Ch('?'), ++out
;
305 *out
= Ch('x'), ++out
;
306 *out
= Ch('m'), ++out
;
307 *out
= Ch('l'), ++out
;
310 out
= print_attributes(out
, node
, flags
);
312 // Print declaration end
313 *out
= Ch('?'), ++out
;
314 *out
= Ch('>'), ++out
;
319 // Print comment node
320 template<class OutIt
, class Ch
>
321 inline OutIt
print_comment_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
323 assert(node
->type() == node_comment
);
324 if (!(flags
& print_no_indenting
))
325 out
= fill_chars(out
, indent
, Ch('\t'));
326 *out
= Ch('<'), ++out
;
327 *out
= Ch('!'), ++out
;
328 *out
= Ch('-'), ++out
;
329 *out
= Ch('-'), ++out
;
330 out
= copy_chars(node
->value(), node
->value() + node
->value_size(), out
);
331 *out
= Ch('-'), ++out
;
332 *out
= Ch('-'), ++out
;
333 *out
= Ch('>'), ++out
;
337 // Print doctype node
338 template<class OutIt
, class Ch
>
339 inline OutIt
print_doctype_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
341 assert(node
->type() == node_doctype
);
342 if (!(flags
& print_no_indenting
))
343 out
= fill_chars(out
, indent
, Ch('\t'));
344 *out
= Ch('<'), ++out
;
345 *out
= Ch('!'), ++out
;
346 *out
= Ch('D'), ++out
;
347 *out
= Ch('O'), ++out
;
348 *out
= Ch('C'), ++out
;
349 *out
= Ch('T'), ++out
;
350 *out
= Ch('Y'), ++out
;
351 *out
= Ch('P'), ++out
;
352 *out
= Ch('E'), ++out
;
353 *out
= Ch(' '), ++out
;
354 out
= copy_chars(node
->value(), node
->value() + node
->value_size(), out
);
355 *out
= Ch('>'), ++out
;
360 template<class OutIt
, class Ch
>
361 inline OutIt
print_pi_node(OutIt out
, const xml_node
<Ch
> *node
, int flags
, int indent
)
363 assert(node
->type() == node_pi
);
364 if (!(flags
& print_no_indenting
))
365 out
= fill_chars(out
, indent
, Ch('\t'));
366 *out
= Ch('<'), ++out
;
367 *out
= Ch('?'), ++out
;
368 out
= copy_chars(node
->name(), node
->name() + node
->name_size(), out
);
369 *out
= Ch(' '), ++out
;
370 out
= copy_chars(node
->value(), node
->value() + node
->value_size(), out
);
371 *out
= Ch('?'), ++out
;
372 *out
= Ch('>'), ++out
;
379 ///////////////////////////////////////////////////////////////////////////
382 //! Prints XML to given output iterator.
383 //! \param out Output iterator to print to.
384 //! \param node Node to be printed. Pass xml_document to print entire document.
385 //! \param flags Flags controlling how XML is printed.
386 //! \return Output iterator pointing to position immediately after last character of printed text.
387 template<class OutIt
, class Ch
>
388 inline OutIt
print(OutIt out
, const xml_node
<Ch
> &node
, int flags
= 0)
390 return internal::print_node(out
, &node
, flags
, 0);
393 #ifndef RAPIDXML_NO_STREAMS
395 //! Prints XML to given output stream.
396 //! \param out Output stream to print to.
397 //! \param node Node to be printed. Pass xml_document to print entire document.
398 //! \param flags Flags controlling how XML is printed.
399 //! \return Output stream.
401 inline std::basic_ostream
<Ch
> &print(std::basic_ostream
<Ch
> &out
, const xml_node
<Ch
> &node
, int flags
= 0)
403 print(std::ostream_iterator
<Ch
>(out
), node
, flags
);
407 //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
408 //! \param out Output stream to print to.
409 //! \param node Node to be printed.
410 //! \return Output stream.
412 inline std::basic_ostream
<Ch
> &operator <<(std::basic_ostream
<Ch
> &out
, const xml_node
<Ch
> &node
)
414 return print(out
, node
);