1 // ---------------------------------------------------------------------------- 2 // Copyright (C) 2002-2006 Marcin Kalicinski 3 // Copyright (C) 2013 Sebastian Redl 4 // 5 // Distributed under the Boost Software License, Version 1.0. 6 // (See accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 // 9 // For more information, see www.boost.org 10 // ---------------------------------------------------------------------------- 11 #ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED 12 #define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED 13 14 #include <boost/property_tree/ptree.hpp> 15 #include <boost/property_tree/detail/xml_parser_utils.hpp> 16 #include <string> 17 #include <ostream> 18 #include <iomanip> 19 20 namespace boost { namespace property_tree { namespace xml_parser 21 { 22 template<class Str> write_xml_indent(std::basic_ostream<typename Str::value_type> & stream,int indent,const xml_writer_settings<Str> & settings)23 void write_xml_indent(std::basic_ostream<typename Str::value_type> &stream, 24 int indent, 25 const xml_writer_settings<Str> & settings 26 ) 27 { 28 stream << std::basic_string<typename Str::value_type>(indent * settings.indent_count, settings.indent_char); 29 } 30 31 template<class Str> write_xml_comment(std::basic_ostream<typename Str::value_type> & stream,const Str & s,int indent,bool separate_line,const xml_writer_settings<Str> & settings)32 void write_xml_comment(std::basic_ostream<typename Str::value_type> &stream, 33 const Str &s, 34 int indent, 35 bool separate_line, 36 const xml_writer_settings<Str> & settings 37 ) 38 { 39 typedef typename Str::value_type Ch; 40 if (separate_line) 41 write_xml_indent(stream,indent,settings); 42 stream << Ch('<') << Ch('!') << Ch('-') << Ch('-'); 43 stream << s; 44 stream << Ch('-') << Ch('-') << Ch('>'); 45 if (separate_line) 46 stream << Ch('\n'); 47 } 48 49 template<class Str> write_xml_text(std::basic_ostream<typename Str::value_type> & stream,const Str & s,int indent,bool separate_line,const xml_writer_settings<Str> & settings)50 void write_xml_text(std::basic_ostream<typename Str::value_type> &stream, 51 const Str &s, 52 int indent, 53 bool separate_line, 54 const xml_writer_settings<Str> & settings 55 ) 56 { 57 typedef typename Str::value_type Ch; 58 if (separate_line) 59 write_xml_indent(stream,indent,settings); 60 stream << encode_char_entities(s); 61 if (separate_line) 62 stream << Ch('\n'); 63 } 64 65 template<class Ptree> write_xml_element(std::basic_ostream<typename Ptree::key_type::value_type> & stream,const typename Ptree::key_type & key,const Ptree & pt,int indent,const xml_writer_settings<typename Ptree::key_type> & settings)66 void write_xml_element(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 67 const typename Ptree::key_type &key, 68 const Ptree &pt, 69 int indent, 70 const xml_writer_settings<typename Ptree::key_type> & settings) 71 { 72 typedef typename Ptree::key_type::value_type Ch; 73 typedef typename Ptree::key_type Str; 74 typedef typename Ptree::const_iterator It; 75 76 bool want_pretty = settings.indent_count > 0; 77 // Find if elements present 78 bool has_elements = false; 79 bool has_attrs_only = pt.data().empty(); 80 for (It it = pt.begin(), end = pt.end(); it != end; ++it) 81 { 82 if (it->first != xmlattr<Str>() ) 83 { 84 has_attrs_only = false; 85 if (it->first != xmltext<Str>()) 86 { 87 has_elements = true; 88 break; 89 } 90 } 91 } 92 93 // Write element 94 if (pt.data().empty() && pt.empty()) // Empty key 95 { 96 if (indent >= 0) 97 { 98 write_xml_indent(stream,indent,settings); 99 stream << Ch('<') << key << 100 Ch('/') << Ch('>'); 101 if (want_pretty) 102 stream << Ch('\n'); 103 } 104 } 105 else // Nonempty key 106 { 107 // Write opening tag, attributes and data 108 if (indent >= 0) 109 { 110 // Write opening brace and key 111 write_xml_indent(stream,indent,settings); 112 stream << Ch('<') << key; 113 114 // Write attributes 115 if (optional<const Ptree &> attribs = pt.get_child_optional(xmlattr<Str>())) 116 for (It it = attribs.get().begin(); it != attribs.get().end(); ++it) 117 stream << Ch(' ') << it->first << Ch('=') 118 << Ch('"') 119 << encode_char_entities( 120 it->second.template get_value<Str>()) 121 << Ch('"'); 122 123 if ( has_attrs_only ) 124 { 125 // Write closing brace 126 stream << Ch('/') << Ch('>'); 127 if (want_pretty) 128 stream << Ch('\n'); 129 } 130 else 131 { 132 // Write closing brace 133 stream << Ch('>'); 134 135 // Break line if needed and if we want pretty-printing 136 if (has_elements && want_pretty) 137 stream << Ch('\n'); 138 } 139 } 140 141 // Write data text, if present 142 if (!pt.data().empty()) 143 write_xml_text(stream, 144 pt.template get_value<Str>(), 145 indent + 1, has_elements && want_pretty, settings); 146 147 // Write elements, comments and texts 148 for (It it = pt.begin(); it != pt.end(); ++it) 149 { 150 if (it->first == xmlattr<Str>()) 151 continue; 152 else if (it->first == xmlcomment<Str>()) 153 write_xml_comment(stream, 154 it->second.template get_value<Str>(), 155 indent + 1, want_pretty, settings); 156 else if (it->first == xmltext<Str>()) 157 write_xml_text(stream, 158 it->second.template get_value<Str>(), 159 indent + 1, has_elements && want_pretty, settings); 160 else 161 write_xml_element(stream, it->first, it->second, 162 indent + 1, settings); 163 } 164 165 // Write closing tag 166 if (indent >= 0 && !has_attrs_only) 167 { 168 if (has_elements) 169 write_xml_indent(stream,indent,settings); 170 stream << Ch('<') << Ch('/') << key << Ch('>'); 171 if (want_pretty) 172 stream << Ch('\n'); 173 } 174 175 } 176 } 177 178 template<class Ptree> 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> & settings)179 void write_xml_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 180 const Ptree &pt, 181 const std::string &filename, 182 const xml_writer_settings<typename Ptree::key_type> & settings) 183 { 184 typedef typename Ptree::key_type Str; 185 stream << detail::widen<Str>("<?xml version=\"1.0\" encoding=\"") 186 << settings.encoding 187 << detail::widen<Str>("\"?>\n"); 188 write_xml_element(stream, Str(), pt, -1, settings); 189 if (!stream) 190 BOOST_PROPERTY_TREE_THROW(xml_parser_error("write error", filename, 0)); 191 } 192 193 } } } 194 195 #endif 196