| // ---------------------------------------------------------------------------- |
| // Copyright (C) 2002-2006 Marcin Kalicinski |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| // (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // For more information, see www.boost.org |
| // ---------------------------------------------------------------------------- |
| #ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED |
| #define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED |
| |
| #include <boost/property_tree/ptree.hpp> |
| #include <boost/property_tree/detail/xml_parser_utils.hpp> |
| #include <string> |
| #include <ostream> |
| #include <iomanip> |
| |
| namespace boost { namespace property_tree { namespace xml_parser |
| { |
| template<class Ch> |
| void write_xml_indent(std::basic_ostream<Ch> &stream, |
| int indent, |
| const xml_writer_settings<Ch> & settings |
| ) |
| { |
| stream << std::basic_string<Ch>(indent * settings.indent_count, settings.indent_char); |
| } |
| |
| template<class Ch> |
| void write_xml_comment(std::basic_ostream<Ch> &stream, |
| const std::basic_string<Ch> &s, |
| int indent, |
| bool separate_line, |
| const xml_writer_settings<Ch> & settings |
| ) |
| { |
| typedef typename std::basic_string<Ch> Str; |
| if (separate_line) |
| write_xml_indent(stream,indent,settings); |
| stream << Ch('<') << Ch('!') << Ch('-') << Ch('-'); |
| stream << s; |
| stream << Ch('-') << Ch('-') << Ch('>'); |
| if (separate_line) |
| stream << Ch('\n'); |
| } |
| |
| template<class Ch> |
| void write_xml_text(std::basic_ostream<Ch> &stream, |
| const std::basic_string<Ch> &s, |
| int indent, |
| bool separate_line, |
| const xml_writer_settings<Ch> & settings |
| ) |
| { |
| if (separate_line) |
| write_xml_indent(stream,indent,settings); |
| stream << encode_char_entities(s); |
| if (separate_line) |
| stream << Ch('\n'); |
| } |
| |
| template<class Ptree> |
| void write_xml_element(std::basic_ostream<typename Ptree::key_type::value_type> &stream, |
| const std::basic_string<typename Ptree::key_type::value_type> &key, |
| const Ptree &pt, |
| int indent, |
| const xml_writer_settings<typename Ptree::key_type::value_type> & settings) |
| { |
| |
| typedef typename Ptree::key_type::value_type Ch; |
| typedef typename std::basic_string<Ch> Str; |
| typedef typename Ptree::const_iterator It; |
| |
| bool want_pretty = settings.indent_count > 0; |
| // Find if elements present |
| bool has_elements = false; |
| bool has_attrs_only = pt.data().empty(); |
| for (It it = pt.begin(), end = pt.end(); it != end; ++it) |
| { |
| if (it->first != xmlattr<Ch>() ) |
| { |
| has_attrs_only = false; |
| if (it->first != xmltext<Ch>()) |
| { |
| has_elements = true; |
| break; |
| } |
| } |
| } |
| |
| // Write element |
| if (pt.data().empty() && pt.empty()) // Empty key |
| { |
| if (indent >= 0) |
| { |
| write_xml_indent(stream,indent,settings); |
| stream << Ch('<') << key << |
| Ch('/') << Ch('>'); |
| if (want_pretty) |
| stream << Ch('\n'); |
| } |
| } |
| else // Nonempty key |
| { |
| |
| // Write opening tag, attributes and data |
| if (indent >= 0) |
| { |
| |
| // Write opening brace and key |
| write_xml_indent(stream,indent,settings); |
| stream << Ch('<') << key; |
| |
| // Write attributes |
| if (optional<const Ptree &> attribs = pt.get_child_optional(xmlattr<Ch>())) |
| for (It it = attribs.get().begin(); it != attribs.get().end(); ++it) |
| stream << Ch(' ') << it->first << Ch('=') << |
| Ch('"') << it->second.template get_value<std::basic_string<Ch> >() << Ch('"'); |
| |
| if ( has_attrs_only ) |
| { |
| // Write closing brace |
| stream << Ch('/') << Ch('>'); |
| if (want_pretty) |
| stream << Ch('\n'); |
| } |
| else |
| { |
| // Write closing brace |
| stream << Ch('>'); |
| |
| // Break line if needed and if we want pretty-printing |
| if (has_elements && want_pretty) |
| stream << Ch('\n'); |
| } |
| } |
| |
| // Write data text, if present |
| if (!pt.data().empty()) |
| write_xml_text(stream, |
| pt.template get_value<std::basic_string<Ch> >(), |
| indent + 1, has_elements && want_pretty, settings); |
| |
| // Write elements, comments and texts |
| for (It it = pt.begin(); it != pt.end(); ++it) |
| { |
| if (it->first == xmlattr<Ch>()) |
| continue; |
| else if (it->first == xmlcomment<Ch>()) |
| write_xml_comment(stream, |
| it->second.template get_value<std::basic_string<Ch> >(), |
| indent + 1, want_pretty, settings); |
| else if (it->first == xmltext<Ch>()) |
| write_xml_text(stream, |
| it->second.template get_value<std::basic_string<Ch> >(), |
| indent + 1, has_elements && want_pretty, settings); |
| else |
| write_xml_element(stream, it->first, it->second, |
| indent + 1, settings); |
| } |
| |
| // Write closing tag |
| if (indent >= 0 && !has_attrs_only) |
| { |
| if (has_elements) |
| write_xml_indent(stream,indent,settings); |
| stream << Ch('<') << Ch('/') << key << Ch('>'); |
| if (want_pretty) |
| stream << Ch('\n'); |
| } |
| |
| } |
| } |
| |
| template<class Ptree> |
| void write_xml_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, |
| const Ptree &pt, |
| const std::string &filename, |
| const xml_writer_settings<typename Ptree::key_type::value_type> & settings) |
| { |
| typedef typename Ptree::key_type::value_type Ch; |
| typedef typename std::basic_string<Ch> Str; |
| stream << detail::widen<Ch>("<?xml version=\"1.0\" encoding=\"") |
| << settings.encoding |
| << detail::widen<Ch>("\"?>\n"); |
| write_xml_element(stream, Str(), pt, -1, settings); |
| if (!stream) |
| BOOST_PROPERTY_TREE_THROW(xml_parser_error("write error", filename, 0)); |
| } |
| |
| } } } |
| |
| #endif |