/*============================================================================= Copyright (c) 2001-2003 Hartmut Kaiser Copyright (c) 2001-2003 Daniel Nuffer http://spirit.sourceforge.net/ Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #if !defined(TREE_TO_XML_IPP) #define TREE_TO_XML_IPP #include #include #include #include #include #ifdef BOOST_NO_STRINGSTREAM #include #define BOOST_SPIRIT_OSSTREAM std::ostrstream std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss) { ss << ends; std::string rval = ss.str(); ss.freeze(false); return rval; } #else #include #define BOOST_SPIRIT_GETSTRING(ss) ss.str() #define BOOST_SPIRIT_OSSTREAM std::ostringstream #endif namespace boost { namespace spirit { // xml formatting helper classes namespace xml { inline void encode (std::string &str, char s, char const *r, int len) { std::string::size_type pos = 0; while ((pos = str.find_first_of (s, pos)) != std::string::size_type(std::string::npos)) { str.replace (pos, 1, r); pos += len; } } inline std::string encode (std::string str) { encode(str, '&', "&", 3); encode(str, '<', "<", 2); encode(str, '>', ">", 2); encode(str, '\r', "\\r", 1); encode(str, '\n', "\\n", 1); return str; } inline std::string encode (char const *text) { return encode (std::string(text)); } // format a xml attribute struct attribute { attribute() { } attribute (char const *key_, char const *value_) : key (key_), value(value_) { } bool has_value() { return value.size() > 0; } std::string key; std::string value; }; inline std::ostream& operator<< (std::ostream &ostrm, attribute const &attr) { if (0 == attr.key.size()) return ostrm; ostrm << " " << encode(attr.key) << "=\"" << encode(attr.value) << "\""; return ostrm; } // output a xml element (base class, not used directly) class element { protected: element(std::ostream &ostrm_, bool incr_indent_ = true) : ostrm(ostrm_), incr_indent(incr_indent_) { if (incr_indent) ++get_indent(); } ~element() { if (incr_indent) --get_indent(); } public: void output_space () { for (int i = 0; i < get_indent(); i++) ostrm << " "; } protected: int &get_indent() { static int indent; return indent; } std::ostream &ostrm; bool incr_indent; }; // a xml node class node : public element { public: node (std::ostream &ostrm_, char const *tag_, attribute &attr) : element(ostrm_), tag(tag_) { output_space(); ostrm << "<" << tag_ << attr << ">\n"; } node (std::ostream &ostrm_, char const *tag_) : element(ostrm_), tag(tag_) { output_space(); ostrm << "<" << tag_ << ">\n"; } ~node() { output_space(); ostrm << "\n"; } private: std::string tag; }; class text : public element { public: text (std::ostream &ostrm, char const *tag, char const *text) : element(ostrm) { output_space(); ostrm << "<" << tag << ">" << encode(text) << "\n"; } text (std::ostream &ostrm, char const *tag, char const *text, attribute &attr) : element(ostrm) { output_space(); ostrm << "<" << tag << attr << ">" << encode(text) << "\n"; } text (std::ostream &ostrm, char const *tag, char const *text, attribute &attr1, attribute &attr2) : element(ostrm) { output_space(); ostrm << "<" << tag << attr1 << attr2 << ">" << encode(text) << "\n"; } }; // a xml comment class comment : public element { public: comment (std::ostream &ostrm, char const *comment) : element(ostrm, false) { if ('\0' != comment[0]) { output_space(); ostrm << "\n"; } } }; // a xml document class document : public element { public: document (std::ostream &ostrm) : element(ostrm) { get_indent() = -1; ostrm << "\n"; } document (std::ostream &ostrm, char const *mainnode, char const *dtd) : element(ostrm) { get_indent() = -1; ostrm << "\n"; output_space(); ostrm << "\n"; } ~document() { BOOST_SPIRIT_ASSERT(-1 == get_indent()); } }; } // end of namespace xml namespace impl { // look up the rule name from the given parser_id template inline typename AssocContainerT::value_type::second_type get_rulename (AssocContainerT const &id_to_name_map, boost::spirit::parser_id const &id) { typename AssocContainerT::const_iterator it = id_to_name_map.find(id); if (it != id_to_name_map.end()) return (*it).second; typedef typename AssocContainerT::value_type::second_type second_t; return second_t(); } // dump a parse tree as xml template inline void token_to_xml (std::ostream &ostrm, IteratorT const &it, bool is_root, GetIdT const &get_token_id, GetValueT const &get_token_value) { BOOST_SPIRIT_OSSTREAM stream; stream << get_token_id(*it) << std::ends; xml::attribute token_id ("id", BOOST_SPIRIT_GETSTRING(stream).c_str()); xml::attribute is_root_attr ("is_root", is_root ? "1" : ""); xml::attribute nil; xml::text(ostrm, "token", get_token_value(*it).c_str(), token_id, is_root_attr.has_value() ? is_root_attr : nil); } template < typename TreeNodeT, typename AssocContainerT, typename GetIdT, typename GetValueT > inline void tree_node_to_xml (std::ostream &ostrm, TreeNodeT const &node, AssocContainerT const& id_to_name_map, GetIdT const &get_token_id, GetValueT const &get_token_value) { typedef typename TreeNodeT::const_iterator node_iter_t; typedef typename TreeNodeT::value_type::parse_node_t::const_iterator_t value_iter_t; xml::attribute nil; node_iter_t end = node.end(); for (node_iter_t it = node.begin(); it != end; ++it) { // output a node xml::attribute id ("rule", get_rulename(id_to_name_map, (*it).value.id()).c_str()); xml::node currnode (ostrm, "parsenode", (*it).value.id() != 0 && id.has_value() ? id : nil); // first dump the value std::size_t cnt = std::distance((*it).value.begin(), (*it).value.end()); if (1 == cnt) { token_to_xml (ostrm, (*it).value.begin(), (*it).value.is_root(), get_token_id, get_token_value); } else if (cnt > 1) { xml::node value (ostrm, "value"); bool is_root = (*it).value.is_root(); value_iter_t val_end = (*it).value.end(); for (value_iter_t val_it = (*it).value.begin(); val_it != val_end; ++val_it) { token_to_xml (ostrm, val_it, is_root, get_token_id, get_token_value); } } tree_node_to_xml(ostrm, (*it).children, id_to_name_map, get_token_id, get_token_value); // dump all subnodes } } template inline void tree_node_to_xml (std::ostream &ostrm, TreeNodeT const &node, AssocContainerT const& id_to_name_map) { typedef typename TreeNodeT::const_iterator node_iter_t; xml::attribute nil; node_iter_t end = node.end(); for (node_iter_t it = node.begin(); it != end; ++it) { // output a node xml::attribute id ("rule", get_rulename(id_to_name_map, (*it).value.id()).c_str()); xml::node currnode (ostrm, "parsenode", (*it).value.id() != parser_id() && id.has_value() ? id : nil); // first dump the value if ((*it).value.begin() != (*it).value.end()) { std::string tokens ((*it).value.begin(), (*it).value.end()); if (tokens.size() > 0) { // output all subtokens as one string (for better readability) xml::attribute is_root ("is_root", (*it).value.is_root() ? "1" : ""); xml::text(ostrm, "value", tokens.c_str(), is_root.has_value() ? is_root : nil); } } // dump all subnodes tree_node_to_xml(ostrm, (*it).children, id_to_name_map); } } } // namespace impl // dump a parse tree as a xml stream (generic variant) template < typename TreeNodeT, typename AssocContainerT, typename GetIdT, typename GetValueT > inline void tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree, std::string const &input_line, AssocContainerT const& id_to_name, GetIdT const &get_token_id, GetValueT const &get_token_value) { // generate xml dump xml::document doc (ostrm, "parsetree", "parsetree.dtd"); xml::comment input (ostrm, input_line.c_str()); xml::attribute ver ("version", "1.0"); xml::node mainnode (ostrm, "parsetree", ver); impl::tree_node_to_xml (ostrm, tree, id_to_name, get_token_id, get_token_value); } // dump a parse tree as a xml steam (for character based parsers) template inline void tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree, std::string const &input_line, AssocContainerT const& id_to_name) { // generate xml dump xml::document doc (ostrm, "parsetree", "parsetree.dtd"); xml::comment input (ostrm, input_line.c_str()); xml::attribute ver ("version", "1.0"); xml::node mainnode (ostrm, "parsetree", ver); impl::tree_node_to_xml (ostrm, tree, id_to_name); } template inline void tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree, std::string const &input_line) { return tree_to_xml(ostrm, tree, input_line, std::map()); } }} // namespace boost::spirit #undef BOOST_SPIRIT_OSSTREAM #undef BOOST_SPIRIT_GETSTRING #endif // !defined(PARSE_TREE_XML_HPP)