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 template<class OutIt, class Ch>
103 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
105 // Print children of the node
106 template<class OutIt, class Ch>
107 inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
109 for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
110 out = print_node(out, child, flags, indent);
114 // Print attributes of the node
115 template<class OutIt, class Ch>
116 inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
118 for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
120 if (attribute->name() && attribute->value())
122 // Print attribute name
123 *out = Ch(' '), ++out;
124 out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
125 *out = Ch('='), ++out;
126 // Print attribute value using appropriate quote type
127 if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
129 *out = Ch('\''), ++out;
130 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
131 *out = Ch('\''), ++out;
135 *out = Ch('"'), ++out;
136 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
137 *out = Ch('"'), ++out;
145 template<class OutIt, class Ch>
146 inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
148 assert(node->type() == node_data);
149 if (!(flags & print_no_indenting))
150 out = fill_chars(out, indent, Ch('\t'));
151 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
156 template<class OutIt, class Ch>
157 inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
159 assert(node->type() == node_cdata);
160 if (!(flags & print_no_indenting))
161 out = fill_chars(out, indent, Ch('\t'));
162 *out = Ch('<'); ++out;
163 *out = Ch('!'); ++out;
164 *out = Ch('['); ++out;
165 *out = Ch('C'); ++out;
166 *out = Ch('D'); ++out;
167 *out = Ch('A'); ++out;
168 *out = Ch('T'); ++out;
169 *out = Ch('A'); ++out;
170 *out = Ch('['); ++out;
171 out = copy_chars(node->value(), node->value() + node->value_size(), out);
172 *out = Ch(']'); ++out;
173 *out = Ch(']'); ++out;
174 *out = Ch('>'); ++out;
178 // Print element node
179 template<class OutIt, class Ch>
180 inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
182 assert(node->type() == node_element);
184 // Print element name and attributes, if any
185 if (!(flags & print_no_indenting))
186 out = fill_chars(out, indent, Ch('\t'));
187 *out = Ch('<'), ++out;
188 out = copy_chars(node->name(), node->name() + node->name_size(), out);
189 out = print_attributes(out, node, flags);
191 // If node is childless
192 if (node->value_size() == 0 && !node->first_node())
194 // Print childless node tag ending
195 *out = Ch('/'), ++out;
196 *out = Ch('>'), ++out;
200 // Print normal node tag ending
201 *out = Ch('>'), ++out;
203 // Test if node contains a single data node only (and no other nodes)
204 xml_node<Ch> *child = node->first_node();
207 // If node has no children, only print its value without indenting
208 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
210 else if (child->next_sibling() == 0 && child->type() == node_data)
212 // If node has a sole data child, only print its value without indenting
213 out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
217 // Print all children with full indenting
218 if (!(flags & print_no_indenting))
219 *out = Ch('\n'), ++out;
220 out = print_children(out, node, flags, indent + 1);
221 if (!(flags & print_no_indenting))
222 out = fill_chars(out, indent, Ch('\t'));
226 *out = Ch('<'), ++out;
227 *out = Ch('/'), ++out;
228 out = copy_chars(node->name(), node->name() + node->name_size(), out);
229 *out = Ch('>'), ++out;
234 // Print declaration node
235 template<class OutIt, class Ch>
236 inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
238 // Print declaration start
239 if (!(flags & print_no_indenting))
240 out = fill_chars(out, indent, Ch('\t'));
241 *out = Ch('<'), ++out;
242 *out = Ch('?'), ++out;
243 *out = Ch('x'), ++out;
244 *out = Ch('m'), ++out;
245 *out = Ch('l'), ++out;
248 out = print_attributes(out, node, flags);
250 // Print declaration end
251 *out = Ch('?'), ++out;
252 *out = Ch('>'), ++out;
257 // Print comment node
258 template<class OutIt, class Ch>
259 inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
261 assert(node->type() == node_comment);
262 if (!(flags & print_no_indenting))
263 out = fill_chars(out, indent, Ch('\t'));
264 *out = Ch('<'), ++out;
265 *out = Ch('!'), ++out;
266 *out = Ch('-'), ++out;
267 *out = Ch('-'), ++out;
268 out = copy_chars(node->value(), node->value() + node->value_size(), out);
269 *out = Ch('-'), ++out;
270 *out = Ch('-'), ++out;
271 *out = Ch('>'), ++out;
275 // Print doctype node
276 template<class OutIt, class Ch>
277 inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
279 assert(node->type() == node_doctype);
280 if (!(flags & print_no_indenting))
281 out = fill_chars(out, indent, Ch('\t'));
282 *out = Ch('<'), ++out;
283 *out = Ch('!'), ++out;
284 *out = Ch('D'), ++out;
285 *out = Ch('O'), ++out;
286 *out = Ch('C'), ++out;
287 *out = Ch('T'), ++out;
288 *out = Ch('Y'), ++out;
289 *out = Ch('P'), ++out;
290 *out = Ch('E'), ++out;
291 *out = Ch(' '), ++out;
292 out = copy_chars(node->value(), node->value() + node->value_size(), out);
293 *out = Ch('>'), ++out;
298 template<class OutIt, class Ch>
299 inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
301 assert(node->type() == node_pi);
302 if (!(flags & print_no_indenting))
303 out = fill_chars(out, indent, Ch('\t'));
304 *out = Ch('<'), ++out;
305 *out = Ch('?'), ++out;
306 out = copy_chars(node->name(), node->name() + node->name_size(), out);
307 *out = Ch(' '), ++out;
308 out = copy_chars(node->value(), node->value() + node->value_size(), out);
309 *out = Ch('?'), ++out;
310 *out = Ch('>'), ++out;
313 ///////////////////////////////////////////////////////////////////////////
314 // Internal printing operations
317 template<class OutIt, class Ch>
318 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
320 // Print proper node type
321 switch (node->type())
326 out = print_children(out, node, flags, indent);
331 out = print_element_node(out, node, flags, indent);
336 out = print_data_node(out, node, flags, indent);
341 out = print_cdata_node(out, node, flags, indent);
345 case node_declaration:
346 out = print_declaration_node(out, node, flags, indent);
351 out = print_comment_node(out, node, flags, indent);
356 out = print_doctype_node(out, node, flags, indent);
361 out = print_pi_node(out, node, flags, indent);
370 // If indenting not disabled, add line break after node
371 if (!(flags & print_no_indenting))
372 *out = Ch('\n'), ++out;
374 // Return modified iterator
380 ///////////////////////////////////////////////////////////////////////////
383 //! Prints XML to given output iterator.
384 //! \param out Output iterator to print to.
385 //! \param node Node to be printed. Pass xml_document to print entire document.
386 //! \param flags Flags controlling how XML is printed.
387 //! \return Output iterator pointing to position immediately after last character of printed text.
388 template<class OutIt, class Ch>
389 inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
391 return internal::print_node(out, &node, flags, 0);
394 #ifndef RAPIDXML_NO_STREAMS
396 //! Prints XML to given output stream.
397 //! \param out Output stream to print to.
398 //! \param node Node to be printed. Pass xml_document to print entire document.
399 //! \param flags Flags controlling how XML is printed.
400 //! \return Output stream.
402 inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
404 print(std::ostream_iterator<Ch>(out), node, flags);
408 //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
409 //! \param out Output stream to print to.
410 //! \param node Node to be printed.
411 //! \return Output stream.
413 inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
415 return print(out, node);