rapidxml_print.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #ifndef RAPIDXML_PRINT_HPP_INCLUDED
  2. #define RAPIDXML_PRINT_HPP_INCLUDED
  3. // Copyright (C) 2006, 2009 Marcin Kalicinski
  4. // Version 1.13
  5. // Revision $DateTime: 2009/05/13 01:46:17 $
  6. //! \file rapidxml_print.hpp This file contains rapidxml printer implementation
  7. #include "rapidxml.hpp"
  8. // Only include streams if not disabled
  9. #ifndef RAPIDXML_NO_STREAMS
  10. #include <ostream>
  11. #include <iterator>
  12. #endif
  13. namespace rapidxml
  14. {
  15. ///////////////////////////////////////////////////////////////////////
  16. // Printing flags
  17. const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
  18. ///////////////////////////////////////////////////////////////////////
  19. // Internal
  20. //! \cond internal
  21. namespace internal
  22. {
  23. ///////////////////////////////////////////////////////////////////////////
  24. // Internal character operations
  25. // Copy characters from given range to given output iterator
  26. template<class OutIt, class Ch>
  27. inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
  28. {
  29. while (begin != end)
  30. *out++ = *begin++;
  31. return out;
  32. }
  33. // Copy characters from given range to given output iterator and expand
  34. // characters into references (&lt; &gt; &apos; &quot; &amp;)
  35. template<class OutIt, class Ch>
  36. inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
  37. {
  38. while (begin != end)
  39. {
  40. if (*begin == noexpand)
  41. {
  42. *out++ = *begin; // No expansion, copy character
  43. }
  44. else
  45. {
  46. switch (*begin)
  47. {
  48. case Ch('<'):
  49. *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
  50. break;
  51. case Ch('>'):
  52. *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
  53. break;
  54. case Ch('\''):
  55. *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
  56. break;
  57. case Ch('"'):
  58. *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
  59. break;
  60. case Ch('&'):
  61. *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
  62. break;
  63. default:
  64. *out++ = *begin; // No expansion, copy character
  65. }
  66. }
  67. ++begin; // Step to next character
  68. }
  69. return out;
  70. }
  71. // Fill given output iterator with repetitions of the same character
  72. template<class OutIt, class Ch>
  73. inline OutIt fill_chars(OutIt out, int n, Ch ch)
  74. {
  75. for (int i = 0; i < n; ++i)
  76. *out++ = ch;
  77. return out;
  78. }
  79. // Find character
  80. template<class Ch, Ch ch>
  81. inline bool find_char(const Ch *begin, const Ch *end)
  82. {
  83. while (begin != end)
  84. if (*begin++ == ch)
  85. return true;
  86. return false;
  87. }
  88. ///////////////////////////////////////////////////////////////////////////
  89. // Internal printing operations
  90. // Print node
  91. template<class OutIt, class Ch>
  92. inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  93. {
  94. // Print proper node type
  95. switch (node->type())
  96. {
  97. // Document
  98. case node_document:
  99. out = print_children(out, node, flags, indent);
  100. break;
  101. // Element
  102. case node_element:
  103. out = print_element_node(out, node, flags, indent);
  104. break;
  105. // Data
  106. case node_data:
  107. out = print_data_node(out, node, flags, indent);
  108. break;
  109. // CDATA
  110. case node_cdata:
  111. out = print_cdata_node(out, node, flags, indent);
  112. break;
  113. // Declaration
  114. case node_declaration:
  115. out = print_declaration_node(out, node, flags, indent);
  116. break;
  117. // Comment
  118. case node_comment:
  119. out = print_comment_node(out, node, flags, indent);
  120. break;
  121. // Doctype
  122. case node_doctype:
  123. out = print_doctype_node(out, node, flags, indent);
  124. break;
  125. // Pi
  126. case node_pi:
  127. out = print_pi_node(out, node, flags, indent);
  128. break;
  129. // Unknown
  130. default:
  131. assert(0);
  132. break;
  133. }
  134. // If indenting not disabled, add line break after node
  135. if (!(flags & print_no_indenting))
  136. *out = Ch('\n'), ++out;
  137. // Return modified iterator
  138. return out;
  139. }
  140. // Print children of the node
  141. template<class OutIt, class Ch>
  142. inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  143. {
  144. for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
  145. out = print_node(out, child, flags, indent);
  146. return out;
  147. }
  148. // Print attributes of the node
  149. template<class OutIt, class Ch>
  150. inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
  151. {
  152. for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
  153. {
  154. if (attribute->name() && attribute->value())
  155. {
  156. // Print attribute name
  157. *out = Ch(' '), ++out;
  158. out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
  159. *out = Ch('='), ++out;
  160. // Print attribute value using appropriate quote type
  161. if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
  162. {
  163. *out = Ch('\''), ++out;
  164. out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
  165. *out = Ch('\''), ++out;
  166. }
  167. else
  168. {
  169. *out = Ch('"'), ++out;
  170. out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
  171. *out = Ch('"'), ++out;
  172. }
  173. }
  174. }
  175. return out;
  176. }
  177. // Print data node
  178. template<class OutIt, class Ch>
  179. inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  180. {
  181. assert(node->type() == node_data);
  182. if (!(flags & print_no_indenting))
  183. out = fill_chars(out, indent, Ch('\t'));
  184. out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
  185. return out;
  186. }
  187. // Print data node
  188. template<class OutIt, class Ch>
  189. inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  190. {
  191. assert(node->type() == node_cdata);
  192. if (!(flags & print_no_indenting))
  193. out = fill_chars(out, indent, Ch('\t'));
  194. *out = Ch('<'); ++out;
  195. *out = Ch('!'); ++out;
  196. *out = Ch('['); ++out;
  197. *out = Ch('C'); ++out;
  198. *out = Ch('D'); ++out;
  199. *out = Ch('A'); ++out;
  200. *out = Ch('T'); ++out;
  201. *out = Ch('A'); ++out;
  202. *out = Ch('['); ++out;
  203. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  204. *out = Ch(']'); ++out;
  205. *out = Ch(']'); ++out;
  206. *out = Ch('>'); ++out;
  207. return out;
  208. }
  209. // Print element node
  210. template<class OutIt, class Ch>
  211. inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  212. {
  213. assert(node->type() == node_element);
  214. // Print element name and attributes, if any
  215. if (!(flags & print_no_indenting))
  216. out = fill_chars(out, indent, Ch('\t'));
  217. *out = Ch('<'), ++out;
  218. out = copy_chars(node->name(), node->name() + node->name_size(), out);
  219. out = print_attributes(out, node, flags);
  220. // If node is childless
  221. if (node->value_size() == 0 && !node->first_node())
  222. {
  223. // Print childless node tag ending
  224. *out = Ch('/'), ++out;
  225. *out = Ch('>'), ++out;
  226. }
  227. else
  228. {
  229. // Print normal node tag ending
  230. *out = Ch('>'), ++out;
  231. // Test if node contains a single data node only (and no other nodes)
  232. xml_node<Ch> *child = node->first_node();
  233. if (!child)
  234. {
  235. // If node has no children, only print its value without indenting
  236. out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
  237. }
  238. else if (child->next_sibling() == 0 && child->type() == node_data)
  239. {
  240. // If node has a sole data child, only print its value without indenting
  241. out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
  242. }
  243. else
  244. {
  245. // Print all children with full indenting
  246. if (!(flags & print_no_indenting))
  247. *out = Ch('\n'), ++out;
  248. out = print_children(out, node, flags, indent + 1);
  249. if (!(flags & print_no_indenting))
  250. out = fill_chars(out, indent, Ch('\t'));
  251. }
  252. // Print node end
  253. *out = Ch('<'), ++out;
  254. *out = Ch('/'), ++out;
  255. out = copy_chars(node->name(), node->name() + node->name_size(), out);
  256. *out = Ch('>'), ++out;
  257. }
  258. return out;
  259. }
  260. // Print declaration node
  261. template<class OutIt, class Ch>
  262. inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  263. {
  264. // Print declaration start
  265. if (!(flags & print_no_indenting))
  266. out = fill_chars(out, indent, Ch('\t'));
  267. *out = Ch('<'), ++out;
  268. *out = Ch('?'), ++out;
  269. *out = Ch('x'), ++out;
  270. *out = Ch('m'), ++out;
  271. *out = Ch('l'), ++out;
  272. // Print attributes
  273. out = print_attributes(out, node, flags);
  274. // Print declaration end
  275. *out = Ch('?'), ++out;
  276. *out = Ch('>'), ++out;
  277. return out;
  278. }
  279. // Print comment node
  280. template<class OutIt, class Ch>
  281. inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  282. {
  283. assert(node->type() == node_comment);
  284. if (!(flags & print_no_indenting))
  285. out = fill_chars(out, indent, Ch('\t'));
  286. *out = Ch('<'), ++out;
  287. *out = Ch('!'), ++out;
  288. *out = Ch('-'), ++out;
  289. *out = Ch('-'), ++out;
  290. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  291. *out = Ch('-'), ++out;
  292. *out = Ch('-'), ++out;
  293. *out = Ch('>'), ++out;
  294. return out;
  295. }
  296. // Print doctype node
  297. template<class OutIt, class Ch>
  298. inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  299. {
  300. assert(node->type() == node_doctype);
  301. if (!(flags & print_no_indenting))
  302. out = fill_chars(out, indent, Ch('\t'));
  303. *out = Ch('<'), ++out;
  304. *out = Ch('!'), ++out;
  305. *out = Ch('D'), ++out;
  306. *out = Ch('O'), ++out;
  307. *out = Ch('C'), ++out;
  308. *out = Ch('T'), ++out;
  309. *out = Ch('Y'), ++out;
  310. *out = Ch('P'), ++out;
  311. *out = Ch('E'), ++out;
  312. *out = Ch(' '), ++out;
  313. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  314. *out = Ch('>'), ++out;
  315. return out;
  316. }
  317. // Print pi node
  318. template<class OutIt, class Ch>
  319. inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  320. {
  321. assert(node->type() == node_pi);
  322. if (!(flags & print_no_indenting))
  323. out = fill_chars(out, indent, Ch('\t'));
  324. *out = Ch('<'), ++out;
  325. *out = Ch('?'), ++out;
  326. out = copy_chars(node->name(), node->name() + node->name_size(), out);
  327. *out = Ch(' '), ++out;
  328. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  329. *out = Ch('?'), ++out;
  330. *out = Ch('>'), ++out;
  331. return out;
  332. }
  333. }
  334. //! \endcond
  335. ///////////////////////////////////////////////////////////////////////////
  336. // Printing
  337. //! Prints XML to given output iterator.
  338. //! \param out Output iterator to print to.
  339. //! \param node Node to be printed. Pass xml_document to print entire document.
  340. //! \param flags Flags controlling how XML is printed.
  341. //! \return Output iterator pointing to position immediately after last character of printed text.
  342. template<class OutIt, class Ch>
  343. inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
  344. {
  345. return internal::print_node(out, &node, flags, 0);
  346. }
  347. #ifndef RAPIDXML_NO_STREAMS
  348. //! Prints XML to given output stream.
  349. //! \param out Output stream to print to.
  350. //! \param node Node to be printed. Pass xml_document to print entire document.
  351. //! \param flags Flags controlling how XML is printed.
  352. //! \return Output stream.
  353. template<class Ch>
  354. inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
  355. {
  356. print(std::ostream_iterator<Ch>(out), node, flags);
  357. return out;
  358. }
  359. //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
  360. //! \param out Output stream to print to.
  361. //! \param node Node to be printed.
  362. //! \return Output stream.
  363. template<class Ch>
  364. inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
  365. {
  366. return print(out, node);
  367. }
  368. #endif
  369. }
  370. #endif