rapidxml_print.h 15 KB

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