rapidxml_print.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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. template<class OutIt, class Ch>
  91. inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  92. template<class OutIt, class Ch>
  93. inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
  94. template<class OutIt, class Ch>
  95. inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  96. template<class OutIt, class Ch>
  97. inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  98. template<class OutIt, class Ch>
  99. inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  100. template<class OutIt, class Ch>
  101. inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  102. template<class OutIt, class Ch>
  103. inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  104. template<class OutIt, class Ch>
  105. inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  106. template<class OutIt, class Ch>
  107. inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
  108. // Print node
  109. template<class OutIt, class Ch>
  110. inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  111. {
  112. // Print proper node type
  113. switch (node->type())
  114. {
  115. // Document
  116. case node_document:
  117. out = print_children(out, node, flags, indent);
  118. break;
  119. // Element
  120. case node_element:
  121. out = print_element_node(out, node, flags, indent);
  122. break;
  123. // Data
  124. case node_data:
  125. out = print_data_node(out, node, flags, indent);
  126. break;
  127. // CDATA
  128. case node_cdata:
  129. out = print_cdata_node(out, node, flags, indent);
  130. break;
  131. // Declaration
  132. case node_declaration:
  133. out = print_declaration_node(out, node, flags, indent);
  134. break;
  135. // Comment
  136. case node_comment:
  137. out = print_comment_node(out, node, flags, indent);
  138. break;
  139. // Doctype
  140. case node_doctype:
  141. out = print_doctype_node(out, node, flags, indent);
  142. break;
  143. // Pi
  144. case node_pi:
  145. out = print_pi_node(out, node, flags, indent);
  146. break;
  147. // Unknown
  148. default:
  149. assert(0);
  150. break;
  151. }
  152. // If indenting not disabled, add line break after node
  153. if (!(flags & print_no_indenting))
  154. *out = Ch('\n'), ++out;
  155. // Return modified iterator
  156. return out;
  157. }
  158. // Print children of the node
  159. template<class OutIt, class Ch>
  160. inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  161. {
  162. for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
  163. out = print_node(out, child, flags, indent);
  164. return out;
  165. }
  166. // Print attributes of the node
  167. template<class OutIt, class Ch>
  168. inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
  169. {
  170. (void)(flags); // 避免告警
  171. for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
  172. {
  173. if (attribute->name() && attribute->value())
  174. {
  175. // Print attribute name
  176. *out = Ch(' '), ++out;
  177. out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
  178. *out = Ch('='), ++out;
  179. // Print attribute value using appropriate quote type
  180. if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
  181. {
  182. *out = Ch('\''), ++out;
  183. out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
  184. *out = Ch('\''), ++out;
  185. }
  186. else
  187. {
  188. *out = Ch('"'), ++out;
  189. out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
  190. *out = Ch('"'), ++out;
  191. }
  192. }
  193. }
  194. return out;
  195. }
  196. // Print data node
  197. template<class OutIt, class Ch>
  198. inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  199. {
  200. assert(node->type() == node_data);
  201. if (!(flags & print_no_indenting))
  202. out = fill_chars(out, indent, Ch('\t'));
  203. out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
  204. return out;
  205. }
  206. // Print data node
  207. template<class OutIt, class Ch>
  208. inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  209. {
  210. assert(node->type() == node_cdata);
  211. if (!(flags & print_no_indenting))
  212. out = fill_chars(out, indent, Ch('\t'));
  213. *out = Ch('<'); ++out;
  214. *out = Ch('!'); ++out;
  215. *out = Ch('['); ++out;
  216. *out = Ch('C'); ++out;
  217. *out = Ch('D'); ++out;
  218. *out = Ch('A'); ++out;
  219. *out = Ch('T'); ++out;
  220. *out = Ch('A'); ++out;
  221. *out = Ch('['); ++out;
  222. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  223. *out = Ch(']'); ++out;
  224. *out = Ch(']'); ++out;
  225. *out = Ch('>'); ++out;
  226. return out;
  227. }
  228. // Print element node
  229. template<class OutIt, class Ch>
  230. inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  231. {
  232. assert(node->type() == node_element);
  233. // Print element name and attributes, if any
  234. if (!(flags & print_no_indenting))
  235. out = fill_chars(out, indent, Ch('\t'));
  236. *out = Ch('<'), ++out;
  237. out = copy_chars(node->name(), node->name() + node->name_size(), out);
  238. out = print_attributes(out, node, flags);
  239. // If node is childless
  240. if (node->value_size() == 0 && !node->first_node())
  241. {
  242. // Print childless node tag ending
  243. *out = Ch('/'), ++out;
  244. *out = Ch('>'), ++out;
  245. }
  246. else
  247. {
  248. // Print normal node tag ending
  249. *out = Ch('>'), ++out;
  250. // Test if node contains a single data node only (and no other nodes)
  251. xml_node<Ch> *child = node->first_node();
  252. if (!child)
  253. {
  254. // If node has no children, only print its value without indenting
  255. out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
  256. }
  257. else if (child->next_sibling() == 0 && child->type() == node_data)
  258. {
  259. // If node has a sole data child, only print its value without indenting
  260. out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
  261. }
  262. else
  263. {
  264. // Print all children with full indenting
  265. if (!(flags & print_no_indenting))
  266. *out = Ch('\n'), ++out;
  267. out = print_children(out, node, flags, indent + 1);
  268. if (!(flags & print_no_indenting))
  269. out = fill_chars(out, indent, Ch('\t'));
  270. }
  271. // Print node end
  272. *out = Ch('<'), ++out;
  273. *out = Ch('/'), ++out;
  274. out = copy_chars(node->name(), node->name() + node->name_size(), out);
  275. *out = Ch('>'), ++out;
  276. }
  277. return out;
  278. }
  279. // Print declaration node
  280. template<class OutIt, class Ch>
  281. inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  282. {
  283. // Print declaration start
  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('x'), ++out;
  289. *out = Ch('m'), ++out;
  290. *out = Ch('l'), ++out;
  291. // Print attributes
  292. out = print_attributes(out, node, flags);
  293. // Print declaration end
  294. *out = Ch('?'), ++out;
  295. *out = Ch('>'), ++out;
  296. return out;
  297. }
  298. // Print comment node
  299. template<class OutIt, class Ch>
  300. inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  301. {
  302. assert(node->type() == node_comment);
  303. if (!(flags & print_no_indenting))
  304. out = fill_chars(out, indent, Ch('\t'));
  305. *out = Ch('<'), ++out;
  306. *out = Ch('!'), ++out;
  307. *out = Ch('-'), ++out;
  308. *out = Ch('-'), ++out;
  309. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  310. *out = Ch('-'), ++out;
  311. *out = Ch('-'), ++out;
  312. *out = Ch('>'), ++out;
  313. return out;
  314. }
  315. // Print doctype node
  316. template<class OutIt, class Ch>
  317. inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  318. {
  319. assert(node->type() == node_doctype);
  320. if (!(flags & print_no_indenting))
  321. out = fill_chars(out, indent, Ch('\t'));
  322. *out = Ch('<'), ++out;
  323. *out = Ch('!'), ++out;
  324. *out = Ch('D'), ++out;
  325. *out = Ch('O'), ++out;
  326. *out = Ch('C'), ++out;
  327. *out = Ch('T'), ++out;
  328. *out = Ch('Y'), ++out;
  329. *out = Ch('P'), ++out;
  330. *out = Ch('E'), ++out;
  331. *out = Ch(' '), ++out;
  332. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  333. *out = Ch('>'), ++out;
  334. return out;
  335. }
  336. // Print pi node
  337. template<class OutIt, class Ch>
  338. inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
  339. {
  340. assert(node->type() == node_pi);
  341. if (!(flags & print_no_indenting))
  342. out = fill_chars(out, indent, Ch('\t'));
  343. *out = Ch('<'), ++out;
  344. *out = Ch('?'), ++out;
  345. out = copy_chars(node->name(), node->name() + node->name_size(), out);
  346. *out = Ch(' '), ++out;
  347. out = copy_chars(node->value(), node->value() + node->value_size(), out);
  348. *out = Ch('?'), ++out;
  349. *out = Ch('>'), ++out;
  350. return out;
  351. }
  352. }
  353. //! \endcond
  354. ///////////////////////////////////////////////////////////////////////////
  355. // Printing
  356. //! Prints XML to given output iterator.
  357. //! \param out Output iterator to print to.
  358. //! \param node Node to be printed. Pass xml_document to print entire document.
  359. //! \param flags Flags controlling how XML is printed.
  360. //! \return Output iterator pointing to position immediately after last character of printed text.
  361. template<class OutIt, class Ch>
  362. inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
  363. {
  364. return internal::print_node(out, &node, flags, 0);
  365. }
  366. #ifndef RAPIDXML_NO_STREAMS
  367. //! Prints XML to given output stream.
  368. //! \param out Output stream to print to.
  369. //! \param node Node to be printed. Pass xml_document to print entire document.
  370. //! \param flags Flags controlling how XML is printed.
  371. //! \return Output stream.
  372. template<class Ch>
  373. inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
  374. {
  375. print(std::ostream_iterator<Ch>(out), node, flags);
  376. return out;
  377. }
  378. //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
  379. //! \param out Output stream to print to.
  380. //! \param node Node to be printed.
  381. //! \return Output stream.
  382. template<class Ch>
  383. inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
  384. {
  385. return print(out, node);
  386. }
  387. #endif
  388. }
  389. #endif