提高精神难度,从XML示例工作

boost spirit difficulty, working from XML example

本文关键字:XML 工作 高精神      更新时间:2023-10-16

我正在尝试学习提升精神库。从 qi/karma XML 示例 (http://www.boost.org/doc/libs/1_50_0/libs/spirit/repository/example/karma/mini_xml_karma_sr.cpp( 开始,我尝试将 mini_xml 中的子容器更改为 std::vector 以外的内容(在本例中为 std::list,请在下面查找 mini_xml_children typedef(。不幸的是,这样做似乎无法编译。

编译错误似乎表明 phoenix 正在尝试将 std::list 分配给 std::vector,我在解释这个问题时遇到了一点麻烦,因为我的代码中不再有任何对 std::vector 的引用。我做了一些挖掘 - 看起来像 boost::spirit::karma::action::generate 决定在内部使用 std::vector,而不是检测mini_xml使用的容器。

如果我的假设是正确的,我认为我需要一种更明确地传达"属性"应该是什么的方法。有没有简单的方法可以做到这一点?理想情况下,我希望这段代码与容器无关。

代码:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
//[mini_xml_karma_sr_includes
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/repository/include/karma_subrule.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
//]
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <iostream>
#include <fstream>
#include <string>
//[mini_xml_karma_sr_using
using namespace boost::spirit;
using namespace boost::spirit::ascii;
namespace repo = boost::spirit::repository;
//]
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
using phoenix::at_c;
using phoenix::push_back;
///////////////////////////////////////////////////////////////////////////////
//  Our mini XML tree representation
///////////////////////////////////////////////////////////////////////////////
struct mini_xml;
typedef
    boost::variant<
        boost::recursive_wrapper<mini_xml>
      , std::string
    >
mini_xml_node;
//typedef std::vector<mini_xml_node> mini_xml_children; // original
typedef std::list<mini_xml_node> mini_xml_children;
struct mini_xml
{
    std::string name;                           // tag name
    mini_xml_children children;                 // children
};
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_STRUCT(
    mini_xml,
    (std::string, name)
    (mini_xml_children, children)
)
///////////////////////////////////////////////////////////////////////////////
//  Our mini XML grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct mini_xml_parser :
    qi::grammar<Iterator, mini_xml(), space_type>
{
    mini_xml_parser() : mini_xml_parser::base_type(xml)
    {
        text = lexeme[+(char_ - '<')        [_val += _1]];
        node = (xml | text)                 [_val = _1];
        start_tag =
                '<'
            >>  !lit('/')
            >>  lexeme[+(char_ - '>')       [_val += _1]]
            >>  '>'
        ;
        end_tag =
                "</"
            >>  lit(_r1)
            >>  '>'
        ;
        xml =
                start_tag                   [at_c<0>(_val) = _1]
            >>  *node                       [push_back(at_c<1>(_val), _1)]
            >>  end_tag(at_c<0>(_val))
        ;
    }
    qi::rule<Iterator, mini_xml(), space_type> xml;
    qi::rule<Iterator, mini_xml_node(), space_type> node;
    qi::rule<Iterator, std::string(), space_type> text;
    qi::rule<Iterator, std::string(), space_type> start_tag;
    qi::rule<Iterator, void(std::string), space_type> end_tag;
};
///////////////////////////////////////////////////////////////////////////////
//  A couple of phoenix functions helping to access the elements of the 
//  generated AST
///////////////////////////////////////////////////////////////////////////////
template <typename T>
struct get_element
{
    template <typename T1>
    struct result { typedef T const& type; };
    T const& operator()(mini_xml_node const& node) const
    {
        return boost::get<T>(node);
    }
};
phoenix::function<get_element<std::string> > _string;
phoenix::function<get_element<mini_xml> > _xml;
///////////////////////////////////////////////////////////////////////////////
//  The output grammar defining the format of the generated data
///////////////////////////////////////////////////////////////////////////////
//[mini_xml_karma_sr_grammar
template <typename OutputIterator>
struct mini_xml_generator
  : karma::grammar<OutputIterator, mini_xml()>
{
    mini_xml_generator() : mini_xml_generator::base_type(xml)
    {
        node %= ascii::string | xml;
        xml = 
                '<'  << ascii::string[qi::_1 = phoenix::at_c<0>(qi::_val)] << '>'
            <<                (*node)[qi::_1 = phoenix::at_c<1>(qi::_val)]
            <<  "</" << ascii::string[qi::_1 = phoenix::at_c<0>(qi::_val)] << '>'
            ;
    }
    karma::rule<OutputIterator, mini_xml()> xml;
    karma::rule<OutputIterator, mini_xml_node()> node;
};
//]
///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
    char const* filename;
    if (argc > 1)
    {
        filename = argv[1];
    }
    else
    {
        std::cerr << "Error: No input file provided." << std::endl;
        return 1;
    }
    std::ifstream in(filename, std::ios_base::in);
    if (!in)
    {
        std::cerr << "Error: Could not open input file: "
            << filename << std::endl;
        return 1;
    }
    std::string storage; // We will read the contents here.
    in.unsetf(std::ios::skipws); // No white space skipping!
    std::copy(
        std::istream_iterator<char>(in),
        std::istream_iterator<char>(),
        std::back_inserter(storage));
    typedef mini_xml_parser<std::string::const_iterator> mini_xml_parser;
    mini_xml_parser xmlin;  //  Our grammar definition
    mini_xml ast; // our tree
    std::string::const_iterator iter = storage.begin();
    std::string::const_iterator end = storage.end();
    bool r = qi::phrase_parse(iter, end, xmlin, space, ast);
    if (r && iter == end)
    {
        std::cout << "-------------------------n";
        std::cout << "Parsing succeededn";
        std::cout << "-------------------------n";
        typedef std::back_insert_iterator<std::string> outiter_type;
        typedef mini_xml_generator<outiter_type> mini_xml_generator;
        mini_xml_generator xmlout;                 //  Our grammar definition
        std::string generated;
        outiter_type outit(generated);
        bool r = karma::generate(outit, xmlout, ast);
        if (r)
            std::cout << generated << std::endl;
        return 0;
    }
    else
    {
        std::string::const_iterator begin = storage.begin();
        std::size_t dist = std::distance(begin, iter);
        std::string::const_iterator some = 
            iter + (std::min)(storage.size()-dist, std::size_t(30));
        std::string context(iter, some);
        std::cout << "-------------------------n";
        std::cout << "Parsing failedn";
        std::cout << "stopped at: ": " << context << "..."n";
        std::cout << "-------------------------n";
        return 1;
    }
}

错误消息的开头:

1>------ Build started: Project: test_project, Configuration: Debug Win32 ------
1>Compiling...
1>test_project.cpp
1>c:rtgcodethirdpartythirdpartyboost/spirit/home/phoenix/operator/self.hpp(27) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const std::list<_Ty>' (or there is no acceptable conversion)
1>        with
1>        [
1>            _Ty=mini_xml_node
1>        ]
1>        c:Program Files (x86)Microsoft Visual Studio 9.0VCincludevector(562): could be 'std::vector<_Ty> &std::vector<_Ty>::operator =(const std::vector<_Ty> &)'
1>        with
1>        [
1>            _Ty=boost::variant<boost::recursive_wrapper<mini_xml>,std::string>
1>        ]
1>        while trying to match the argument list '(std::vector<_Ty>, const std::list<_Ty>)'
1>        with
1>        [
1>            _Ty=boost::variant<boost::recursive_wrapper<mini_xml>,std::string>
1>        ]
1>        and
1>        [
1>            _Ty=mini_xml_node
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/mpl/eval_if.hpp(41) : see reference to class template instantiation 'boost::phoenix::result_of_assign<X,Y>' being compiled
1>        with
1>        [
1>            X=std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> ,
1>            Y=const std::list<mini_xml_node> 
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/phoenix/operator/self.hpp(69) : see reference to class template instantiation 'boost::mpl::eval_if<C,F1,F2>' being compiled
1>        with
1>        [
1>            C=boost::mpl::or_<boost::phoenix::is_actor<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> >,boost::phoenix::is_actor<const std::list<mini_xml_node> >>,
1>            F1=boost::phoenix::re_curry<boost::phoenix::assign_eval,std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> ,const std::list<mini_xml_node> >,
1>            F2=boost::phoenix::result_of_assign<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> ,const std::list<mini_xml_node> >
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/phoenix/core/detail/composite_eval.hpp(88) : see reference to class template instantiation 'boost::phoenix::assign_eval::result<Env,A0,A1>' being compiled
1>        with
1>        [
1>            Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>,
1>            A0=boost::spirit::argument<0>,
1>            A1=boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/phoenix/core/composite.hpp(60) : see reference to class template instantiation 'boost::phoenix::detail::composite_eval<2>::result<Composite,Env>' being compiled
1>        with
1>        [
1>            Composite=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1>            Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/phoenix/core/actor.hpp(56) : see reference to class template instantiation 'boost::phoenix::composite<EvalPolicy,EvalTuple>::result<Env>' being compiled
1>        with
1>        [
1>            EvalPolicy=boost::phoenix::assign_eval,
1>            EvalTuple=boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>,
1>            Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/phoenix/core/detail/actor.hpp(48) : see reference to class template instantiation 'boost::phoenix::eval_result<Eval,Env>' being compiled
1>        with
1>        [
1>            Eval=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1>            Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/support/action_dispatch.hpp(178) : see reference to class template instantiation 'boost::phoenix::actor<Eval>::result<Sig>' being compiled
1>        with
1>        [
1>            Eval=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1>            Sig=boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>> (boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &> &,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>> &,bool &)
1>        ]
1>        c:rtgcodethirdpartythirdpartyboost/spirit/home/karma/action/action.hpp(69) : see reference to function template instantiation 'bool boost::spirit::traits::action_dispatch<Component>::operator ()<boost::phoenix::composite<EvalPolicy,EvalTuple>,std::vector<_Ty>,Context>(const boost::phoenix::actor<Eval> &,Attribute &,Context &)' being compiled
1>        with
1>        [
1>            Component=boost::spirit::karma::kleene<boost::spirit::karma::reference<const boost::spirit::karma::rule<outiter_type,mini_xml_node (void)>>>,
1>            EvalPolicy=boost::phoenix::assign_eval,
1>            EvalTuple=boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>,
1>            _Ty=boost::variant<boost::recursive_wrapper<mini_xml>,std::string>,
1>            Context=boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,
1>            Eval=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1>            Attribute=std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>>
1>        ]
*snip*

在Visual Studio 2008中使用boost v1.50.0编译。

旁注:如果不先将 karma::subrule 更改为 karma::rule,我就无法编译原始示例。1.50.0 中的子规则有问题吗?有没有比我所做的更好的解决方法?

这是

Boost Spirit的另一个案例:"语义行为是邪恶的"?

如果您更改为列表,出于显而易见的原因,push_back不起作用。所以,改变

        >>  *node   [push_back(at_c<1>(_val), _1)]

        >>  *node   [phoenix::insert(at_c<1>(_val), phoenix::end(at_c<1>(_val)), _1)]

在生成器端,用更简单的语义操作替换所有语义操作的使用,该操作允许您仍然依赖属性兼容性魔术来处理所有其他操作:

    karma::_a_type element_name_; // using karma::locals<std::string>
    xml %= 
        '<'  << string[element_name_ = _1] << '>'
        <<  *node
        <<  "</" << string(element_name_) << '>'
        ;

<咆哮>所有这些都只是更多的证据,证明代码越少越好。干扰少,拼出来少,依赖内置机制。一旦你干涉(通过为属性提取编写精确的、命令式的、语义的操作(,当你想要维护代码时,你就输了.


更新 现在删除了所有无端使用语义操作,因此我们有一个 Qi 语法和 Karma 生成器,无需任何额外工作即可与listvector一起使用。还修复了一些风格的元素(不再using namespace(。

这意味着不再需要上述phoenix::insert(at_c<1>(_val), phoenix::end(at_c<1>(_val)), _1)

    qi::_a_type element_name_;
    xml %=
            start_tag[element_name_ = _1]
        >>  *node
        >>  end_tag(element_name_)
    ;

住在科里鲁

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
namespace fusion  = boost::fusion;
namespace qi      = boost::spirit::qi;
namespace ascii   = boost::spirit::ascii;
namespace karma   = boost::spirit::karma;
namespace phoenix = boost::phoenix;
///////////////////////////////////////////////////////////////////////////////
//  Our mini XML tree representation
///////////////////////////////////////////////////////////////////////////////
struct mini_xml;
typedef
    boost::variant<
        boost::recursive_wrapper<mini_xml>
      , std::string
    >
mini_xml_node;
typedef std::list<mini_xml_node> mini_xml_nodes;
struct mini_xml
{
    std::string name;               // tag name
    mini_xml_nodes children;        // children
};
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_STRUCT(
    mini_xml,
    (std::string, name)
    (mini_xml_nodes, children)
)
///////////////////////////////////////////////////////////////////////////////
//  Our mini XML grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct mini_xml_parser :
    qi::grammar<Iterator, mini_xml(), qi::space_type>
{
    mini_xml_parser() : mini_xml_parser::base_type(start)
    {
        using qi::lit;
        using qi::lexeme;
        using ascii::char_;
        using ascii::string;
        using namespace qi::labels;
        text %= lexeme[+(char_ - '<')];
        node %= xml | text;
        start_tag %=
                '<'
            >>  !lit('/')
            >>  lexeme[+(char_ - '>')]
            >>  '>'
        ;
        end_tag =
                "</"
            >>  string(_r1)
            >>  '>'
        ;
        qi::_a_type element_name_;
        xml %=
                start_tag[element_name_ = _1]
            >>  *node
            >>  end_tag(element_name_)
        ;
        start = xml;
    }
    qi::rule<Iterator, mini_xml(), qi::space_type> start;
    qi::rule<Iterator, mini_xml(), qi::space_type, qi::locals<std::string> > xml;
    qi::rule<Iterator, mini_xml_node(), qi::space_type> node;
    qi::rule<Iterator, std::string(), qi::space_type> text;
    qi::rule<Iterator, std::string(), qi::space_type> start_tag;
    qi::rule<Iterator, void(std::string), qi::space_type> end_tag;
};
///////////////////////////////////////////////////////////////////////////////
//  A couple of phoenix functions helping to access the elements of the 
//  generated AST
///////////////////////////////////////////////////////////////////////////////
template <typename T>
struct get_element
{
    template <typename T1>
    struct result { typedef T const& type; };
    T const& operator()(mini_xml_node const& node) const
    {
        return boost::get<T>(node);
    }
};
phoenix::function<get_element<std::string> > _string;
phoenix::function<get_element<mini_xml> > _xml;
///////////////////////////////////////////////////////////////////////////////
//  The output grammar defining the format of the generated data
///////////////////////////////////////////////////////////////////////////////
//[mini_xml_karma_sr_grammar
template <typename OutputIterator>
struct mini_xml_generator
  : karma::grammar<OutputIterator, mini_xml()>
{
    mini_xml_generator() : mini_xml_generator::base_type(entry)
    {
        karma::_a_type element_name_;
        xml   %= 
            '<'  << karma::string[element_name_ = karma::_1] << '>'
            <<  *node
            <<  "</" << karma::string(element_name_) << '>'
            ;
        node  %= karma::string | xml;
        entry %= node;
    }
    karma::rule<OutputIterator, mini_xml()> entry;
    karma::rule<OutputIterator, mini_xml(), qi::locals<std::string> > xml;
    karma::rule<OutputIterator, mini_xml_node()> node;
};
//]
///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
    char const* filename;
    if (argc > 1)
    {
        filename = argv[1];
    }
    else
    {
        std::cerr << "Error: No input file provided." << std::endl;
        return 1;
    }
    std::ifstream in(filename, std::ios_base::in);
    if (!in)
    {
        std::cerr << "Error: Could not open input file: "
            << filename << std::endl;
        return 1;
    }
    std::string storage; // We will read the contents here.
    in.unsetf(std::ios::skipws); // No white space skipping!
    std::copy(
        std::istream_iterator<char>(in),
        std::istream_iterator<char>(),
        std::back_inserter(storage));
    typedef mini_xml_parser<std::string::const_iterator> mini_xml_parser;
    mini_xml_parser xmlin;  //  Our grammar definition
    mini_xml ast; // our tree
    std::string::const_iterator iter = storage.begin();
    std::string::const_iterator end = storage.end();
    bool r = qi::phrase_parse(iter, end, xmlin, qi::space, ast);
    if (r && iter == end)
    {
        std::cout << "-------------------------n";
        std::cout << "Parsing succeededn";
        std::cout << "-------------------------n";
        typedef std::back_insert_iterator<std::string> outiter_type;
        typedef mini_xml_generator<outiter_type> mini_xml_generator;
        mini_xml_generator xmlout;                 //  Our grammar definition
        std::string generated;
        outiter_type outit(generated);
        bool r = karma::generate(outit, xmlout, ast);
        if (r)
            std::cout << generated << std::endl;
        return 0;
    }
    else
    {
        std::string::const_iterator begin = storage.begin();
        std::size_t dist = std::distance(begin, iter);
        std::string::const_iterator some = 
            iter + (std::min)(storage.size()-dist, std::size_t(30));
        std::string context(iter, some);
        std::cout << "-------------------------n";
        std::cout << "Parsing failedn";
        std::cout << "stopped at: ": " << context << "..."n";
        std::cout << "-------------------------n";
        return 1;
    }
}