xml_parser_write.hpp 7.2 KB

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