]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
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> | |
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> | |
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> | |
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> | |
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 |