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