PageRenderTime 31ms CodeModel.GetById 18ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/spirit/home/classic/tree/impl/tree_to_xml.ipp

http://hadesmem.googlecode.com/
C++ Header | 526 lines | 433 code | 61 blank | 32 comment | 28 complexity | 45610af29f14851504256ad256800234 MD5 | raw file
  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
 28inline
 29std::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
 42namespace boost { namespace spirit {
 43
 44BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
 45
 46namespace 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
 86namespace 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
326namespace 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)
465template <
466    typename CharT, typename TreeNodeT, typename AssocContainerT,
467    typename GetIdT, typename GetValueT
468>
469inline void
470basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
471std::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)
490template <typename CharT, typename TreeNodeT, typename AssocContainerT>
491inline void
492basic_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
510template <typename CharT, typename TreeNodeT>
511inline void
512basic_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
519BOOST_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)