Ticket #1480: tree_to_xml.ipp

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