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