rapidxml_print.hpp 16 KB

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