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 108 // Write opening tag, attributes and data 109 if (indent >= 0) 110 { 111 112 // Write opening brace and key 113 write_xml_indent(stream,indent,settings); 114 stream << Ch('<') << key; 115 116 // Write attributes 117 if (optional<const Ptree &> attribs = pt.get_child_optional(xmlattr<Str>())) 118 for (It it = attribs.get().begin(); it != attribs.get().end(); ++it) 119 stream << Ch(' ') << it->first << Ch('=') 120 << Ch('"') 121 << encode_char_entities( 122 it->second.template get_value<Str>()) 123 << Ch('"'); 124 125 if ( has_attrs_only ) 126 { 127 // Write closing brace 128 stream << Ch('/') << Ch('>'); 129 if (want_pretty) 130 stream << Ch('\n'); 131 } 132 else 133 { 134 // Write closing brace 135 stream << Ch('>'); 136 137 // Break line if needed and if we want pretty-printing 138 if (has_elements && want_pretty) 139 stream << Ch('\n'); 140 } 141 } 142 143 // Write data text, if present 144 if (!pt.data().empty()) 145 write_xml_text(stream, 146 pt.template get_value<Str>(), 147 indent + 1, has_elements && want_pretty, settings); 148 149 // Write elements, comments and texts 150 for (It it = pt.begin(); it != pt.end(); ++it) 151 { 152 if (it->first == xmlattr<Str>()) 153 continue; 154 else if (it->first == xmlcomment<Str>()) 155 write_xml_comment(stream, 156 it->second.template get_value<Str>(), 157 indent + 1, want_pretty, settings); 158 else if (it->first == xmltext<Str>()) 159 write_xml_text(stream, 160 it->second.template get_value<Str>(), 161 indent + 1, has_elements && want_pretty, settings); 162 else 163 write_xml_element(stream, it->first, it->second, 164 indent + 1, settings); 165 } 166 167 // Write closing tag 168 if (indent >= 0 && !has_attrs_only) 169 { 170 if (has_elements) 171 write_xml_indent(stream,indent,settings); 172 stream << Ch('<') << Ch('/') << key << Ch('>'); 173 if (want_pretty) 174 stream << Ch('\n'); 175 } 176 177 } 178 } 179 180 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)181 void write_xml_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 182 const Ptree &pt, 183 const std::string &filename, 184 const xml_writer_settings<typename Ptree::key_type> & settings) 185 { 186 typedef typename Ptree::key_type Str; 187 stream << detail::widen<Str>("<?xml version=\"1.0\" encoding=\"") 188 << settings.encoding 189 << detail::widen<Str>("\"?>\n"); 190 write_xml_element(stream, Str(), pt, -1, settings); 191 if (!stream) 192 BOOST_PROPERTY_TREE_THROW(xml_parser_error("write error", filename, 0)); 193 } 194 195 } } } 196 197 #endif 198