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