Анализировать XML с помощью ускоренного доступа и заполнять дерево свойств

У меня есть XML-файл:

<expressions>
    <addition id="1">
        <item>2</item>
        <item>3</item>
        <item>4</item>
    </addition>
    <subtraction id="2">
        <minuend>3</minuend>
        <subtrahend>2</subtrahend>
    </subtraction>
    <multiplication id="3">
        <factor>5</factor>
        <factor>6</factor>
        <factor>8</factor>
    </multiplication>
    <division id="4">
        <dividend>54</dividend>
        <divisor>9</divisor> 
    </division>
</expressions>

Необходимо проанализировать его и предоставить результат как другой XML:

<expressions>
    <result id="1">9</result>
    <result id="2">1</result>
    <result id="3">240</result>
    <result id="4">6</result>
</expressions>

В настоящее время исследую BOOST в области ptree и read_xml. Посоветуйте, пожалуйста, где можно найти дополнительную информацию? заранее спасибо

Мои текущие результаты расследования:

У меня есть класс, который определяет Expression с виртуальной функцией, которая оценивает выражение, ниже по дереву наследования, эта функция должна быть переопределена и реализована в контексте типа выражения.

class AbstractExpression
{
public:
    AbstractExpression(ExpressionType aType){}
    virtual ~AbstractExpression() {}

    // Evaluates expression (must be overrided by child)
    virtual int  evalExpr() const = 0;

};

Унаследованные классы additionExpression, substractionExpression, multiplicationExpression, divisionExpression.

Помимо этого, я реализовал методы манипулирования данными в каждом унаследованном классе.

В конце я написал код, который считает этот XML:

using boost::property_tree::ptree;
    ptree pt;
    read_xml("/PATH_TO/valuator.xml", pt);
    const ptree & expressions = pt.get_child("expressions");
    BOOST_FOREACH(const ptree::value_type & currExpr, expressions){
        std::string readExprType = currExpr.first;
        std::cout << "currExpr = " << readExprType << std::endl;

        if (readExprType == "addition") {
            AbstractExpression *addExpr = new additionExpression();
            BOOST_FOREACH(const ptree::value_type & additionNodeEl, currExpr.second){
                std::string val = additionNodeEl.second.data();
                ((additionExpression*)addExpr)->addVal( atoi(val.c_str()) );

            }
            std::cout << "addition result = " << addExpr->evalExpr() << std::endl;
            delete addExpr;
        } else if (readExprType == "multiplication") {
            AbstractExpression *multExpr = new multiplicationExpression();
            BOOST_FOREACH(const ptree::value_type &multNodeEl, currExpr.second) {
                std::string val = multNodeEl.second.data();
                if (!val.empty())
                    ((multiplicationExpression*)multExpr)->addVal( atoi(val.c_str()) );
            }
            std::cout << "multiplication node result = " << multExpr->evalExpr() << std::endl;
            delete multExpr;
        } else if (readExprType == "subtraction") {
            AbstractExpression *substrExpr = new substractionExpression();
            BOOST_FOREACH(const ptree::value_type &substNodeEl, currExpr.second) {
                std::string elTypeName = substNodeEl.first;
                std::string val = substNodeEl.second.data();
                if (elTypeName == "minuend") {
                    ((substractionExpression*)substrExpr)->setMinuend( atoi(val.c_str()) );
                } else if (elTypeName == "subtrahend") {
                    ((substractionExpression*)substrExpr)->setSubtrahend( atoi(val.c_str()) );
                }
            }
            std::cout << "subtraction node result = " << substrExpr->evalExpr() << std::endl;
            delete substrExpr;
        } else if (readExprType == "division") {
            AbstractExpression *divExpr = new divisionExpression();
            BOOST_FOREACH(const ptree::value_type &divNodeEl, currExpr.second) {
                std::string elTypeName = divNodeEl.first;
                std::string val = divNodeEl.second.data();
                if ( elTypeName == "dividend" ) {
                    ((divisionExpression*)divExpr)->setDividend( atoi(val.c_str()) );
                } else if ( elTypeName == "divisor" ) {
                    ((divisionExpression*)divExpr)->setDivisor( atoi(val.c_str()) );
                }
            }
            std::cout << "dividend node result = " << divExpr->evalExpr() << std::endl;
            delete divExpr;
        }

    }

Теперь мне нужно записать все эти результаты в XML.


person Oleksandr Hryhorchuk    schedule 23.09.2014    source источник
comment
Извините за формат сообщения, особенно за исходный код.   -  person Oleksandr Hryhorchuk    schedule 23.09.2014
comment
Поместите результаты на карту ‹int, string› и напишите XML в виде текста позже   -  person Grigorii Chudnov    schedule 23.09.2014
comment
Хорошо, но как я могу получить идентификатор из ‹добавления id = 1› ‹/addition› Спасибо   -  person Oleksandr Hryhorchuk    schedule 24.09.2014


Ответы (1)


На самом деле, используйте правильную библиотеку XML (TinyXML, RapidXML, PugiXML, libxml2 и т. Д.).

Если вас действительно интересует только очень конкретное подмножество XML, вот быстрый и грязный синтаксический анализатор на основе Boost Spirit V2: В прямом эфире на Coliru

namespace /*parser*/
{
    namespace qi = boost::spirit::qi;

    template <typename It, typename Skipper = qi::space_type>
        struct grammar : qi::grammar<It, ast::expressions(), Skipper>
    {
        grammar() : grammar::base_type(expressions_)
        {
            using namespace qi;

            static const lexeme_type L;

            simplevalue_ = auto_; // parses into Value, whatever it was declared as
            id_attr      = eps >> L["id"]      > '=' > '"' > int_        > '"';
            complex_attr = eps >> L["complex"] > '=' > '"' > *~char_('"') > '"';
            expr_open    = eps >> '<' >> L[lit(_r1)] > -id_attr > -complex_attr > '>';
            expr_close   = eps >> '<' >> '/' > L[lit(_r1)] > '>';

            // expression element parsing
            addition_       = expr_open(+"addition") > +subexpr_(+"item")                                  > expr_close(+"addition");
            subtraction_    = expr_open(+"subtraction") > (subexpr_(+"minuend") > subexpr_(+"subtrahend")) > expr_close(+"subtraction");
            multiplication_ = expr_open(+"multiplication") > +subexpr_(+"factor")                          > expr_close(+"multiplication");
            division_       = expr_open(+"division") > (subexpr_(+"dividend") > subexpr_(+"divisor"))      > expr_close(+"division");
            expression_     = simplevalue_ | addition_ | subtraction_ | multiplication_ | division_;

            subexpr_ = eps >> '<' >> L[lit(_r1)] > '>' > expression_ > '<' > '/' > L[lit(_r1)] > '>';

            expressions_ = eps
                > '<' > L["expressions"] > '>'
                > *expression_
                > expr_close(+"expressions");

            BOOST_SPIRIT_DEBUG_NODES((simplevalue_)(expr_open)(expr_close)(subexpr_)(addition_)(subtraction_)(multiplication_)(division_)(expression_)(expressions_))
        }
      private:
        template <typename... T>
            using Rule = qi::rule<It, T..., qi::space_type>;

        // tags/primitives
        Rule<> complex_attr;
        Rule<int()> id_attr;
        Rule<ast::Value()> simplevalue_;
        Rule<ast::Id(std::string element_name)> expr_open;
        Rule<void(std::string element_name)> expr_close;

        Rule<ast::expression(std::string element_name )> subexpr_;

        // compounds
        Rule<ast::addition()>       addition_;
        Rule<ast::subtraction()>    subtraction_;
        Rule<ast::multiplication()> multiplication_;
        Rule<ast::division()>       division_;
        Rule<ast::expression()>     expression_;

        Rule<ast::expressions()> 
            expressions_;
    };

} /*parser*/

Он анализирует ввод в абстрактное синтаксическое дерево, которое можно посетить для оценки (под) выражений. Тест-драйвер

int main()
{
    std::ifstream ifs("expressions.xml");
    It f(ifs >> std::noskipws), l;

    try {
        ast::expressions parsed;

        grammar<It> g;
        // parsing
        bool ok = phrase_parse(f, l, g, qi::space, parsed);

        // output results
        if (ok)
        {
            eval::machine machine;

            std::cout << "<expressions>\n";
            for (auto& expr : parsed)
                if (get_id(expr))
                    std::cout << "\t<result id=\"" << *get_id(expr) << "\">" << machine.evaluate(expr) << "</result>\n";
            std::cout << "</expressions>\n";
        }
    } catch(qi::expectation_failure<It> const& e) {
        std::cout << "Expected " << e.what_ << " at '" << std::string(e.first,e.last) << "'\n";
    }
}

Печать

<expressions>
    <result id="1">9</result>
    <result id="2">1</result>
    <result id="3">240</result>
    <result id="4">6</result>
</expressions>

Live On Coliru

Примечание: не обрабатывает комментарии, юникод, инструкции обработки, пространства имен, PCDATA, ссылки на символьные сущности и т. д. Короче Это не анализатор XML

person sehe    schedule 24.09.2014
comment
Спасибо, но есть еще один случай для этой задачи (только что получил обновление), сложные узлы с комплексным флагом: `‹ add id = 10 complex = true ›‹item› 2 ‹/item› ‹item› 3 ‹/item›‹ item ›‹subtraction› ‹minuend› 7 ‹/minuend› ‹subtrahend› 3 ‹/subtrahend› ‹/subtraction› ‹/item› ‹/addition›` Заранее благодарим за вашу помощь! - person Oleksandr Hryhorchuk; 24.09.2014
comment
Кстати, ваше решение генерирует сообщение об ошибке, пока я пытаюсь скомпилировать: simpleVal.cpp: 21: 30: error: инициализация по умолчанию объекта константного типа 'const lexeme_type' (также известного как 'const expr ‹proto :: tag: : terminal, term ‹boost :: spirit :: tag :: lexeme›, 0 ›') требует предоставленного пользователем конструктора по умолчанию static const lexeme_type L; ^ 1 ошибка сгенерирована. Какую буст-версию вы используете? - person Oleksandr Hryhorchuk; 24.09.2014
comment
@ АлександрГригорчук, это clang для вас. И это правильно. Хотя есть отчет о дефектах против стандарта для этого AFAIR. (Как вы заметили в моем ответе, он включает инициализатор) - person sehe; 24.09.2014
comment
В общем, я почти выполнил эту задачу, но у меня все еще есть дерево свойств и ream_xml. Кстати, чтобы читать атрибуты (было в моих предыдущих вопросах), нам нужно: auto second = currExpr.second; second.get<int>("<xmlattr>.id"); Просто чтобы прояснить для других. - person Oleksandr Hryhorchuk; 24.09.2014
comment
@OleksandrHryhorchuk Ты должен дать ответ. В любом случае, вот версия, которая тоже выполняет подвыражения. Теперь в комплекте с представлением AST. См. Live On Coliru, где можно увидеть вычисления эти прекрасные деревья выражений: 2 и -6138.58 (Смотри, мама! Нет явные динамические распределения). - person sehe; 24.09.2014
comment
Успех с компиляцией, однако у меня есть выражение: ‹multiplication id = 13 complex = true› ‹factor› ‹addition› ‹item› 2 ‹/item› ‹item› 3 ‹/item› ‹item› 4 ‹/item› ‹ / дополнение ›‹/factor› ‹factor› 6 ‹/factor› ‹factor› ‹multiplication› ‹factor› 3 ‹/factor› ‹factor› 4 ‹/factor› ‹factor› 5 ‹/factor› ‹factor› 10‹ / factor ›‹factor› 56 ‹/factor› ‹/multiplication› ‹/factor› ‹/multiplication› Должен быть результат 1814400, но у меня 1.8144e + 06 - person Oleksandr Hryhorchuk; 24.09.2014
comment
@soho Я очень, очень, очень благодарен вам за это решение! Закрытие этого вопроса, как вы ответили! Как я могу это сделать (я здесь новенький) - person Oleksandr Hryhorchuk; 24.09.2014
comment
Вы его нашли :) По-прежнему имеет смысл добавить свое решение для чтения значений атрибутов с помощью Boost PropertyTree. Это кажется довольно редкой информацией (я никогда о ней не слышал и решил, что это не особенность) - person sehe; 24.09.2014