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 $
8 #include "rapidxml.hpp"
10 // Only include streams if not disabled
11 #ifndef RAPIDXML_NO_STREAMS
19 ///////////////////////////////////////////////////////////////////////
22 const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
24 ///////////////////////////////////////////////////////////////////////
31 ///////////////////////////////////////////////////////////////////////////
32 // Internal character operations
34 // Copy characters from given range to given output iterator
35 template<class OutIt, class Ch>
36 inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
43 // Copy characters from given range to given output iterator and expand
44 // characters into references (< > ' " &)
45 template<class OutIt, class Ch>
46 inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
50 if (*begin == noexpand)
52 *out++ = *begin; // No expansion, copy character
59 *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
62 *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
65 *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
68 *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
71 *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
74 *out++ = *begin; // No expansion, copy character
77 ++begin; // Step to next character
82 // Fill given output iterator with repetitions of the same character
83 template<class OutIt, class Ch>
84 inline OutIt fill_chars(OutIt out, int n, Ch ch)
86 for (int i = 0; i < n; ++i)
92 template<class Ch, Ch ch>
93 inline bool find_char(const Ch *begin, const Ch *end)
101 ///////////////////////////////////////////////////////////////////////////
102 // Internal printing operations
105 template<class OutIt, class Ch>
106 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
108 // Print children of the node
109 template<class OutIt, class Ch>
110 inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
112 for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
113 out = print_node(out, child, flags, indent);
117 // Print attributes of the node
118 template<class OutIt, class Ch>
119 inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int /*flags*/)
121 for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
123 if (attribute->name() && attribute->value())
125 // Print attribute name
126 *out = Ch(' '), ++out;
127 out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
128 *out = Ch('='), ++out;
129 // Print attribute value using appropriate quote type
130 if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
132 *out = Ch('\''), ++out;
133 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
134 *out = Ch('\''), ++out;
138 *out = Ch('"'), ++out;
139 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
140 *out = Ch('"'), ++out;
148 template<class OutIt, class Ch>
149 inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
151 assert(node->type() == node_data);
152 if (!(flags & print_no_indenting))
153 out = fill_chars(out, indent, Ch('\t'));
154 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
159 template<class OutIt, class Ch>
160 inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
162 assert(node->type() == node_cdata);
163 if (!(flags & print_no_indenting))
164 out = fill_chars(out, indent, Ch('\t'));
165 *out = Ch('<'); ++out;
166 *out = Ch('!'); ++out;
167 *out = Ch('['); ++out;
168 *out = Ch('C'); ++out;
169 *out = Ch('D'); ++out;
170 *out = Ch('A'); ++out;
171 *out = Ch('T'); ++out;
172 *out = Ch('A'); ++out;
173 *out = Ch('['); ++out;
174 out = copy_chars(node->value(), node->value() + node->value_size(), out);
175 *out = Ch(']'); ++out;
176 *out = Ch(']'); ++out;
177 *out = Ch('>'); ++out;
181 // Print element node
182 template<class OutIt, class Ch>
183 inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
185 assert(node->type() == node_element);
187 // Print element name and attributes, if any
188 if (!(flags & print_no_indenting))
189 out = fill_chars(out, indent, Ch('\t'));
190 *out = Ch('<'), ++out;
191 out = copy_chars(node->name(), node->name() + node->name_size(), out);
192 out = print_attributes(out, node, flags);
194 // If node is childless
195 if (node->value_size() == 0 && !node->first_node())
197 // Print childless node tag ending
198 *out = Ch('/'), ++out;
199 *out = Ch('>'), ++out;
203 // Print normal node tag ending
204 *out = Ch('>'), ++out;
206 // Test if node contains a single data node only (and no other nodes)
207 xml_node<Ch> *child = node->first_node();
210 // If node has no children, only print its value without indenting
211 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
213 else if (child->next_sibling() == 0 && child->type() == node_data)
215 // If node has a sole data child, only print its value without indenting
216 out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
220 // Print all children with full indenting
221 if (!(flags & print_no_indenting))
222 *out = Ch('\n'), ++out;
223 out = print_children(out, node, flags, indent + 1);
224 if (!(flags & print_no_indenting))
225 out = fill_chars(out, indent, Ch('\t'));
229 *out = Ch('<'), ++out;
230 *out = Ch('/'), ++out;
231 out = copy_chars(node->name(), node->name() + node->name_size(), out);
232 *out = Ch('>'), ++out;
237 // Print declaration node
238 template<class OutIt, class Ch>
239 inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
241 // Print declaration start
242 if (!(flags & print_no_indenting))
243 out = fill_chars(out, indent, Ch('\t'));
244 *out = Ch('<'), ++out;
245 *out = Ch('?'), ++out;
246 *out = Ch('x'), ++out;
247 *out = Ch('m'), ++out;
248 *out = Ch('l'), ++out;
251 out = print_attributes(out, node, flags);
253 // Print declaration end
254 *out = Ch('?'), ++out;
255 *out = Ch('>'), ++out;
260 // Print comment node
261 template<class OutIt, class Ch>
262 inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
264 assert(node->type() == node_comment);
265 if (!(flags & print_no_indenting))
266 out = fill_chars(out, indent, Ch('\t'));
267 *out = Ch('<'), ++out;
268 *out = Ch('!'), ++out;
269 *out = Ch('-'), ++out;
270 *out = Ch('-'), ++out;
271 out = copy_chars(node->value(), node->value() + node->value_size(), out);
272 *out = Ch('-'), ++out;
273 *out = Ch('-'), ++out;
274 *out = Ch('>'), ++out;
278 // Print doctype node
279 template<class OutIt, class Ch>
280 inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
282 assert(node->type() == node_doctype);
283 if (!(flags & print_no_indenting))
284 out = fill_chars(out, indent, Ch('\t'));
285 *out = Ch('<'), ++out;
286 *out = Ch('!'), ++out;
287 *out = Ch('D'), ++out;
288 *out = Ch('O'), ++out;
289 *out = Ch('C'), ++out;
290 *out = Ch('T'), ++out;
291 *out = Ch('Y'), ++out;
292 *out = Ch('P'), ++out;
293 *out = Ch('E'), ++out;
294 *out = Ch(' '), ++out;
295 out = copy_chars(node->value(), node->value() + node->value_size(), out);
296 *out = Ch('>'), ++out;
301 template<class OutIt, class Ch>
302 inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
304 assert(node->type() == node_pi);
305 if (!(flags & print_no_indenting))
306 out = fill_chars(out, indent, Ch('\t'));
307 *out = Ch('<'), ++out;
308 *out = Ch('?'), ++out;
309 out = copy_chars(node->name(), node->name() + node->name_size(), out);
310 *out = Ch(' '), ++out;
311 out = copy_chars(node->value(), node->value() + node->value_size(), out);
312 *out = Ch('?'), ++out;
313 *out = Ch('>'), ++out;
318 template<class OutIt, class Ch>
319 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
321 // Print proper node type
322 switch (node->type())
327 out = print_children(out, node, flags, indent);
332 out = print_element_node(out, node, flags, indent);
337 out = print_data_node(out, node, flags, indent);
342 out = print_cdata_node(out, node, flags, indent);
346 case node_declaration:
347 out = print_declaration_node(out, node, flags, indent);
352 out = print_comment_node(out, node, flags, indent);
357 out = print_doctype_node(out, node, flags, indent);
362 out = print_pi_node(out, node, flags, indent);
371 // If indenting not disabled, add line break after node
372 if (!(flags & print_no_indenting))
373 *out = Ch('\n'), ++out;
375 // Return modified iterator
382 ///////////////////////////////////////////////////////////////////////////
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)
393 return internal::print_node(out, &node, flags, 0);
396 #ifndef RAPIDXML_NO_STREAMS
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.
404 inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
406 print(std::ostream_iterator<Ch>(out), node, flags);
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.
415 inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
417 return print(out, node);