You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
194 lines
7.1 KiB
194 lines
7.1 KiB
// ---------------------------------------------------------------------------- |
|
// 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
|
|
|