Imported Upstream version 1.49.0
[platform/upstream/boost.git] / boost / spirit / home / classic / tree / impl / tree_to_xml.ipp
1 /*=============================================================================
2     Copyright (c) 2001-2008 Hartmut Kaiser
3     Copyright (c) 2001-2003 Daniel Nuffer
4     http://spirit.sourceforge.net/
5
6     Use, modification and distribution is subject to the Boost Software
7     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8     http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10
11 #if !defined(TREE_TO_XML_IPP)
12 #define TREE_TO_XML_IPP
13
14 #include <cstdio>
15 #include <cstdarg>
16 #include <locale>
17 #include <string>
18 #include <cstring>
19
20 #include <map>
21 #include <iostream>
22 #include <boost/config.hpp>
23 #include <boost/assert.hpp>
24
25 #ifdef BOOST_NO_STRINGSTREAM
26 #include <strstream>
27 #define BOOST_SPIRIT_OSSTREAM std::ostrstream
28 inline
29 std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss)
30 {
31     ss << std::ends;
32     std::string rval = ss.str();
33     ss.freeze(false);
34     return rval;
35 }
36 #else
37 #include <sstream>
38 #define BOOST_SPIRIT_GETSTRING(ss) ss.str()
39 #define BOOST_SPIRIT_OSSTREAM std::basic_ostringstream<CharT>
40 #endif
41
42 namespace boost { namespace spirit {
43
44 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
45
46 namespace impl {
47
48     ///////////////////////////////////////////////////////////////////////////
49     template <typename CharT>
50     struct string_lit;
51
52     template <>
53     struct string_lit<char>
54     {
55         static char get(char c) { return c; }
56         static std::string get(char const* str = "") { return str; }
57     };
58
59     template <>
60     struct string_lit<wchar_t>
61     {
62         static wchar_t get(char c)
63         {
64             typedef std::ctype<wchar_t> ctype_t;
65             return std::use_facet<ctype_t>(std::locale()).widen(c);
66         }
67         static std::basic_string<wchar_t> get(char const* source = "")
68         {
69             using namespace std;        // some systems have size_t in ns std
70             size_t len = strlen(source);
71             std::auto_ptr<wchar_t> result (new wchar_t[len+1]);
72             result.get()[len] = '\0';
73
74             // working with wide character streams is supported only if the
75             // platform provides the std::ctype<wchar_t> facet
76             BOOST_ASSERT(std::has_facet<std::ctype<wchar_t> >(std::locale()));
77
78             std::use_facet<std::ctype<wchar_t> >(std::locale())
79                 .widen(source, source + len, result.get());
80             return result.get();
81         }
82     };
83 }
84
85 // xml formatting helper classes
86 namespace xml {
87
88     template <typename CharT>
89     inline void
90     encode (std::basic_string<CharT> &str, char s, char const *r, int len)
91     {
92         typedef typename std::basic_string<CharT>::size_type size_type;
93
94         size_type pos = 0;
95         while ((pos = str.find_first_of (impl::string_lit<CharT>::get(s), pos)) !=
96                 size_type(std::basic_string<CharT>::npos))
97         {
98             str.replace (pos, 1, impl::string_lit<CharT>::get(r));
99             pos += len;
100         }
101     }
102
103     template <typename CharT>
104     inline std::basic_string<CharT>
105     encode (std::basic_string<CharT> str)
106     {
107         encode(str, '&', "&amp;", 3);
108         encode(str, '<', "&lt;", 2);
109         encode(str, '>', "&gt;", 2);
110         encode(str, '\r', "\\r", 1);
111         encode(str, '\n', "\\n", 1);
112         return str;
113     }
114
115     template <typename CharT>
116     inline std::basic_string<CharT>
117     encode (CharT const *text)
118     {
119         return encode (std::basic_string<CharT>(text));
120     }
121
122     // format a xml attribute
123     template <typename CharT>
124     struct attribute
125     {
126         attribute()
127         {
128         }
129
130         attribute (std::basic_string<CharT> const& key_,
131                    std::basic_string<CharT> const& value_)
132           : key (key_), value(value_)
133         {
134         }
135
136         bool has_value()
137         {
138             return value.size() > 0;
139         }
140
141         std::basic_string<CharT> key;
142         std::basic_string<CharT> value;
143     };
144
145     template <typename CharT>
146     inline std::basic_ostream<CharT>&
147     operator<< (std::basic_ostream<CharT> &ostrm, attribute<CharT> const &attr)
148     {
149         if (0 == attr.key.size())
150             return ostrm;
151         ostrm << impl::string_lit<CharT>::get(" ") << encode(attr.key)
152               << impl::string_lit<CharT>::get("=\"") << encode(attr.value)
153               << impl::string_lit<CharT>::get("\"");
154         return ostrm;
155     }
156
157     // output a xml element (base class, not used directly)
158     template <typename CharT>
159     class element
160     {
161     protected:
162         element(std::basic_ostream<CharT> &ostrm_, bool incr_indent_ = true)
163         :   ostrm(ostrm_), incr_indent(incr_indent_)
164         {
165             if (incr_indent) ++get_indent();
166         }
167         ~element()
168         {
169             if (incr_indent) --get_indent();
170         }
171
172     public:
173         void output_space ()
174         {
175             for (int i = 0; i < get_indent(); i++)
176                 ostrm << impl::string_lit<CharT>::get("    ");
177         }
178
179     protected:
180         int &get_indent()
181         {
182             static int indent;
183
184             return indent;
185         }
186
187         std::basic_ostream<CharT> &ostrm;
188         bool incr_indent;
189     };
190
191     // a xml node
192     template <typename CharT>
193     class node : public element<CharT>
194     {
195     public:
196         node (std::basic_ostream<CharT> &ostrm_,
197               std::basic_string<CharT> const& tag_, attribute<CharT> &attr)
198         :   element<CharT>(ostrm_), tag(tag_)
199         {
200             this->output_space();
201             this->ostrm
202                   << impl::string_lit<CharT>::get("<") << tag_ << attr
203                   << impl::string_lit<CharT>::get(">\n");
204         }
205         node (std::basic_ostream<CharT> &ostrm_,
206               std::basic_string<CharT> const& tag_)
207         :   element<CharT>(ostrm_), tag(tag_)
208         {
209             this->output_space();
210             this->ostrm
211                   << impl::string_lit<CharT>::get("<") << tag_
212                   << impl::string_lit<CharT>::get(">\n");
213         }
214         ~node()
215         {
216             this->output_space();
217             this->ostrm
218                   << impl::string_lit<CharT>::get("</") << tag
219                   << impl::string_lit<CharT>::get(">\n");
220         }
221
222     private:
223         std::basic_string<CharT> tag;
224     };
225
226     template <typename CharT>
227     class text : public element<CharT>
228     {
229     public:
230         text (std::basic_ostream<CharT> &ostrm_,
231               std::basic_string<CharT> const& tag,
232               std::basic_string<CharT> const& textlit)
233         :   element<CharT>(ostrm_)
234         {
235             this->output_space();
236             this->ostrm
237                   << impl::string_lit<CharT>::get("<") << tag
238                   << impl::string_lit<CharT>::get(">") << encode(textlit)
239                   << impl::string_lit<CharT>::get("</") << tag
240                   << impl::string_lit<CharT>::get(">\n");
241         }
242
243         text (std::basic_ostream<CharT> &ostrm_,
244               std::basic_string<CharT> const& tag,
245               std::basic_string<CharT> const& textlit,
246               attribute<CharT> &attr)
247         :   element<CharT>(ostrm_)
248         {
249             this->output_space();
250             this->ostrm
251                   << impl::string_lit<CharT>::get("<") << tag << attr
252                   << impl::string_lit<CharT>::get(">") << encode(textlit)
253                   << impl::string_lit<CharT>::get("</") << tag
254                   << impl::string_lit<CharT>::get(">\n");
255         }
256
257         text (std::basic_ostream<CharT> &ostrm_,
258               std::basic_string<CharT> const& tag,
259               std::basic_string<CharT> const& textlit,
260               attribute<CharT> &attr1, attribute<CharT> &attr2)
261         :   element<CharT>(ostrm_)
262         {
263             this->output_space();
264             this->ostrm
265                   << impl::string_lit<CharT>::get("<") << tag << attr1 << attr2
266                   << impl::string_lit<CharT>::get(">") << encode(textlit)
267                   << impl::string_lit<CharT>::get("</") << tag
268                   << impl::string_lit<CharT>::get(">\n");
269         }
270     };
271
272     // a xml comment
273     template <typename CharT>
274     class comment : public element<CharT>
275     {
276     public:
277         comment (std::basic_ostream<CharT> &ostrm_,
278                  std::basic_string<CharT> const& commentlit)
279         :   element<CharT>(ostrm_, false)
280         {
281             if ('\0' != commentlit[0])
282             {
283                 this->output_space();
284                 this->ostrm << impl::string_lit<CharT>::get("<!-- ")
285                       << encode(commentlit)
286                       << impl::string_lit<CharT>::get(" -->\n");
287             }
288         }
289     };
290
291     // a xml document
292     template <typename CharT>
293     class document : public element<CharT>
294     {
295     public:
296         document (std::basic_ostream<CharT> &ostrm_)
297         :   element<CharT>(ostrm_)
298         {
299             this->get_indent() = -1;
300             this->ostrm << impl::string_lit<CharT>::get(
301                 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
302         }
303
304         document (std::basic_ostream<CharT> &ostrm_,
305                   std::basic_string<CharT> const& mainnode,
306                   std::basic_string<CharT> const& dtd)
307         :   element<CharT>(ostrm_)
308         {
309             this->get_indent() = -1;
310             this->ostrm << impl::string_lit<CharT>::get(
311                 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
312
313             this->output_space();
314             this->ostrm << impl::string_lit<CharT>::get("<!DOCTYPE ") << mainnode
315                   << impl::string_lit<CharT>::get(" SYSTEM \"") << dtd
316                   << impl::string_lit<CharT>::get("\">\n");
317         }
318         ~document()
319         {
320             BOOST_SPIRIT_ASSERT(-1 == this->get_indent());
321         }
322     };
323
324 } // end of namespace xml
325
326 namespace impl {
327
328     ///////////////////////////////////////////////////////////////////////////
329     // look up the rule name from the given parser_id
330     template <typename AssocContainerT>
331     inline typename AssocContainerT::value_type::second_type
332     get_rulename (AssocContainerT const &id_to_name_map,
333         BOOST_SPIRIT_CLASSIC_NS::parser_id const &id)
334     {
335         typename AssocContainerT::const_iterator it = id_to_name_map.find(id);
336         if (it != id_to_name_map.end())
337             return (*it).second;
338         typedef typename AssocContainerT::value_type::second_type second_t;
339         return second_t();
340     }
341
342     // dump a parse tree as xml
343     template <
344         typename CharT, typename IteratorT, typename GetIdT, typename GetValueT
345     >
346     inline void
347     token_to_xml (std::basic_ostream<CharT> &ostrm, IteratorT const &it,
348         bool is_root, GetIdT const &get_token_id, GetValueT const &get_token_value)
349     {
350         BOOST_SPIRIT_OSSTREAM stream;
351
352         stream << get_token_id(*it) << std::ends;
353         xml::attribute<CharT> token_id (
354                 impl::string_lit<CharT>::get("id"),
355                 BOOST_SPIRIT_GETSTRING(stream).c_str());
356         xml::attribute<CharT> is_root_attr (
357                 impl::string_lit<CharT>::get("is_root"),
358                 impl::string_lit<CharT>::get(is_root ? "1" : ""));
359         xml::attribute<CharT> nil;
360         xml::text<CharT>(ostrm,
361                 impl::string_lit<CharT>::get("token"),
362                 get_token_value(*it).c_str(),
363                 token_id,
364                 is_root_attr.has_value() ? is_root_attr : nil);
365     }
366
367     template <
368         typename CharT, typename TreeNodeT, typename AssocContainerT,
369         typename GetIdT, typename GetValueT
370     >
371     inline void
372     tree_node_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &node,
373         AssocContainerT const& id_to_name_map, GetIdT const &get_token_id,
374         GetValueT const &get_token_value)
375     {
376         typedef typename TreeNodeT::const_iterator node_iter_t;
377         typedef
378             typename TreeNodeT::value_type::parse_node_t::const_iterator_t
379             value_iter_t;
380
381         xml::attribute<CharT> nil;
382         node_iter_t end = node.end();
383         for (node_iter_t it = node.begin(); it != end; ++it)
384         {
385             // output a node
386             xml::attribute<CharT> id (
387                 impl::string_lit<CharT>::get("rule"),
388                 get_rulename(id_to_name_map, (*it).value.id()).c_str());
389             xml::node<CharT> currnode (ostrm,
390                 impl::string_lit<CharT>::get("parsenode"),
391                 (*it).value.id() != 0 && id.has_value() ? id : nil);
392
393             // first dump the value
394             std::size_t cnt = std::distance((*it).value.begin(), (*it).value.end());
395
396             if (1 == cnt)
397             {
398                 token_to_xml (ostrm, (*it).value.begin(),
399                     (*it).value.is_root(), get_token_id, get_token_value);
400             }
401             else if (cnt > 1)
402             {
403                 xml::node<CharT> value (ostrm,
404                         impl::string_lit<CharT>::get("value"));
405                 bool is_root = (*it).value.is_root();
406
407                 value_iter_t val_end = (*it).value.end();
408                 for (value_iter_t val_it = (*it).value.begin();
409                 val_it != val_end; ++val_it)
410                 {
411                     token_to_xml (ostrm, val_it, is_root, get_token_id,
412                         get_token_value);
413                 }
414             }
415             tree_node_to_xml(ostrm, (*it).children, id_to_name_map,
416                 get_token_id, get_token_value);      // dump all subnodes
417         }
418     }
419
420     template <typename CharT, typename TreeNodeT, typename AssocContainerT>
421     inline void
422     tree_node_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &node,
423             AssocContainerT const& id_to_name_map)
424     {
425         typedef typename TreeNodeT::const_iterator node_iter_t;
426
427         xml::attribute<CharT> nil;
428         node_iter_t end = node.end();
429         for (node_iter_t it = node.begin(); it != end; ++it)
430         {
431             // output a node
432             xml::attribute<CharT> id (
433                 impl::string_lit<CharT>::get("rule"),
434                 get_rulename(id_to_name_map, (*it).value.id()).c_str());
435             xml::node<CharT> currnode (ostrm,
436                 impl::string_lit<CharT>::get("parsenode"),
437                 (*it).value.id() != parser_id() && id.has_value() ? id : nil);
438
439             // first dump the value
440             if ((*it).value.begin() != (*it).value.end())
441             {
442                 std::basic_string<CharT> tokens ((*it).value.begin(), (*it).value.end());
443
444                 if (tokens.size() > 0)
445                 {
446                     // output all subtokens as one string (for better readability)
447                     xml::attribute<CharT> is_root (
448                         impl::string_lit<CharT>::get("is_root"),
449                         impl::string_lit<CharT>::get((*it).value.is_root() ? "1" : ""));
450                     xml::text<CharT>(ostrm,
451                         impl::string_lit<CharT>::get("value"), tokens.c_str(),
452                         is_root.has_value() ? is_root : nil);
453                 }
454
455             }
456             // dump all subnodes
457             tree_node_to_xml(ostrm, (*it).children, id_to_name_map);
458         }
459     }
460
461 } // namespace impl
462
463 ///////////////////////////////////////////////////////////////////////////////
464 // dump a parse tree as a xml stream (generic variant)
465 template <
466     typename CharT, typename TreeNodeT, typename AssocContainerT,
467     typename GetIdT, typename GetValueT
468 >
469 inline void
470 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
471 std::basic_string<CharT> const &input_line, AssocContainerT const& id_to_name,
472         GetIdT const &get_token_id, GetValueT const &get_token_value)
473 {
474     // generate xml dump
475     xml::document<CharT> doc (ostrm,
476             impl::string_lit<CharT>::get("parsetree"),
477             impl::string_lit<CharT>::get("parsetree.dtd"));
478     xml::comment<CharT> input (ostrm, input_line.c_str());
479     xml::attribute<CharT> ver (
480             impl::string_lit<CharT>::get("version"),
481             impl::string_lit<CharT>::get("1.0"));
482     xml::node<CharT> mainnode (ostrm,
483             impl::string_lit<CharT>::get("parsetree"), ver);
484
485     impl::tree_node_to_xml (ostrm, tree, id_to_name, get_token_id,
486         get_token_value);
487 }
488
489 // dump a parse tree as a xml steam (for character based parsers)
490 template <typename CharT, typename TreeNodeT, typename AssocContainerT>
491 inline void
492 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
493         std::basic_string<CharT> const &input_line,
494         AssocContainerT const& id_to_name)
495 {
496     // generate xml dump
497     xml::document<CharT> doc (ostrm,
498             impl::string_lit<CharT>::get("parsetree"),
499             impl::string_lit<CharT>::get("parsetree.dtd"));
500     xml::comment<CharT> input (ostrm, input_line.c_str());
501     xml::attribute<CharT> ver (
502             impl::string_lit<CharT>::get("version"),
503             impl::string_lit<CharT>::get("1.0"));
504     xml::node<CharT> mainnode (ostrm,
505             impl::string_lit<CharT>::get("parsetree"), ver);
506
507     impl::tree_node_to_xml(ostrm, tree, id_to_name);
508 }
509
510 template <typename CharT, typename TreeNodeT>
511 inline void
512 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
513         std::basic_string<CharT> const &input_line)
514 {
515     return basic_tree_to_xml<CharT>(ostrm, tree, input_line,
516         std::map<BOOST_SPIRIT_CLASSIC_NS::parser_id, std::basic_string<CharT> >());
517 }
518
519 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
520
521 }} // namespace boost::spirit
522
523 #undef BOOST_SPIRIT_OSSTREAM
524 #undef BOOST_SPIRIT_GETSTRING
525
526 #endif // !defined(PARSE_TREE_XML_HPP)