xml_parser_write.hpp 7.2 KB

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