1 /*=============================================================================
2 Copyright (c) 2001-2008 Hartmut Kaiser
3 Copyright (c) 2001-2003 Daniel Nuffer
4 http://spirit.sourceforge.net/
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 =============================================================================*/
11 #if !defined(TREE_TO_XML_IPP)
12 #define TREE_TO_XML_IPP
22 #include <boost/config.hpp>
23 #include <boost/assert.hpp>
25 #ifdef BOOST_NO_STRINGSTREAM
27 #define BOOST_SPIRIT_OSSTREAM std::ostrstream
29 std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss)
32 std::string rval = ss.str();
38 #define BOOST_SPIRIT_GETSTRING(ss) ss.str()
39 #define BOOST_SPIRIT_OSSTREAM std::basic_ostringstream<CharT>
42 namespace boost { namespace spirit {
44 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
48 ///////////////////////////////////////////////////////////////////////////
49 template <typename CharT>
53 struct string_lit<char>
55 static char get(char c) { return c; }
56 static std::string get(char const* str = "") { return str; }
60 struct string_lit<wchar_t>
62 static wchar_t get(char c)
64 typedef std::ctype<wchar_t> ctype_t;
65 return std::use_facet<ctype_t>(std::locale()).widen(c);
67 static std::basic_string<wchar_t> get(char const* source = "")
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';
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()));
78 std::use_facet<std::ctype<wchar_t> >(std::locale())
79 .widen(source, source + len, result.get());
85 // xml formatting helper classes
88 template <typename CharT>
90 encode (std::basic_string<CharT> &str, char s, char const *r, int len)
92 typedef typename std::basic_string<CharT>::size_type size_type;
95 while ((pos = str.find_first_of (impl::string_lit<CharT>::get(s), pos)) !=
96 size_type(std::basic_string<CharT>::npos))
98 str.replace (pos, 1, impl::string_lit<CharT>::get(r));
103 template <typename CharT>
104 inline std::basic_string<CharT>
105 encode (std::basic_string<CharT> str)
107 encode(str, '&', "&", 3);
108 encode(str, '<', "<", 2);
109 encode(str, '>', ">", 2);
110 encode(str, '\r', "\\r", 1);
111 encode(str, '\n', "\\n", 1);
115 template <typename CharT>
116 inline std::basic_string<CharT>
117 encode (CharT const *text)
119 return encode (std::basic_string<CharT>(text));
122 // format a xml attribute
123 template <typename CharT>
130 attribute (std::basic_string<CharT> const& key_,
131 std::basic_string<CharT> const& value_)
132 : key (key_), value(value_)
138 return value.size() > 0;
141 std::basic_string<CharT> key;
142 std::basic_string<CharT> value;
145 template <typename CharT>
146 inline std::basic_ostream<CharT>&
147 operator<< (std::basic_ostream<CharT> &ostrm, attribute<CharT> const &attr)
149 if (0 == attr.key.size())
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("\"");
157 // output a xml element (base class, not used directly)
158 template <typename CharT>
162 element(std::basic_ostream<CharT> &ostrm_, bool incr_indent_ = true)
163 : ostrm(ostrm_), incr_indent(incr_indent_)
165 if (incr_indent) ++get_indent();
169 if (incr_indent) --get_indent();
175 for (int i = 0; i < get_indent(); i++)
176 ostrm << impl::string_lit<CharT>::get(" ");
187 std::basic_ostream<CharT> &ostrm;
192 template <typename CharT>
193 class node : public element<CharT>
196 node (std::basic_ostream<CharT> &ostrm_,
197 std::basic_string<CharT> const& tag_, attribute<CharT> &attr)
198 : element<CharT>(ostrm_), tag(tag_)
200 this->output_space();
202 << impl::string_lit<CharT>::get("<") << tag_ << attr
203 << impl::string_lit<CharT>::get(">\n");
205 node (std::basic_ostream<CharT> &ostrm_,
206 std::basic_string<CharT> const& tag_)
207 : element<CharT>(ostrm_), tag(tag_)
209 this->output_space();
211 << impl::string_lit<CharT>::get("<") << tag_
212 << impl::string_lit<CharT>::get(">\n");
216 this->output_space();
218 << impl::string_lit<CharT>::get("</") << tag
219 << impl::string_lit<CharT>::get(">\n");
223 std::basic_string<CharT> tag;
226 template <typename CharT>
227 class text : public element<CharT>
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_)
235 this->output_space();
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");
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_)
249 this->output_space();
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");
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_)
263 this->output_space();
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");
273 template <typename CharT>
274 class comment : public element<CharT>
277 comment (std::basic_ostream<CharT> &ostrm_,
278 std::basic_string<CharT> const& commentlit)
279 : element<CharT>(ostrm_, false)
281 if ('\0' != commentlit[0])
283 this->output_space();
284 this->ostrm << impl::string_lit<CharT>::get("<!-- ")
285 << encode(commentlit)
286 << impl::string_lit<CharT>::get(" -->\n");
292 template <typename CharT>
293 class document : public element<CharT>
296 document (std::basic_ostream<CharT> &ostrm_)
297 : element<CharT>(ostrm_)
299 this->get_indent() = -1;
300 this->ostrm << impl::string_lit<CharT>::get(
301 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
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_)
309 this->get_indent() = -1;
310 this->ostrm << impl::string_lit<CharT>::get(
311 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
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");
320 BOOST_SPIRIT_ASSERT(-1 == this->get_indent());
324 } // end of namespace xml
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)
335 typename AssocContainerT::const_iterator it = id_to_name_map.find(id);
336 if (it != id_to_name_map.end())
338 typedef typename AssocContainerT::value_type::second_type second_t;
342 // dump a parse tree as xml
344 typename CharT, typename IteratorT, typename GetIdT, typename GetValueT
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)
350 BOOST_SPIRIT_OSSTREAM stream;
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(),
364 is_root_attr.has_value() ? is_root_attr : nil);
368 typename CharT, typename TreeNodeT, typename AssocContainerT,
369 typename GetIdT, typename GetValueT
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)
376 typedef typename TreeNodeT::const_iterator node_iter_t;
378 typename TreeNodeT::value_type::parse_node_t::const_iterator_t
381 xml::attribute<CharT> nil;
382 node_iter_t end = node.end();
383 for (node_iter_t it = node.begin(); it != end; ++it)
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);
393 // first dump the value
394 std::size_t cnt = std::distance((*it).value.begin(), (*it).value.end());
398 token_to_xml (ostrm, (*it).value.begin(),
399 (*it).value.is_root(), get_token_id, get_token_value);
403 xml::node<CharT> value (ostrm,
404 impl::string_lit<CharT>::get("value"));
405 bool is_root = (*it).value.is_root();
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)
411 token_to_xml (ostrm, val_it, is_root, get_token_id,
415 tree_node_to_xml(ostrm, (*it).children, id_to_name_map,
416 get_token_id, get_token_value); // dump all subnodes
420 template <typename CharT, typename TreeNodeT, typename AssocContainerT>
422 tree_node_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &node,
423 AssocContainerT const& id_to_name_map)
425 typedef typename TreeNodeT::const_iterator node_iter_t;
427 xml::attribute<CharT> nil;
428 node_iter_t end = node.end();
429 for (node_iter_t it = node.begin(); it != end; ++it)
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);
439 // first dump the value
440 if ((*it).value.begin() != (*it).value.end())
442 std::basic_string<CharT> tokens ((*it).value.begin(), (*it).value.end());
444 if (tokens.size() > 0)
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);
457 tree_node_to_xml(ostrm, (*it).children, id_to_name_map);
463 ///////////////////////////////////////////////////////////////////////////////
464 // dump a parse tree as a xml stream (generic variant)
466 typename CharT, typename TreeNodeT, typename AssocContainerT,
467 typename GetIdT, typename GetValueT
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)
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);
485 impl::tree_node_to_xml (ostrm, tree, id_to_name, get_token_id,
489 // dump a parse tree as a xml steam (for character based parsers)
490 template <typename CharT, typename TreeNodeT, typename AssocContainerT>
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)
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);
507 impl::tree_node_to_xml(ostrm, tree, id_to_name);
510 template <typename CharT, typename TreeNodeT>
512 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
513 std::basic_string<CharT> const &input_line)
515 return basic_tree_to_xml<CharT>(ostrm, tree, input_line,
516 std::map<BOOST_SPIRIT_CLASSIC_NS::parser_id, std::basic_string<CharT> >());
519 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
521 }} // namespace boost::spirit
523 #undef BOOST_SPIRIT_OSSTREAM
524 #undef BOOST_SPIRIT_GETSTRING
526 #endif // !defined(PARSE_TREE_XML_HPP)