/*=============================================================================
|
Copyright (c) 2001-2008 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)
|
=============================================================================*/
|
|
#ifndef BOOST_SPIRIT_CLASSIC_TREE_IMPL_TREE_TO_XML_IPP
|
#define BOOST_SPIRIT_CLASSIC_TREE_IMPL_TREE_TO_XML_IPP
|
|
#include <cstdio>
|
#include <cstdarg>
|
#include <locale>
|
#include <string>
|
#include <cstring>
|
|
#include <map>
|
#include <iostream>
|
#include <boost/config.hpp>
|
#include <boost/assert.hpp>
|
#include <boost/scoped_array.hpp>
|
|
#ifdef BOOST_NO_STRINGSTREAM
|
#include <strstream>
|
#define BOOST_SPIRIT_OSSTREAM std::ostrstream
|
inline
|
std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss)
|
{
|
ss << std::ends;
|
std::string rval = ss.str();
|
ss.freeze(false);
|
return rval;
|
}
|
#else
|
#include <sstream>
|
#define BOOST_SPIRIT_GETSTRING(ss) ss.str()
|
#define BOOST_SPIRIT_OSSTREAM std::basic_ostringstream<CharT>
|
#endif
|
|
namespace boost { namespace spirit {
|
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
|
namespace impl {
|
|
///////////////////////////////////////////////////////////////////////////
|
template <typename CharT>
|
struct string_lit;
|
|
template <>
|
struct string_lit<char>
|
{
|
static char get(char c) { return c; }
|
static std::string get(char const* str = "") { return str; }
|
};
|
|
template <>
|
struct string_lit<wchar_t>
|
{
|
static wchar_t get(char c)
|
{
|
typedef std::ctype<wchar_t> ctype_t;
|
return std::use_facet<ctype_t>(std::locale()).widen(c);
|
}
|
static std::basic_string<wchar_t> get(char const* source = "")
|
{
|
using namespace std; // some systems have size_t in ns std
|
size_t len = strlen(source);
|
boost::scoped_array<wchar_t> result (new wchar_t[len+1]);
|
result.get()[len] = '\0';
|
|
// working with wide character streams is supported only if the
|
// platform provides the std::ctype<wchar_t> facet
|
BOOST_ASSERT(std::has_facet<std::ctype<wchar_t> >(std::locale()));
|
|
std::use_facet<std::ctype<wchar_t> >(std::locale())
|
.widen(source, source + len, result.get());
|
return result.get();
|
}
|
};
|
}
|
|
// xml formatting helper classes
|
namespace xml {
|
|
template <typename CharT>
|
inline void
|
encode (std::basic_string<CharT> &str, char s, char const *r, int len)
|
{
|
typedef typename std::basic_string<CharT>::size_type size_type;
|
|
size_type pos = 0;
|
while ((pos = str.find_first_of (impl::string_lit<CharT>::get(s), pos)) !=
|
size_type(std::basic_string<CharT>::npos))
|
{
|
str.replace (pos, 1, impl::string_lit<CharT>::get(r));
|
pos += len;
|
}
|
}
|
|
template <typename CharT>
|
inline std::basic_string<CharT>
|
encode (std::basic_string<CharT> str)
|
{
|
encode(str, '&', "&", 3);
|
encode(str, '<', "<", 2);
|
encode(str, '>', ">", 2);
|
encode(str, '\r', "\\r", 1);
|
encode(str, '\n', "\\n", 1);
|
return str;
|
}
|
|
template <typename CharT>
|
inline std::basic_string<CharT>
|
encode (CharT const *text)
|
{
|
return encode (std::basic_string<CharT>(text));
|
}
|
|
// format a xml attribute
|
template <typename CharT>
|
struct attribute
|
{
|
attribute()
|
{
|
}
|
|
attribute (std::basic_string<CharT> const& key_,
|
std::basic_string<CharT> const& value_)
|
: key (key_), value(value_)
|
{
|
}
|
|
bool has_value()
|
{
|
return value.size() > 0;
|
}
|
|
std::basic_string<CharT> key;
|
std::basic_string<CharT> value;
|
};
|
|
template <typename CharT>
|
inline std::basic_ostream<CharT>&
|
operator<< (std::basic_ostream<CharT> &ostrm, attribute<CharT> const &attr)
|
{
|
if (0 == attr.key.size())
|
return ostrm;
|
ostrm << impl::string_lit<CharT>::get(" ") << encode(attr.key)
|
<< impl::string_lit<CharT>::get("=\"") << encode(attr.value)
|
<< impl::string_lit<CharT>::get("\"");
|
return ostrm;
|
}
|
|
// output a xml element (base class, not used directly)
|
template <typename CharT>
|
class element
|
{
|
protected:
|
element(std::basic_ostream<CharT> &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 << impl::string_lit<CharT>::get(" ");
|
}
|
|
protected:
|
int &get_indent()
|
{
|
static int indent;
|
|
return indent;
|
}
|
|
std::basic_ostream<CharT> &ostrm;
|
bool incr_indent;
|
};
|
|
// a xml node
|
template <typename CharT>
|
class node : public element<CharT>
|
{
|
public:
|
node (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& tag_, attribute<CharT> &attr)
|
: element<CharT>(ostrm_), tag(tag_)
|
{
|
this->output_space();
|
this->ostrm
|
<< impl::string_lit<CharT>::get("<") << tag_ << attr
|
<< impl::string_lit<CharT>::get(">\n");
|
}
|
node (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& tag_)
|
: element<CharT>(ostrm_), tag(tag_)
|
{
|
this->output_space();
|
this->ostrm
|
<< impl::string_lit<CharT>::get("<") << tag_
|
<< impl::string_lit<CharT>::get(">\n");
|
}
|
~node()
|
{
|
this->output_space();
|
this->ostrm
|
<< impl::string_lit<CharT>::get("</") << tag
|
<< impl::string_lit<CharT>::get(">\n");
|
}
|
|
private:
|
std::basic_string<CharT> tag;
|
};
|
|
template <typename CharT>
|
class text : public element<CharT>
|
{
|
public:
|
text (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& tag,
|
std::basic_string<CharT> const& textlit)
|
: element<CharT>(ostrm_)
|
{
|
this->output_space();
|
this->ostrm
|
<< impl::string_lit<CharT>::get("<") << tag
|
<< impl::string_lit<CharT>::get(">") << encode(textlit)
|
<< impl::string_lit<CharT>::get("</") << tag
|
<< impl::string_lit<CharT>::get(">\n");
|
}
|
|
text (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& tag,
|
std::basic_string<CharT> const& textlit,
|
attribute<CharT> &attr)
|
: element<CharT>(ostrm_)
|
{
|
this->output_space();
|
this->ostrm
|
<< impl::string_lit<CharT>::get("<") << tag << attr
|
<< impl::string_lit<CharT>::get(">") << encode(textlit)
|
<< impl::string_lit<CharT>::get("</") << tag
|
<< impl::string_lit<CharT>::get(">\n");
|
}
|
|
text (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& tag,
|
std::basic_string<CharT> const& textlit,
|
attribute<CharT> &attr1, attribute<CharT> &attr2)
|
: element<CharT>(ostrm_)
|
{
|
this->output_space();
|
this->ostrm
|
<< impl::string_lit<CharT>::get("<") << tag << attr1 << attr2
|
<< impl::string_lit<CharT>::get(">") << encode(textlit)
|
<< impl::string_lit<CharT>::get("</") << tag
|
<< impl::string_lit<CharT>::get(">\n");
|
}
|
};
|
|
// a xml comment
|
template <typename CharT>
|
class comment : public element<CharT>
|
{
|
public:
|
comment (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& commentlit)
|
: element<CharT>(ostrm_, false)
|
{
|
if ('\0' != commentlit[0])
|
{
|
this->output_space();
|
this->ostrm << impl::string_lit<CharT>::get("<!-- ")
|
<< encode(commentlit)
|
<< impl::string_lit<CharT>::get(" -->\n");
|
}
|
}
|
};
|
|
// a xml document
|
template <typename CharT>
|
class document : public element<CharT>
|
{
|
public:
|
document (std::basic_ostream<CharT> &ostrm_)
|
: element<CharT>(ostrm_)
|
{
|
this->get_indent() = -1;
|
this->ostrm << impl::string_lit<CharT>::get(
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
|
}
|
|
document (std::basic_ostream<CharT> &ostrm_,
|
std::basic_string<CharT> const& mainnode,
|
std::basic_string<CharT> const& dtd)
|
: element<CharT>(ostrm_)
|
{
|
this->get_indent() = -1;
|
this->ostrm << impl::string_lit<CharT>::get(
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
|
|
this->output_space();
|
this->ostrm << impl::string_lit<CharT>::get("<!DOCTYPE ") << mainnode
|
<< impl::string_lit<CharT>::get(" SYSTEM \"") << dtd
|
<< impl::string_lit<CharT>::get("\">\n");
|
}
|
~document()
|
{
|
BOOST_SPIRIT_ASSERT(-1 == this->get_indent());
|
}
|
};
|
|
} // end of namespace xml
|
|
namespace impl {
|
|
///////////////////////////////////////////////////////////////////////////
|
// look up the rule name from the given parser_id
|
template <typename AssocContainerT>
|
inline typename AssocContainerT::value_type::second_type
|
get_rulename (AssocContainerT const &id_to_name_map,
|
BOOST_SPIRIT_CLASSIC_NS::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 <
|
typename CharT, typename IteratorT, typename GetIdT, typename GetValueT
|
>
|
inline void
|
token_to_xml (std::basic_ostream<CharT> &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<CharT> token_id (
|
impl::string_lit<CharT>::get("id"),
|
BOOST_SPIRIT_GETSTRING(stream).c_str());
|
xml::attribute<CharT> is_root_attr (
|
impl::string_lit<CharT>::get("is_root"),
|
impl::string_lit<CharT>::get(is_root ? "1" : ""));
|
xml::attribute<CharT> nil;
|
xml::text<CharT>(ostrm,
|
impl::string_lit<CharT>::get("token"),
|
get_token_value(*it).c_str(),
|
token_id,
|
is_root_attr.has_value() ? is_root_attr : nil);
|
}
|
|
template <
|
typename CharT, typename TreeNodeT, typename AssocContainerT,
|
typename GetIdT, typename GetValueT
|
>
|
inline void
|
tree_node_to_xml (std::basic_ostream<CharT> &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<CharT> nil;
|
node_iter_t end = node.end();
|
for (node_iter_t it = node.begin(); it != end; ++it)
|
{
|
// output a node
|
xml::attribute<CharT> id (
|
impl::string_lit<CharT>::get("rule"),
|
get_rulename(id_to_name_map, (*it).value.id()).c_str());
|
xml::node<CharT> currnode (ostrm,
|
impl::string_lit<CharT>::get("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<CharT> value (ostrm,
|
impl::string_lit<CharT>::get("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 <typename CharT, typename TreeNodeT, typename AssocContainerT>
|
inline void
|
tree_node_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &node,
|
AssocContainerT const& id_to_name_map)
|
{
|
typedef typename TreeNodeT::const_iterator node_iter_t;
|
|
xml::attribute<CharT> nil;
|
node_iter_t end = node.end();
|
for (node_iter_t it = node.begin(); it != end; ++it)
|
{
|
// output a node
|
xml::attribute<CharT> id (
|
impl::string_lit<CharT>::get("rule"),
|
get_rulename(id_to_name_map, (*it).value.id()).c_str());
|
xml::node<CharT> currnode (ostrm,
|
impl::string_lit<CharT>::get("parsenode"),
|
(*it).value.id() != parser_id() && id.has_value() ? id : nil);
|
|
// first dump the value
|
if ((*it).value.begin() != (*it).value.end())
|
{
|
std::basic_string<CharT> tokens ((*it).value.begin(), (*it).value.end());
|
|
if (tokens.size() > 0)
|
{
|
// output all subtokens as one string (for better readability)
|
xml::attribute<CharT> is_root (
|
impl::string_lit<CharT>::get("is_root"),
|
impl::string_lit<CharT>::get((*it).value.is_root() ? "1" : ""));
|
xml::text<CharT>(ostrm,
|
impl::string_lit<CharT>::get("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 CharT, typename TreeNodeT, typename AssocContainerT,
|
typename GetIdT, typename GetValueT
|
>
|
inline void
|
basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
|
std::basic_string<CharT> const &input_line, AssocContainerT const& id_to_name,
|
GetIdT const &get_token_id, GetValueT const &get_token_value)
|
{
|
// generate xml dump
|
xml::document<CharT> doc (ostrm,
|
impl::string_lit<CharT>::get("parsetree"),
|
impl::string_lit<CharT>::get("parsetree.dtd"));
|
xml::comment<CharT> input (ostrm, input_line.c_str());
|
xml::attribute<CharT> ver (
|
impl::string_lit<CharT>::get("version"),
|
impl::string_lit<CharT>::get("1.0"));
|
xml::node<CharT> mainnode (ostrm,
|
impl::string_lit<CharT>::get("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 <typename CharT, typename TreeNodeT, typename AssocContainerT>
|
inline void
|
basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
|
std::basic_string<CharT> const &input_line,
|
AssocContainerT const& id_to_name)
|
{
|
// generate xml dump
|
xml::document<CharT> doc (ostrm,
|
impl::string_lit<CharT>::get("parsetree"),
|
impl::string_lit<CharT>::get("parsetree.dtd"));
|
xml::comment<CharT> input (ostrm, input_line.c_str());
|
xml::attribute<CharT> ver (
|
impl::string_lit<CharT>::get("version"),
|
impl::string_lit<CharT>::get("1.0"));
|
xml::node<CharT> mainnode (ostrm,
|
impl::string_lit<CharT>::get("parsetree"), ver);
|
|
impl::tree_node_to_xml(ostrm, tree, id_to_name);
|
}
|
|
template <typename CharT, typename TreeNodeT>
|
inline void
|
basic_tree_to_xml (std::basic_ostream<CharT> &ostrm, TreeNodeT const &tree,
|
std::basic_string<CharT> const &input_line)
|
{
|
return basic_tree_to_xml<CharT>(ostrm, tree, input_line,
|
std::map<BOOST_SPIRIT_CLASSIC_NS::parser_id, std::basic_string<CharT> >());
|
}
|
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
|
}} // namespace boost::spirit
|
|
#undef BOOST_SPIRIT_OSSTREAM
|
#undef BOOST_SPIRIT_GETSTRING
|
|
#endif
|