rapidxml
|
00001 #ifndef RAPIDXML_PRINT_HPP_INCLUDED 00002 #define RAPIDXML_PRINT_HPP_INCLUDED 00003 00004 // Copyright (C) 2006, 2009 Marcin Kalicinski 00005 // Version 1.13 00006 // Revision $DateTime: 2009/05/13 01:46:17 $ 00008 00009 #include "rapidxml.hpp" 00010 00011 // Only include streams if not disabled 00012 #ifndef RAPIDXML_NO_STREAMS 00013 #include <ostream> 00014 #include <iterator> 00015 #endif 00016 00017 namespace rapidxml 00018 { 00019 00021 // Printing flags 00022 00023 const int print_no_indenting = 0x1; 00024 00026 // Internal 00027 00029 namespace internal 00030 { 00031 00033 // Internal character operations 00034 00035 // Copy characters from given range to given output iterator 00036 template<class OutIt, class Ch> 00037 inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) 00038 { 00039 while (begin != end) 00040 *out++ = *begin++; 00041 return out; 00042 } 00043 00044 // Copy characters from given range to given output iterator and expand 00045 // characters into references (< > ' " &) 00046 template<class OutIt, class Ch> 00047 inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) 00048 { 00049 while (begin != end) 00050 { 00051 if (*begin == noexpand) 00052 { 00053 *out++ = *begin; // No expansion, copy character 00054 } 00055 else 00056 { 00057 switch (*begin) 00058 { 00059 case Ch('<'): 00060 *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); 00061 break; 00062 case Ch('>'): 00063 *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); 00064 break; 00065 case Ch('\''): 00066 *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); 00067 break; 00068 case Ch('"'): 00069 *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); 00070 break; 00071 case Ch('&'): 00072 *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); 00073 break; 00074 default: 00075 *out++ = *begin; // No expansion, copy character 00076 } 00077 } 00078 ++begin; // Step to next character 00079 } 00080 return out; 00081 } 00082 00083 // Fill given output iterator with repetitions of the same character 00084 template<class OutIt, class Ch> 00085 inline OutIt fill_chars(OutIt out, int n, Ch ch) 00086 { 00087 for (int i = 0; i < n; ++i) 00088 *out++ = ch; 00089 return out; 00090 } 00091 00092 // Find character 00093 template<class Ch, Ch ch> 00094 inline bool find_char(const Ch *begin, const Ch *end) 00095 { 00096 while (begin != end) 00097 if (*begin++ == ch) 00098 return true; 00099 return false; 00100 } 00101 00103 // Internal printing operations 00104 00105 // Print node 00106 template<class OutIt, class Ch> 00107 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00108 { 00109 // Print proper node type 00110 switch (node->type()) 00111 { 00112 00113 // Document 00114 case node_document: 00115 out = print_children(out, node, flags, indent); 00116 break; 00117 00118 // Element 00119 case node_element: 00120 out = print_element_node(out, node, flags, indent); 00121 break; 00122 00123 // Data 00124 case node_data: 00125 out = print_data_node(out, node, flags, indent); 00126 break; 00127 00128 // CDATA 00129 case node_cdata: 00130 out = print_cdata_node(out, node, flags, indent); 00131 break; 00132 00133 // Declaration 00134 case node_declaration: 00135 out = print_declaration_node(out, node, flags, indent); 00136 break; 00137 00138 // Comment 00139 case node_comment: 00140 out = print_comment_node(out, node, flags, indent); 00141 break; 00142 00143 // Doctype 00144 case node_doctype: 00145 out = print_doctype_node(out, node, flags, indent); 00146 break; 00147 00148 // Pi 00149 case node_pi: 00150 out = print_pi_node(out, node, flags, indent); 00151 break; 00152 00153 // Unknown 00154 default: 00155 assert(0); 00156 break; 00157 } 00158 00159 // If indenting not disabled, add line break after node 00160 if (!(flags & print_no_indenting)) 00161 *out = Ch('\n'), ++out; 00162 00163 // Return modified iterator 00164 return out; 00165 } 00166 00167 // Print children of the node 00168 template<class OutIt, class Ch> 00169 inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00170 { 00171 for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling()) 00172 out = print_node(out, child, flags, indent); 00173 return out; 00174 } 00175 00176 // Print attributes of the node 00177 template<class OutIt, class Ch> 00178 inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags) 00179 { 00180 for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) 00181 { 00182 if (attribute->name() && attribute->value()) 00183 { 00184 // Print attribute name 00185 *out = Ch(' '), ++out; 00186 out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); 00187 *out = Ch('='), ++out; 00188 // Print attribute value using appropriate quote type 00189 if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size())) 00190 { 00191 *out = Ch('\''), ++out; 00192 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); 00193 *out = Ch('\''), ++out; 00194 } 00195 else 00196 { 00197 *out = Ch('"'), ++out; 00198 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); 00199 *out = Ch('"'), ++out; 00200 } 00201 } 00202 } 00203 return out; 00204 } 00205 00206 // Print data node 00207 template<class OutIt, class Ch> 00208 inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00209 { 00210 assert(node->type() == node_data); 00211 if (!(flags & print_no_indenting)) 00212 out = fill_chars(out, indent, Ch('\t')); 00213 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); 00214 return out; 00215 } 00216 00217 // Print data node 00218 template<class OutIt, class Ch> 00219 inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00220 { 00221 assert(node->type() == node_cdata); 00222 if (!(flags & print_no_indenting)) 00223 out = fill_chars(out, indent, Ch('\t')); 00224 *out = Ch('<'); ++out; 00225 *out = Ch('!'); ++out; 00226 *out = Ch('['); ++out; 00227 *out = Ch('C'); ++out; 00228 *out = Ch('D'); ++out; 00229 *out = Ch('A'); ++out; 00230 *out = Ch('T'); ++out; 00231 *out = Ch('A'); ++out; 00232 *out = Ch('['); ++out; 00233 out = copy_chars(node->value(), node->value() + node->value_size(), out); 00234 *out = Ch(']'); ++out; 00235 *out = Ch(']'); ++out; 00236 *out = Ch('>'); ++out; 00237 return out; 00238 } 00239 00240 // Print element node 00241 template<class OutIt, class Ch> 00242 inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00243 { 00244 assert(node->type() == node_element); 00245 00246 // Print element name and attributes, if any 00247 if (!(flags & print_no_indenting)) 00248 out = fill_chars(out, indent, Ch('\t')); 00249 *out = Ch('<'), ++out; 00250 out = copy_chars(node->name(), node->name() + node->name_size(), out); 00251 out = print_attributes(out, node, flags); 00252 00253 // If node is childless 00254 if (node->value_size() == 0 && !node->first_node()) 00255 { 00256 // Print childless node tag ending 00257 *out = Ch('/'), ++out; 00258 *out = Ch('>'), ++out; 00259 } 00260 else 00261 { 00262 // Print normal node tag ending 00263 *out = Ch('>'), ++out; 00264 00265 // Test if node contains a single data node only (and no other nodes) 00266 xml_node<Ch> *child = node->first_node(); 00267 if (!child) 00268 { 00269 // If node has no children, only print its value without indenting 00270 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); 00271 } 00272 else if (child->next_sibling() == 0 && child->type() == node_data) 00273 { 00274 // If node has a sole data child, only print its value without indenting 00275 out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); 00276 } 00277 else 00278 { 00279 // Print all children with full indenting 00280 if (!(flags & print_no_indenting)) 00281 *out = Ch('\n'), ++out; 00282 out = print_children(out, node, flags, indent + 1); 00283 if (!(flags & print_no_indenting)) 00284 out = fill_chars(out, indent, Ch('\t')); 00285 } 00286 00287 // Print node end 00288 *out = Ch('<'), ++out; 00289 *out = Ch('/'), ++out; 00290 out = copy_chars(node->name(), node->name() + node->name_size(), out); 00291 *out = Ch('>'), ++out; 00292 } 00293 return out; 00294 } 00295 00296 // Print declaration node 00297 template<class OutIt, class Ch> 00298 inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00299 { 00300 // Print declaration start 00301 if (!(flags & print_no_indenting)) 00302 out = fill_chars(out, indent, Ch('\t')); 00303 *out = Ch('<'), ++out; 00304 *out = Ch('?'), ++out; 00305 *out = Ch('x'), ++out; 00306 *out = Ch('m'), ++out; 00307 *out = Ch('l'), ++out; 00308 00309 // Print attributes 00310 out = print_attributes(out, node, flags); 00311 00312 // Print declaration end 00313 *out = Ch('?'), ++out; 00314 *out = Ch('>'), ++out; 00315 00316 return out; 00317 } 00318 00319 // Print comment node 00320 template<class OutIt, class Ch> 00321 inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00322 { 00323 assert(node->type() == node_comment); 00324 if (!(flags & print_no_indenting)) 00325 out = fill_chars(out, indent, Ch('\t')); 00326 *out = Ch('<'), ++out; 00327 *out = Ch('!'), ++out; 00328 *out = Ch('-'), ++out; 00329 *out = Ch('-'), ++out; 00330 out = copy_chars(node->value(), node->value() + node->value_size(), out); 00331 *out = Ch('-'), ++out; 00332 *out = Ch('-'), ++out; 00333 *out = Ch('>'), ++out; 00334 return out; 00335 } 00336 00337 // Print doctype node 00338 template<class OutIt, class Ch> 00339 inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00340 { 00341 assert(node->type() == node_doctype); 00342 if (!(flags & print_no_indenting)) 00343 out = fill_chars(out, indent, Ch('\t')); 00344 *out = Ch('<'), ++out; 00345 *out = Ch('!'), ++out; 00346 *out = Ch('D'), ++out; 00347 *out = Ch('O'), ++out; 00348 *out = Ch('C'), ++out; 00349 *out = Ch('T'), ++out; 00350 *out = Ch('Y'), ++out; 00351 *out = Ch('P'), ++out; 00352 *out = Ch('E'), ++out; 00353 *out = Ch(' '), ++out; 00354 out = copy_chars(node->value(), node->value() + node->value_size(), out); 00355 *out = Ch('>'), ++out; 00356 return out; 00357 } 00358 00359 // Print pi node 00360 template<class OutIt, class Ch> 00361 inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) 00362 { 00363 assert(node->type() == node_pi); 00364 if (!(flags & print_no_indenting)) 00365 out = fill_chars(out, indent, Ch('\t')); 00366 *out = Ch('<'), ++out; 00367 *out = Ch('?'), ++out; 00368 out = copy_chars(node->name(), node->name() + node->name_size(), out); 00369 *out = Ch(' '), ++out; 00370 out = copy_chars(node->value(), node->value() + node->value_size(), out); 00371 *out = Ch('?'), ++out; 00372 *out = Ch('>'), ++out; 00373 return out; 00374 } 00375 00376 } 00378 00380 // Printing 00381 00387 template<class OutIt, class Ch> 00388 inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0) 00389 { 00390 return internal::print_node(out, &node, flags, 0); 00391 } 00392 00393 #ifndef RAPIDXML_NO_STREAMS 00394 00400 template<class Ch> 00401 inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0) 00402 { 00403 print(std::ostream_iterator<Ch>(out), node, flags); 00404 return out; 00405 } 00406 00411 template<class Ch> 00412 inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node) 00413 { 00414 return print(out, node); 00415 } 00416 00417 #endif 00418 00419 } 00420 00421 #endif