source: NonGTP/Boost/boost/spirit/tree/impl/tree_to_xml.ipp @ 857

Revision 857, 11.9 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Copyright (c) 2001-2003 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
17#include <map>
18#include <iostream>
19#include <boost/config.hpp>
20#ifdef BOOST_NO_STRINGSTREAM
21#include <strstream>
22#define BOOST_SPIRIT_OSSTREAM std::ostrstream
23inline std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss)
24{
25    ss << ends;
26    std::string rval = ss.str();
27    ss.freeze(false);
28    return rval;
29}
30#else
31#include <sstream>
32#define BOOST_SPIRIT_GETSTRING(ss) ss.str()
33#define BOOST_SPIRIT_OSSTREAM std::ostringstream
34#endif
35
36namespace boost { namespace spirit {
37
38// xml formatting helper classes
39namespace xml {
40
41    inline void
42    encode (std::string &str, char s, char const *r, int len)
43    {
44        std::string::size_type pos = 0;
45        while ((pos = str.find_first_of (s, pos)) !=
46        std::string::size_type(std::string::npos))
47        {
48            str.replace (pos, 1, r);
49            pos += len;
50        }
51    }
52
53    inline std::string
54    encode (std::string str)
55    {
56        encode(str, '&', "&amp;", 3);
57        encode(str, '<', "&lt;", 2);
58        encode(str, '>', "&gt;", 2);
59        encode(str, '\r', "\\r", 1);
60        encode(str, '\n', "\\n", 1);
61        return str;
62    }
63
64    inline std::string
65    encode (char const *text)
66    {
67        return encode (std::string(text));
68    }
69
70    // format a xml attribute
71    struct attribute
72    {
73        attribute()
74        {
75        }
76
77        attribute (char const *key_, char const *value_) :
78        key (key_), value(value_)
79        {
80        }
81
82        bool has_value()
83        {
84            return value.size() > 0;
85        }
86
87        std::string key;
88        std::string value;
89    };
90
91    inline std::ostream&
92    operator<< (std::ostream &ostrm, attribute const &attr)
93    {
94        if (0 == attr.key.size())
95            return ostrm;
96        ostrm << " " << encode(attr.key) << "=\"" << encode(attr.value) << "\"";
97        return ostrm;
98    }
99
100    // output a xml element (base class, not used directly)
101    class element
102    {
103    protected:
104        element(std::ostream &ostrm_, bool incr_indent_ = true) :
105        ostrm(ostrm_), incr_indent(incr_indent_)
106        {
107            if (incr_indent) ++get_indent();
108        }
109        ~element()
110        {
111            if (incr_indent) --get_indent();
112        }
113
114    public:
115        void output_space ()
116        {
117            for (int i = 0; i < get_indent(); i++)
118                ostrm << "    ";
119        }
120
121    protected:
122        int &get_indent()
123        {
124            static int indent;
125
126            return indent;
127        }
128
129        std::ostream &ostrm;
130        bool incr_indent;
131    };
132
133    // a xml node
134    class node : public element
135    {
136    public:
137        node (std::ostream &ostrm_, char const *tag_, attribute &attr) :
138        element(ostrm_), tag(tag_)
139        {
140            output_space();
141            ostrm << "<" << tag_ << attr << ">\n";
142        }
143        node (std::ostream &ostrm_, char const *tag_) :
144        element(ostrm_), tag(tag_)
145        {
146            output_space();
147            ostrm << "<" << tag_ << ">\n";
148        }
149        ~node()
150        {
151            output_space();
152            ostrm << "</" << tag << ">\n";
153        }
154
155    private:
156        std::string tag;
157    };
158
159    class text : public element
160    {
161    public:
162        text (std::ostream &ostrm, char const *tag, char const *text) :
163        element(ostrm)
164        {
165            output_space();
166            ostrm << "<" << tag << ">" << encode(text)
167            << "</" << tag << ">\n";
168        }
169
170        text (std::ostream &ostrm, char const *tag, char const *text,
171                attribute &attr) :
172            element(ostrm)
173        {
174            output_space();
175            ostrm << "<" << tag << attr << ">" << encode(text)
176            << "</" << tag << ">\n";
177        }
178
179        text (std::ostream &ostrm, char const *tag, char const *text,
180                attribute &attr1, attribute &attr2) :
181            element(ostrm)
182        {
183            output_space();
184            ostrm << "<" << tag << attr1 << attr2 << ">" << encode(text)
185            << "</" << tag << ">\n";
186        }
187    };
188
189    // a xml comment
190    class comment : public element
191    {
192    public:
193        comment (std::ostream &ostrm, char const *comment) :
194            element(ostrm, false)
195        {
196            if ('\0' != comment[0])
197            {
198                output_space();
199                ostrm << "<!-- " << encode(comment) << " -->\n";
200            }
201        }
202    };
203
204    // a xml document
205    class document : public element
206    {
207    public:
208        document (std::ostream &ostrm) : element(ostrm)
209        {
210            get_indent() = -1;
211            ostrm << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
212        }
213
214        document (std::ostream &ostrm, char const *mainnode, char const *dtd) :
215            element(ostrm)
216        {
217            get_indent() = -1;
218            ostrm << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
219
220            output_space();
221            ostrm << "<!DOCTYPE " << mainnode << " SYSTEM \"" << dtd
222            << "\">\n";
223        }
224        ~document()
225        {
226            BOOST_SPIRIT_ASSERT(-1 == get_indent());
227        }
228    };
229
230} // end of namespace xml
231
232namespace impl {
233
234    // look up the rule name from the given parser_id
235    template <typename AssocContainerT>
236    inline typename AssocContainerT::value_type::second_type
237    get_rulename (AssocContainerT const &id_to_name_map,
238        boost::spirit::parser_id const &id)
239    {
240        typename AssocContainerT::const_iterator it = id_to_name_map.find(id);
241        if (it != id_to_name_map.end())
242            return (*it).second;
243        typedef typename AssocContainerT::value_type::second_type second_t;
244        return second_t();
245    }
246
247    // dump a parse tree as xml
248    template <typename IteratorT, typename GetIdT, typename GetValueT>
249    inline void
250    token_to_xml (std::ostream &ostrm, IteratorT const &it, bool is_root,
251        GetIdT const &get_token_id, GetValueT const &get_token_value)
252    {
253        BOOST_SPIRIT_OSSTREAM stream;
254
255        stream << get_token_id(*it) << std::ends;
256        xml::attribute token_id ("id", BOOST_SPIRIT_GETSTRING(stream).c_str());
257        xml::attribute is_root_attr ("is_root", is_root ? "1" : "");
258        xml::attribute nil;
259        xml::text(ostrm, "token", get_token_value(*it).c_str(),
260            token_id, is_root_attr.has_value() ? is_root_attr : nil);
261    }
262
263    template <
264        typename TreeNodeT, typename AssocContainerT,
265        typename GetIdT, typename GetValueT
266    >
267    inline void
268    tree_node_to_xml (std::ostream &ostrm, TreeNodeT const &node,
269        AssocContainerT const& id_to_name_map, GetIdT const &get_token_id,
270        GetValueT const &get_token_value)
271    {
272        typedef typename TreeNodeT::const_iterator node_iter_t;
273        typedef
274            typename TreeNodeT::value_type::parse_node_t::const_iterator_t
275            value_iter_t;
276
277        xml::attribute nil;
278        node_iter_t end = node.end();
279        for (node_iter_t it = node.begin(); it != end; ++it)
280        {
281            // output a node
282            xml::attribute id ("rule",
283                get_rulename(id_to_name_map, (*it).value.id()).c_str());
284            xml::node currnode (ostrm, "parsenode",
285                (*it).value.id() != 0 && id.has_value() ? id : nil);
286
287            // first dump the value
288            std::size_t cnt = std::distance((*it).value.begin(), (*it).value.end());
289
290            if (1 == cnt)
291            {
292                token_to_xml (ostrm, (*it).value.begin(),
293                    (*it).value.is_root(), get_token_id, get_token_value);
294            }
295            else if (cnt > 1)
296            {
297                xml::node value (ostrm, "value");
298                bool is_root = (*it).value.is_root();
299
300                value_iter_t val_end = (*it).value.end();
301                for (value_iter_t val_it = (*it).value.begin();
302                val_it != val_end; ++val_it)
303                {
304                    token_to_xml (ostrm, val_it, is_root, get_token_id,
305                        get_token_value);
306                }
307            }
308            tree_node_to_xml(ostrm, (*it).children, id_to_name_map,
309                get_token_id, get_token_value);      // dump all subnodes
310        }
311    }
312
313    template <typename TreeNodeT, typename AssocContainerT>
314    inline void
315    tree_node_to_xml (std::ostream &ostrm, TreeNodeT const &node,
316            AssocContainerT const& id_to_name_map)
317    {
318        typedef typename TreeNodeT::const_iterator node_iter_t;
319
320        xml::attribute nil;
321        node_iter_t end = node.end();
322        for (node_iter_t it = node.begin(); it != end; ++it)
323        {
324            // output a node
325            xml::attribute id ("rule",
326                get_rulename(id_to_name_map, (*it).value.id()).c_str());
327            xml::node currnode (ostrm, "parsenode",
328                (*it).value.id() != parser_id() && id.has_value() ? id : nil);
329
330            // first dump the value
331            if ((*it).value.begin() != (*it).value.end())
332            {
333                std::string tokens ((*it).value.begin(), (*it).value.end());
334
335                if (tokens.size() > 0)
336                {
337                    // output all subtokens as one string (for better readability)
338                    xml::attribute is_root ("is_root",
339                        (*it).value.is_root() ? "1" : "");
340                    xml::text(ostrm, "value", tokens.c_str(),
341                        is_root.has_value() ? is_root : nil);
342                }
343
344            }
345            // dump all subnodes
346            tree_node_to_xml(ostrm, (*it).children, id_to_name_map);
347        }
348    }
349
350} // namespace impl
351
352// dump a parse tree as a xml stream (generic variant)
353template <
354    typename TreeNodeT, typename AssocContainerT,
355    typename GetIdT, typename GetValueT
356>
357inline void
358tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree,
359std::string const &input_line, AssocContainerT const& id_to_name,
360        GetIdT const &get_token_id, GetValueT const &get_token_value)
361{
362    // generate xml dump
363    xml::document doc (ostrm, "parsetree", "parsetree.dtd");
364    xml::comment input (ostrm, input_line.c_str());
365    xml::attribute ver ("version", "1.0");
366    xml::node mainnode (ostrm, "parsetree", ver);
367
368    impl::tree_node_to_xml (ostrm, tree, id_to_name, get_token_id,
369        get_token_value);
370}
371
372// dump a parse tree as a xml steam (for character based parsers)
373template <typename TreeNodeT, typename AssocContainerT>
374inline void
375tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree,
376        std::string const &input_line, AssocContainerT const& id_to_name)
377{
378    // generate xml dump
379    xml::document doc (ostrm, "parsetree", "parsetree.dtd");
380    xml::comment input (ostrm, input_line.c_str());
381    xml::attribute ver ("version", "1.0");
382    xml::node mainnode (ostrm, "parsetree", ver);
383
384    impl::tree_node_to_xml (ostrm, tree, id_to_name);
385}
386
387template <typename TreeNodeT>
388inline void
389tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree,
390        std::string const &input_line)
391{
392    return tree_to_xml(ostrm, tree, input_line,
393        std::map<boost::spirit::parser_id, std::string>());
394}
395
396}} // namespace boost::spirit
397
398#undef BOOST_SPIRIT_OSSTREAM
399#undef BOOST_SPIRIT_GETSTRING
400
401#endif // !defined(PARSE_TREE_XML_HPP)
Note: See TracBrowser for help on using the repository browser.