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>
24 #include <boost/scoped_array.hpp>
26 #ifdef BOOST_NO_STRINGSTREAM
28 #define BOOST_SPIRIT_OSSTREAM std::ostrstream
30 std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss)
33 std::string rval = ss.str();
39 #define BOOST_SPIRIT_GETSTRING(ss) ss.str()
40 #define BOOST_SPIRIT_OSSTREAM std::basic_ostringstream<CharT>
43 namespace boost { namespace spirit {
45 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
49 ///////////////////////////////////////////////////////////////////////////
50 template <typename CharT>
54 struct string_lit<char>
56 static char get(char c) { return c; }
57 static std::string get(char const* str = "") { return str; }
61 struct string_lit<wchar_t>
63 static wchar_t get(char c)
65 typedef std::ctype<wchar_t> ctype_t;
66 return std::use_facet<ctype_t>(std::locale()).widen(c);
68 static std::basic_string<wchar_t> get(char const* source = "")
70 using namespace std; // some systems have size_t in ns std
71 size_t len = strlen(source);
72 boost::scoped_array<wchar_t> result (new wchar_t[len+1]);
73 result.get()[len] = '\0';
75 // working with wide character streams is supported only if the
76 // platform provides the std::ctype<wchar_t> facet
77 BOOST_ASSERT(std::has_facet<std::ctype<wchar_t> >(std::locale()));
79 std::use_facet<std::ctype<wchar_t> >(std::locale())
80 .widen(source, source + len, result.get());
86 // xml formatting helper classes
89 template <typename CharT>
91 encode (std::basic_string<CharT> &str, char s, char const *r, int len)
93 typedef typename std::basic_string<CharT>::size_type size_type;
96 while ((pos = str.find_first_of (impl::string_lit<CharT>::get(s), pos)) !=
97 size_type(std::basic_string<CharT>::npos))
99 str.replace (pos, 1, impl::string_lit<CharT>::get(r));
104 template <typename CharT>
105 inline std::basic_string<CharT>
106 encode (std::basic_string<CharT> str)
108 encode(str, '&', "&", 3);
109 encode(str, '<', "<", 2);
110 encode(str, '>', ">", 2);
111 encode(str, '\r', "\\r", 1);
112 encode(str, '\n', "\\n", 1);
116 template <typename CharT>
117 inline std::basic_string<CharT>
118 encode (CharT const *text)
120 return encode (std::basic_string<CharT>(text));
123 // format a xml attribute
124 template <typename CharT>
131 attribute (std::basic_string<CharT> const& key_,
132 std::basic_string<CharT> const& value_)
133 : key (key_), value(value_)
139 return value.size() > 0;
142 std::basic_string<CharT> key;
143 std::basic_string<CharT> value;
146 template <typename CharT>
147 inline std::basic_ostream<CharT>&
148 operator<< (std::basic_ostream<CharT> &ostrm, attribute<CharT> const &attr)
150 if (0 == attr.key.size())
152 ostrm << impl::string_lit<CharT>::get(" ") << encode(attr.key)
153 << impl::string_lit<CharT>::get("=\"") << encode(attr.value)
154 << impl::string_lit<CharT>::get("\"");
158 // output a xml element (base class, not used directly)
159 template <typename CharT>
163 element(std::basic_ostream<CharT> &ostrm_, bool incr_indent_ = true)
164 : ostrm(ostrm_), incr_indent(incr_indent_)
166 if (incr_indent) ++get_indent();
170 if (incr_indent) --get_indent();
176 for (int i = 0; i < get_indent(); i++)
177 ostrm << impl::string_lit<CharT>::get(" ");
188 std::basic_ostream<CharT> &ostrm;
193 template <typename CharT>
194 class node : public element<CharT>
197 node (std::basic_ostream<CharT> &ostrm_,
198 std::basic_string<CharT> const& tag_, attribute<CharT> &attr)
199 : element<CharT>(ostrm_), tag(tag_)
201 this->output_space();
203 << impl::string_lit<CharT>::get("<") << tag_ << attr
204 << impl::string_lit<CharT>::get(">\n");
206 node (std::basic_ostream<CharT> &ostrm_,
207 std::basic_string<CharT> const& tag_)
208 : element<CharT>(ostrm_), tag(tag_)
210 this->output_space();
212 << impl::string_lit<CharT>::get("<") << tag_
213 << impl::string_lit<CharT>::get(">\n");
217 this->output_space();
219 << impl::string_lit<CharT>::get("</") << tag
220 << impl::string_lit<CharT>::get(">\n");
224 std::basic_string<CharT> tag;
227 template <typename CharT>
228 class text : public element<CharT>
231 text (std::basic_ostream<CharT> &ostrm_,
232 std::basic_string<CharT> const& tag,
233 std::basic_string<CharT> const& textlit)
234 : element<CharT>(ostrm_)
236 this->output_space();
238 << impl::string_lit<CharT>::get("<") << tag
239 << impl::string_lit<CharT>::get(">") << encode(textlit)
240 << impl::string_lit<CharT>::get("</") << tag
241 << impl::string_lit<CharT>::get(">\n");
244 text (std::basic_ostream<CharT> &ostrm_,
245 std::basic_string<CharT> const& tag,
246 std::basic_string<CharT> const& textlit,
247 attribute<CharT> &attr)
248 : element<CharT>(ostrm_)
250 this->output_space();
252 << impl::string_lit<CharT>::get("<") << tag << attr
253 << impl::string_lit<CharT>::get(">") << encode(textlit)
254 << impl::string_lit<CharT>::get("</") << tag
255 << impl::string_lit<CharT>::get(">\n");
258 text (std::basic_ostream<CharT> &ostrm_,
259 std::basic_string<CharT> const& tag,
260 std::basic_string<CharT> const& textlit,
261 attribute<CharT> &attr1, attribute<CharT> &attr2)
262 : element<CharT>(ostrm_)
264 this->output_space();
266 << impl::string_lit<CharT>::get("<") << tag << attr1 << attr2
267 << impl::string_lit<CharT>::get(">") << encode(textlit)
268 << impl::string_lit<CharT>::get("</") << tag
269 << impl::string_lit<CharT>::get(">\n");
274 template <typename CharT>
275 class comment : public element<CharT>
278 comment (std::basic_ostream<CharT> &ostrm_,
279 std::basic_string<CharT> const& commentlit)
280 : element<CharT>(ostrm_, false)
282 if ('\0' != commentlit[0])
284 this->output_space();
285 this->ostrm << impl::string_lit<CharT>::get("<!-- ")
286 << encode(commentlit)
287 << impl::string_lit<CharT>::get(" -->\n");
293 template <typename CharT>
294 class document : public element<CharT>
297 document (std::basic_ostream<CharT> &ostrm_)
298 : element<CharT>(ostrm_)
300 this->get_indent() = -1;
301 this->ostrm << impl::string_lit<CharT>::get(
302 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
305 document (std::basic_ostream<CharT> &ostrm_,
306 std::basic_string<CharT> const& mainnode,
307 std::basic_string<CharT> const& dtd)
308 : element<CharT>(ostrm_)
310 this->get_indent() = -1;
311 this->ostrm << impl::string_lit<CharT>::get(
312 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
314 this->output_space();
315 this->ostrm << impl::string_lit<CharT>::get("<!DOCTYPE ") << mainnode
316 << impl::string_lit<CharT>::get(" SYSTEM \"") << dtd
317 << impl::string_lit<CharT>::get("\">\n");
321 BOOST_SPIRIT_ASSERT(-1 == this->get_indent());
325 } // end of namespace xml
329 ///////////////////////////////////////////////////////////////////////////
330 // look up the rule name from the given parser_id
331 template <typename AssocContainerT>
332 inline typename AssocContainerT::value_type::second_type
333 get_rulename (AssocContainerT const &id_to_name_map,
334 BOOST_SPIRIT_CLASSIC_NS::parser_id const &id)
336 typename AssocContainerT::const_iterator it = id_to_name_map.find(id);
337 if (it != id_to_name_map.end())
339 typedef typename AssocContainerT::value_type::second_type second_t;
343 // dump a parse tree as xml
345 typename CharT, typename IteratorT, typename GetIdT, typename GetValueT
348 token_to_xml (std::basic_ostream<CharT> &ostrm, IteratorT const &it,
349 bool is_root, GetIdT const &get_token_id, GetValueT const &get_token_value)
351 BOOST_SPIRIT_OSSTREAM stream;
353 stream << get_token_id(*it) << std::ends;
354 xml::attribute<CharT> token_id (
355 impl::string_lit<CharT>::get("id"),
356 BOOST_SPIRIT_GETSTRING(stream).c_str());
357 xml::attribute<CharT> is_root_attr (
358 impl::string_lit<CharT>::get("is_root"),
359 impl::string_lit<CharT>::get(is_root ? "1" : ""));
360 xml::attribute<CharT> nil;
361 xml::text<CharT>(ostrm,
362 impl::string_lit<CharT>::get("token"),
363 get_token_value(*it).c_str(),
365 is_root_attr.has_value() ? is_root_attr : nil);
369 typename CharT, typename TreeNodeT, typename AssocContainerT,
370 typename GetIdT, typename GetValueT
373 tree_node_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &node,
374 AssocContainerT const& id_to_name_map, GetIdT const &get_token_id,
375 GetValueT const &get_token_value)
377 typedef typename TreeNodeT::const_iterator node_iter_t;
379 typename TreeNodeT::value_type::parse_node_t::const_iterator_t
382 xml::attribute<CharT> nil;
383 node_iter_t end = node.end();
384 for (node_iter_t it = node.begin(); it != end; ++it)
387 xml::attribute<CharT> id (
388 impl::string_lit<CharT>::get("rule"),
389 get_rulename(id_to_name_map, (*it).value.id()).c_str());
390 xml::node<CharT> currnode (ostrm,
391 impl::string_lit<CharT>::get("parsenode"),
392 (*it).value.id() != 0 && id.has_value() ? id : nil);
394 // first dump the value
395 std::size_t cnt = std::distance((*it).value.begin(), (*it).value.end());
399 token_to_xml (ostrm, (*it).value.begin(),
400 (*it).value.is_root(), get_token_id, get_token_value);
404 xml::node<CharT> value (ostrm,
405 impl::string_lit<CharT>::get("value"));
406 bool is_root = (*it).value.is_root();
408 value_iter_t val_end = (*it).value.end();
409 for (value_iter_t val_it = (*it).value.begin();
410 val_it != val_end; ++val_it)
412 token_to_xml (ostrm, val_it, is_root, get_token_id,
416 tree_node_to_xml(ostrm, (*it).children, id_to_name_map,
417 get_token_id, get_token_value); // dump all subnodes
421 template <typename CharT, typename TreeNodeT, typename AssocContainerT>
423 tree_node_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &node,
424 AssocContainerT const& id_to_name_map)
426 typedef typename TreeNodeT::const_iterator node_iter_t;
428 xml::attribute<CharT> nil;
429 node_iter_t end = node.end();
430 for (node_iter_t it = node.begin(); it != end; ++it)
433 xml::attribute<CharT> id (
434 impl::string_lit<CharT>::get("rule"),
435 get_rulename(id_to_name_map, (*it).value.id()).c_str());
436 xml::node<CharT> currnode (ostrm,
437 impl::string_lit<CharT>::get("parsenode"),
438 (*it).value.id() != parser_id() && id.has_value() ? id : nil);
440 // first dump the value
441 if ((*it).value.begin() != (*it).value.end())
443 std::basic_string<CharT> tokens ((*it).value.begin(), (*it).value.end());
445 if (tokens.size() > 0)
447 // output all subtokens as one string (for better readability)
448 xml::attribute<CharT> is_root (
449 impl::string_lit<CharT>::get("is_root"),
450 impl::string_lit<CharT>::get((*it).value.is_root() ? "1" : ""));
451 xml::text<CharT>(ostrm,
452 impl::string_lit<CharT>::get("value"), tokens.c_str(),
453 is_root.has_value() ? is_root : nil);
458 tree_node_to_xml(ostrm, (*it).children, id_to_name_map);
464 ///////////////////////////////////////////////////////////////////////////////
465 // dump a parse tree as a xml stream (generic variant)
467 typename CharT, typename TreeNodeT, typename AssocContainerT,
468 typename GetIdT, typename GetValueT
471 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
472 std::basic_string<CharT> const &input_line, AssocContainerT const& id_to_name,
473 GetIdT const &get_token_id, GetValueT const &get_token_value)
476 xml::document<CharT> doc (ostrm,
477 impl::string_lit<CharT>::get("parsetree"),
478 impl::string_lit<CharT>::get("parsetree.dtd"));
479 xml::comment<CharT> input (ostrm, input_line.c_str());
480 xml::attribute<CharT> ver (
481 impl::string_lit<CharT>::get("version"),
482 impl::string_lit<CharT>::get("1.0"));
483 xml::node<CharT> mainnode (ostrm,
484 impl::string_lit<CharT>::get("parsetree"), ver);
486 impl::tree_node_to_xml (ostrm, tree, id_to_name, get_token_id,
490 // dump a parse tree as a xml steam (for character based parsers)
491 template <typename CharT, typename TreeNodeT, typename AssocContainerT>
493 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
494 std::basic_string<CharT> const &input_line,
495 AssocContainerT const& id_to_name)
498 xml::document<CharT> doc (ostrm,
499 impl::string_lit<CharT>::get("parsetree"),
500 impl::string_lit<CharT>::get("parsetree.dtd"));
501 xml::comment<CharT> input (ostrm, input_line.c_str());
502 xml::attribute<CharT> ver (
503 impl::string_lit<CharT>::get("version"),
504 impl::string_lit<CharT>::get("1.0"));
505 xml::node<CharT> mainnode (ostrm,
506 impl::string_lit<CharT>::get("parsetree"), ver);
508 impl::tree_node_to_xml(ostrm, tree, id_to_name);
511 template <typename CharT, typename TreeNodeT>
513 basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
514 std::basic_string<CharT> const &input_line)
516 return basic_tree_to_xml<CharT>(ostrm, tree, input_line,
517 std::map<BOOST_SPIRIT_CLASSIC_NS::parser_id, std::basic_string<CharT> >());
520 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
522 }} // namespace boost::spirit
524 #undef BOOST_SPIRIT_OSSTREAM
525 #undef BOOST_SPIRIT_GETSTRING
527 #endif // !defined(PARSE_TREE_XML_HPP)