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
00105
00106 template<class OutIt, class Ch>
00107 inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
00108 {
00109
00110 switch (node->type())
00111 {
00112
00113
00114 case node_document:
00115 out = print_children(out, node, flags, indent);
00116 break;
00117
00118
00119 case node_element:
00120 out = print_element_node(out, node, flags, indent);
00121 break;
00122
00123
00124 case node_data:
00125 out = print_data_node(out, node, flags, indent);
00126 break;
00127
00128
00129 case node_cdata:
00130 out = print_cdata_node(out, node, flags, indent);
00131 break;
00132
00133
00134 case node_declaration:
00135 out = print_declaration_node(out, node, flags, indent);
00136 break;
00137
00138
00139 case node_comment:
00140 out = print_comment_node(out, node, flags, indent);
00141 break;
00142
00143
00144 case node_doctype:
00145 out = print_doctype_node(out, node, flags, indent);
00146 break;
00147
00148
00149 case node_pi:
00150 out = print_pi_node(out, node, flags, indent);
00151 break;
00152
00153
00154 default:
00155 assert(0);
00156 break;
00157 }
00158
00159
00160 if (!(flags & print_no_indenting))
00161 *out = Ch('\n'), ++out;
00162
00163
00164 return out;
00165 }
00166
00167
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
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
00185 *out = Ch(' '), ++out;
00186 out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
00187 *out = Ch('='), ++out;
00188
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
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
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
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
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
00254 if (node->value_size() == 0 && !node->first_node())
00255 {
00256
00257 *out = Ch('/'), ++out;
00258 *out = Ch('>'), ++out;
00259 }
00260 else
00261 {
00262
00263 *out = Ch('>'), ++out;
00264
00265
00266 xml_node<Ch> *child = node->first_node();
00267 if (!child)
00268 {
00269
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
00275 out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
00276 }
00277 else
00278 {
00279
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
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
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
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
00310 out = print_attributes(out, node, flags);
00311
00312
00313 *out = Ch('?'), ++out;
00314 *out = Ch('>'), ++out;
00315
00316 return out;
00317 }
00318
00319
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
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
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
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