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