rapidxml_print.hpp 13 KB

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