tree_to_xml.ipp 17 KB

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