00001 #ifndef RAPIDXML_PRINT_HPP_INCLUDED
00002 #define RAPIDXML_PRINT_HPP_INCLUDED
00003
00004
00005
00006
00008
00009 #include "rapidxml.hpp"
00010
00011
00012 #ifndef RAPIDXML_NO_STREAMS
00013 #include <ostream>
00014 #include <iterator>
00015 #endif
00016
00017 namespace rapidxml
00018 {
00019
00021
00022
00023 const int print_no_indenting = 0x1;
00024
00026
00027
00029 namespace internal
00030 {
00031
00033
00034
00035
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
00045
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;
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;
00076 }
00077 }
00078 ++begin;
00079 }
00080 return out;
00081 }
00082
00083
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
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
00104 template<class OutIt, class Ch>
00105 inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00106 template<class OutIt, class Ch>
00107 inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00108 template<class OutIt, class Ch>
00109 inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00110 template<class OutIt, class Ch>
00111 inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00112 template<class OutIt, class Ch>
00113 inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00114 template<class OutIt, class Ch>
00115 inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00116 template<class OutIt, class Ch>
00117 inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00118 template<class OutIt, class Ch>
00119 inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
00120
00121
00122
00123 template<class OutIt, class Ch>
00124 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00125 {
00126
00127 switch (node->type())
00128 {
00129
00130
00131 case node_document:
00132 out = print_children(out, node, flags, indent);
00133 break;
00134
00135
00136 case node_element:
00137 out = print_element_node(out, node, flags, indent);
00138 break;
00139
00140
00141 case node_data:
00142 out = print_data_node(out, node, flags, indent);
00143 break;
00144
00145
00146 case node_cdata:
00147 out = print_cdata_node(out, node, flags, indent);
00148 break;
00149
00150
00151 case node_declaration:
00152 out = print_declaration_node(out, node, flags, indent);
00153 break;
00154
00155
00156 case node_comment:
00157 out = print_comment_node(out, node, flags, indent);
00158 break;
00159
00160
00161 case node_doctype:
00162 out = print_doctype_node(out, node, flags, indent);
00163 break;
00164
00165
00166 case node_pi:
00167 out = print_pi_node(out, node, flags, indent);
00168 break;
00169
00170
00171 default:
00172 assert(0);
00173 break;
00174 }
00175
00176
00177 if (!(flags & print_no_indenting))
00178 *out = Ch('\n'), ++out;
00179
00180
00181 return out;
00182 }
00183
00184
00185 template<class OutIt, class Ch>
00186 inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00187 {
00188 for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
00189 out = print_node(out, child, flags, indent);
00190 return out;
00191 }
00192
00193
00194 template<class OutIt, class Ch>
00195 inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
00196 {
00197 for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
00198 {
00199 if (attribute->name() && attribute->value())
00200 {
00201
00202 *out = Ch(' '), ++out;
00203 out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
00204 *out = Ch('='), ++out;
00205
00206 if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
00207 {
00208 *out = Ch('\''), ++out;
00209 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
00210 *out = Ch('\''), ++out;
00211 }
00212 else
00213 {
00214 *out = Ch('"'), ++out;
00215 out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
00216 *out = Ch('"'), ++out;
00217 }
00218 }
00219 }
00220 return out;
00221 }
00222
00223
00224 template<class OutIt, class Ch>
00225 inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00226 {
00227 assert(node->type() == node_data);
00228 if (!(flags & print_no_indenting))
00229 out = fill_chars(out, indent, Ch('\t'));
00230 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
00231 return out;
00232 }
00233
00234
00235 template<class OutIt, class Ch>
00236 inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00237 {
00238 assert(node->type() == node_cdata);
00239 if (!(flags & print_no_indenting))
00240 out = fill_chars(out, indent, Ch('\t'));
00241 *out = Ch('<'); ++out;
00242 *out = Ch('!'); ++out;
00243 *out = Ch('['); ++out;
00244 *out = Ch('C'); ++out;
00245 *out = Ch('D'); ++out;
00246 *out = Ch('A'); ++out;
00247 *out = Ch('T'); ++out;
00248 *out = Ch('A'); ++out;
00249 *out = Ch('['); ++out;
00250 out = copy_chars(node->value(), node->value() + node->value_size(), out);
00251 *out = Ch(']'); ++out;
00252 *out = Ch(']'); ++out;
00253 *out = Ch('>'); ++out;
00254 return out;
00255 }
00256
00257
00258 template<class OutIt, class Ch>
00259 inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00260 {
00261 assert(node->type() == node_element);
00262
00263
00264 if (!(flags & print_no_indenting))
00265 out = fill_chars(out, indent, Ch('\t'));
00266 *out = Ch('<'), ++out;
00267 out = copy_chars(node->name(), node->name() + node->name_size(), out);
00268 out = print_attributes(out, node, flags);
00269
00270
00271 if (node->value_size() == 0 && !node->first_node())
00272 {
00273
00274 *out = Ch('/'), ++out;
00275 *out = Ch('>'), ++out;
00276 }
00277 else
00278 {
00279
00280 *out = Ch('>'), ++out;
00281
00282
00283 xml_node<Ch> *child = node->first_node();
00284 if (!child)
00285 {
00286
00287 out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
00288 }
00289 else if (child->next_sibling() == 0 && child->type() == node_data)
00290 {
00291
00292 out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
00293 }
00294 else
00295 {
00296
00297 if (!(flags & print_no_indenting))
00298 *out = Ch('\n'), ++out;
00299 out = print_children(out, node, flags, indent + 1);
00300 if (!(flags & print_no_indenting))
00301 out = fill_chars(out, indent, Ch('\t'));
00302 }
00303
00304
00305 *out = Ch('<'), ++out;
00306 *out = Ch('/'), ++out;
00307 out = copy_chars(node->name(), node->name() + node->name_size(), out);
00308 *out = Ch('>'), ++out;
00309 }
00310 return out;
00311 }
00312
00313
00314 template<class OutIt, class Ch>
00315 inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00316 {
00317
00318 if (!(flags & print_no_indenting))
00319 out = fill_chars(out, indent, Ch('\t'));
00320 *out = Ch('<'), ++out;
00321 *out = Ch('?'), ++out;
00322 *out = Ch('x'), ++out;
00323 *out = Ch('m'), ++out;
00324 *out = Ch('l'), ++out;
00325
00326
00327 out = print_attributes(out, node, flags);
00328
00329
00330 *out = Ch('?'), ++out;
00331 *out = Ch('>'), ++out;
00332
00333 return out;
00334 }
00335
00336
00337 template<class OutIt, class Ch>
00338 inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00339 {
00340 assert(node->type() == node_comment);
00341 if (!(flags & print_no_indenting))
00342 out = fill_chars(out, indent, Ch('\t'));
00343 *out = Ch('<'), ++out;
00344 *out = Ch('!'), ++out;
00345 *out = Ch('-'), ++out;
00346 *out = Ch('-'), ++out;
00347 out = copy_chars(node->value(), node->value() + node->value_size(), out);
00348 *out = Ch('-'), ++out;
00349 *out = Ch('-'), ++out;
00350 *out = Ch('>'), ++out;
00351 return out;
00352 }
00353
00354
00355 template<class OutIt, class Ch>
00356 inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00357 {
00358 assert(node->type() == node_doctype);
00359 if (!(flags & print_no_indenting))
00360 out = fill_chars(out, indent, Ch('\t'));
00361 *out = Ch('<'), ++out;
00362 *out = Ch('!'), ++out;
00363 *out = Ch('D'), ++out;
00364 *out = Ch('O'), ++out;
00365 *out = Ch('C'), ++out;
00366 *out = Ch('T'), ++out;
00367 *out = Ch('Y'), ++out;
00368 *out = Ch('P'), ++out;
00369 *out = Ch('E'), ++out;
00370 *out = Ch(' '), ++out;
00371 out = copy_chars(node->value(), node->value() + node->value_size(), out);
00372 *out = Ch('>'), ++out;
00373 return out;
00374 }
00375
00376
00377 template<class OutIt, class Ch>
00378 inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00379 {
00380 assert(node->type() == node_pi);
00381 if (!(flags & print_no_indenting))
00382 out = fill_chars(out, indent, Ch('\t'));
00383 *out = Ch('<'), ++out;
00384 *out = Ch('?'), ++out;
00385 out = copy_chars(node->name(), node->name() + node->name_size(), out);
00386 *out = Ch(' '), ++out;
00387 out = copy_chars(node->value(), node->value() + node->value_size(), out);
00388 *out = Ch('?'), ++out;
00389 *out = Ch('>'), ++out;
00390 return out;
00391 }
00392
00393 }
00395
00397
00398
00404 template<class OutIt, class Ch>
00405 inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
00406 {
00407 return internal::print_node(out, &node, flags, 0);
00408 }
00409
00410 #ifndef RAPIDXML_NO_STREAMS
00411
00417 template<class Ch>
00418 inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
00419 {
00420 print(std::ostream_iterator<Ch>(out), node, flags);
00421 return out;
00422 }
00423
00428 template<class Ch>
00429 inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
00430 {
00431 return print(out, node);
00432 }
00433
00434 #endif
00435
00436 }
00437
00438 #endif