| #ifndef RAPIDXML_PRINT_HPP_INCLUDED | |
| #define RAPIDXML_PRINT_HPP_INCLUDED | |
| // Copyright (C) 2006, 2009 Marcin Kalicinski | |
| // Version 1.13 | |
| // Revision $DateTime: 2009/05/13 01:46:17 $ | |
| //! \file rapidxml_print.hpp This file contains rapidxml printer implementation | |
| #include "rapidxml.hh" | |
| // Only include streams if not disabled | |
| #ifndef RAPIDXML_NO_STREAMS | |
| #include <ostream> | |
| #include <iterator> | |
| #endif | |
| namespace rapidxml | |
| { | |
| /////////////////////////////////////////////////////////////////////// | |
| // Printing flags | |
| const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. | |
| /////////////////////////////////////////////////////////////////////// | |
| // Internal | |
| //! \cond internal | |
| namespace internal | |
| { | |
| /////////////////////////////////////////////////////////////////////////// | |
| // Internal character operations | |
| // Copy characters from given range to given output iterator | |
| template<class OutIt, class Ch> | |
| inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) | |
| { | |
| while (begin != end) | |
| *out++ = *begin++; | |
| return out; | |
| } | |
| // Copy characters from given range to given output iterator and expand | |
| // characters into references (< > ' " &) | |
| template<class OutIt, class Ch> | |
| inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) | |
| { | |
| while (begin != end) | |
| { | |
| if (*begin == noexpand) | |
| { | |
| *out++ = *begin; // No expansion, copy character | |
| } | |
| else | |
| { | |
| switch (*begin) | |
| { | |
| case Ch('<'): | |
| *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); | |
| break; | |
| case Ch('>'): | |
| *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); | |
| break; | |
| case Ch('\''): | |
| *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); | |
| break; | |
| case Ch('"'): | |
| *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); | |
| break; | |
| case Ch('&'): | |
| *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); | |
| break; | |
| default: | |
| *out++ = *begin; // No expansion, copy character | |
| } | |
| } | |
| ++begin; // Step to next character | |
| } | |
| return out; | |
| } | |
| // Fill given output iterator with repetitions of the same character | |
| template<class OutIt, class Ch> | |
| inline OutIt fill_chars(OutIt out, int n, Ch ch) | |
| { | |
| for (int i = 0; i < n; ++i) | |
| *out++ = ch; | |
| return out; | |
| } | |
| // Find character | |
| template<class Ch, Ch ch> | |
| inline bool find_char(const Ch *begin, const Ch *end) | |
| { | |
| while (begin != end) | |
| if (*begin++ == ch) | |
| return true; | |
| return false; | |
| } | |
| // artf390602 - EPTF CLL Rapid xml is not compatible with gcc 4.7 or newer { | |
| template<class OutIt, class Ch> | |
| inline OutIt print_children(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, | |
| int flags); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| template<class OutIt, class Ch> | |
| inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, | |
| int flags, int indent); | |
| // } artf390602 - EPTF CLL Rapid xml is not compatible with gcc 4.7 or newer | |
| /////////////////////////////////////////////////////////////////////////// | |
| // Internal printing operations | |
| // Print node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| // Print proper node type | |
| switch (node->type()) | |
| { | |
| // Document | |
| case node_document: | |
| out = print_children(out, node, flags, indent); | |
| break; | |
| // Element | |
| case node_element: | |
| out = print_element_node(out, node, flags, indent); | |
| break; | |
| // Data | |
| case node_data: | |
| out = print_data_node(out, node, flags, indent); | |
| break; | |
| // CDATA | |
| case node_cdata: | |
| out = print_cdata_node(out, node, flags, indent); | |
| break; | |
| // Declaration | |
| case node_declaration: | |
| out = print_declaration_node(out, node, flags, indent); | |
| break; | |
| // Comment | |
| case node_comment: | |
| out = print_comment_node(out, node, flags, indent); | |
| break; | |
| // Doctype | |
| case node_doctype: | |
| out = print_doctype_node(out, node, flags, indent); | |
| break; | |
| // Pi | |
| case node_pi: | |
| out = print_pi_node(out, node, flags, indent); | |
| break; | |
| // Unknown | |
| default: | |
| assert(0); | |
| break; | |
| } | |
| // If indenting not disabled, add line break after node | |
| if (!(flags & print_no_indenting)) | |
| *out = Ch('\n'), ++out; | |
| // Return modified iterator | |
| return out; | |
| } | |
| // Print children of the node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling()) | |
| out = print_node(out, child, flags, indent); | |
| return out; | |
| } | |
| // Print attributes of the node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags) | |
| { | |
| for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) | |
| { | |
| if (attribute->name() && attribute->value()) | |
| { | |
| // Print attribute name | |
| *out = Ch(' '), ++out; | |
| out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); | |
| *out = Ch('='), ++out; | |
| // Print attribute value using appropriate quote type | |
| if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size())) | |
| { | |
| *out = Ch('\''), ++out; | |
| out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); | |
| *out = Ch('\''), ++out; | |
| } | |
| else | |
| { | |
| *out = Ch('"'), ++out; | |
| out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); | |
| *out = Ch('"'), ++out; | |
| } | |
| } | |
| } | |
| return out; | |
| } | |
| // Print data node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| assert(node->type() == node_data); | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); | |
| return out; | |
| } | |
| // Print data node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| assert(node->type() == node_cdata); | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| *out = Ch('<'); ++out; | |
| *out = Ch('!'); ++out; | |
| *out = Ch('['); ++out; | |
| *out = Ch('C'); ++out; | |
| *out = Ch('D'); ++out; | |
| *out = Ch('A'); ++out; | |
| *out = Ch('T'); ++out; | |
| *out = Ch('A'); ++out; | |
| *out = Ch('['); ++out; | |
| out = copy_chars(node->value(), node->value() + node->value_size(), out); | |
| *out = Ch(']'); ++out; | |
| *out = Ch(']'); ++out; | |
| *out = Ch('>'); ++out; | |
| return out; | |
| } | |
| // Print element node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| assert(node->type() == node_element); | |
| // Print element name and attributes, if any | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| *out = Ch('<'), ++out; | |
| out = copy_chars(node->name(), node->name() + node->name_size(), out); | |
| out = print_attributes(out, node, flags); | |
| // If node is childless | |
| if (node->value_size() == 0 && !node->first_node()) | |
| { | |
| // Print childless node tag ending | |
| *out = Ch('/'), ++out; | |
| *out = Ch('>'), ++out; | |
| } | |
| else | |
| { | |
| // Print normal node tag ending | |
| *out = Ch('>'), ++out; | |
| // Test if node contains a single data node only (and no other nodes) | |
| xml_node<Ch> *child = node->first_node(); | |
| if (!child) | |
| { | |
| // If node has no children, only print its value without indenting | |
| out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); | |
| } | |
| else if (child->next_sibling() == 0 && child->type() == node_data) | |
| { | |
| // If node has a sole data child, only print its value without indenting | |
| out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); | |
| } | |
| else | |
| { | |
| // Print all children with full indenting | |
| if (!(flags & print_no_indenting)) | |
| *out = Ch('\n'), ++out; | |
| out = print_children(out, node, flags, indent + 1); | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| } | |
| // Print node end | |
| *out = Ch('<'), ++out; | |
| *out = Ch('/'), ++out; | |
| out = copy_chars(node->name(), node->name() + node->name_size(), out); | |
| *out = Ch('>'), ++out; | |
| } | |
| return out; | |
| } | |
| // Print declaration node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| // Print declaration start | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| *out = Ch('<'), ++out; | |
| *out = Ch('?'), ++out; | |
| *out = Ch('x'), ++out; | |
| *out = Ch('m'), ++out; | |
| *out = Ch('l'), ++out; | |
| // Print attributes | |
| out = print_attributes(out, node, flags); | |
| // Print declaration end | |
| *out = Ch('?'), ++out; | |
| *out = Ch('>'), ++out; | |
| return out; | |
| } | |
| // Print comment node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| assert(node->type() == node_comment); | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| *out = Ch('<'), ++out; | |
| *out = Ch('!'), ++out; | |
| *out = Ch('-'), ++out; | |
| *out = Ch('-'), ++out; | |
| out = copy_chars(node->value(), node->value() + node->value_size(), out); | |
| *out = Ch('-'), ++out; | |
| *out = Ch('-'), ++out; | |
| *out = Ch('>'), ++out; | |
| return out; | |
| } | |
| // Print doctype node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| assert(node->type() == node_doctype); | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| *out = Ch('<'), ++out; | |
| *out = Ch('!'), ++out; | |
| *out = Ch('D'), ++out; | |
| *out = Ch('O'), ++out; | |
| *out = Ch('C'), ++out; | |
| *out = Ch('T'), ++out; | |
| *out = Ch('Y'), ++out; | |
| *out = Ch('P'), ++out; | |
| *out = Ch('E'), ++out; | |
| *out = Ch(' '), ++out; | |
| out = copy_chars(node->value(), node->value() + node->value_size(), out); | |
| *out = Ch('>'), ++out; | |
| return out; | |
| } | |
| // Print pi node | |
| template<class OutIt, class Ch> | |
| inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) | |
| { | |
| assert(node->type() == node_pi); | |
| if (!(flags & print_no_indenting)) | |
| out = fill_chars(out, indent, Ch('\t')); | |
| *out = Ch('<'), ++out; | |
| *out = Ch('?'), ++out; | |
| out = copy_chars(node->name(), node->name() + node->name_size(), out); | |
| *out = Ch(' '), ++out; | |
| out = copy_chars(node->value(), node->value() + node->value_size(), out); | |
| *out = Ch('?'), ++out; | |
| *out = Ch('>'), ++out; | |
| return out; | |
| } | |
| } | |
| //! \endcond | |
| /////////////////////////////////////////////////////////////////////////// | |
| // Printing | |
| //! Prints XML to given output iterator. | |
| //! \param out Output iterator to print to. | |
| //! \param node Node to be printed. Pass xml_document to print entire document. | |
| //! \param flags Flags controlling how XML is printed. | |
| //! \return Output iterator pointing to position immediately after last character of printed text. | |
| template<class OutIt, class Ch> | |
| inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0) | |
| { | |
| return internal::print_node(out, &node, flags, 0); | |
| } | |
| #ifndef RAPIDXML_NO_STREAMS | |
| //! Prints XML to given output stream. | |
| //! \param out Output stream to print to. | |
| //! \param node Node to be printed. Pass xml_document to print entire document. | |
| //! \param flags Flags controlling how XML is printed. | |
| //! \return Output stream. | |
| template<class Ch> | |
| inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0) | |
| { | |
| print(std::ostream_iterator<Ch>(out), node, flags); | |
| return out; | |
| } | |
| //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. | |
| //! \param out Output stream to print to. | |
| //! \param node Node to be printed. | |
| //! \return Output stream. | |
| template<class Ch> | |
| inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node) | |
| { | |
| return print(out, node); | |
| } | |
| #endif | |
| } | |
| #endif |