• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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