xml_parser_write.hpp 7.1 KB

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