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