// ---------------------------------------------------------------------------- | |
// 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 |