C++ Использование RapidXml для синтаксического анализа XML-файла, класса-оболочки, parse_error expect ›

Я пытаюсь использовать RapidXML для анализа моего XML-файла. И я сделал это по примеру здесь. Вместо того, чтобы выполнять синтаксический анализ в основной функции, я написал класс-оболочку с именем XMLParser для выполнения синтаксического анализа. И это действительно вызывает у меня головную боль.

XMLParser.hpp:

#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include "rapidxml/rapidxml.hpp"

using namespace std;
using namespace rapidxml;

class XMLParser {

public:
    XMLParser() {};

    XMLParser(const std::string &xmlString): xmlCharVector(xmlString.begin(), xmlString.end())
    {
        //xmlCharVector.push_back('\0');
         parseXML();
    }
    XMLParser(const std::vector<char> &_xmlVector):xmlCharVector(_xmlVector)
    {
        /* xmlCharVector.push_back('\0'); */  // already done in main.cpp
        if (xmlCharVector != _xmlVector)      //And it turns out they're the same....
            std::cout << "The two vectors are not equal" << std::endl;
        else
            std::cout << "They are the same" << std::endl;
        parseXML();
    }

private:
    std::vector<char> xmlCharVector;
    rapidxml::xml_document<> doc;
    void parseXML();

};

XMLParser.cpp:

#include "XMLParser.hpp"

using namespace std;
using namespace rapidxml;

void XMLParser::parseXML()
{
    doc.parse<0>(&xmlCharVector[0]);
}

А вот main.cpp:

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <fstream>
#include "XMLParser.hpp"

using namespace std;
using namespace rapidxml;

int main(int argc, char **argv)
{
    xml_document<> doc;
    xml_node<> *root_node;
    ifstream theFile("beer.xml");
    vector<char> buffer((istreambuf_iterator<char>(theFile)), istreambuf_iterator<char>());
    buffer.push_back('\0');

    doc.parse<0>(&buffer[0]);

    root_node = doc.first_node("MyBeerJournal");
    xml_node<> *engine = root_node->first_node("Brewery");

    //The above code works pretty well, and I can get the element I want in XML file.

    //The problem occurs when I tried to use the XMLParser
    XMLParser xmlParser(buffer);
    return 0;
}

Процесс синтаксического анализа в основной функции работает довольно хорошо. Но когда я попытался использовать функцию в моем классе-оболочке parseXML(), произошла ошибка:

вызывается завершение после создания экземпляра 'rapidxml::parse_error' what(): ожидается > Прервать (дамп ядра)

Изначально у меня был другой код в этой функции, но я прокомментировал их все и обнаружил, что даже с единственной строкой doc.parse<0>(&xmlCharVector[0]);. Почему он хорошо работает в main.cpp, а не в классе-оболочке? Я действительно не могу понять это. Кто-нибудь может мне помочь?


person Dreamer    schedule 23.08.2013    source источник


Ответы (1)


Я выяснил причину... Эта глупая проблема действительно требует много времени для отладки. Я пишу это здесь, чтобы каждый, кто сталкивался с этим (надеюсь, нет), мог сэкономить свое время. Проблема именно в коде doc.parse<0>(&buffer[0]) в функции main. Перед выполнением этой строки кода buffer(type of vector<char>) выглядит так: (выводя вектор на консоль)

<MyBeerJournal>
    <Brewery name="Founders Brewing Company" location="Grand Rapids, MI">
        <Beer name="Centennial" description="IPA" rating="A+" dateSampled="01/02/2011">
            "What an excellent IPA. This is the most delicious beer I have ever tasted!"
        </Beer>
    </Brewery>
    .....
    .....
</MyBeerJournal>

То же самое с исходным файлом xml. После выполнения приведенного выше кода buffer(type of vector<char>) становится примерно таким:

<MyBeerJournal
    <Breweryname"Founders Brewing Company location"Grand Rapids, MI>

        <Beername"Centennial description"IPA rating"A+ dateSampled"01/02/2011>

            "What an excellent IPA. This is the most delicious beer I have ever tasted!"
        /Beer>

    </Brewery>

Как видите, некоторые ангельские скобки исчезли. и некоторые другие вещи, такие как двойные кавычки, также были изменены. Таким образом, конструктор класса-оболочки скопировал измененный «буфер xml», и этот плохо отформатированный вектор xml наверняка приведет к сбою второго doc.parse<0>(&xmlCharVector[0]); в классе-оболочке. Я не знаю, почему разработчику библиотеки необходимо изменить переданный вектор символов, потому что последующий анализ xml не имеет отношения к исходному вектору символов после создания DOC.

person Dreamer    schedule 23.08.2013
comment
'Я не знаю, зачем разработчику библиотеки изменять передаваемый вектор символов' - потому что RapidXML разработан как сверхбыстрый анализатор in-situ. Создаваемый им DOM — это просто набор указателей на исходные данные. Прочтите документацию, особенно раздел об «отличиях от обычных анализаторов XML». rapidxml.sourceforge.net/manual.html - person Roddy; 01.10.2013
comment
@Roddy Означает ли это, что функция будет редактировать исходную строку напрямую с помощью указателя, а не сначала копировать ее, а затем что-то делать с скопированной? - person Dreamer; 01.10.2013
comment
Точно: он вводит нулевые символы для завершения каждого «узла», если вы не используете «неразрушающий» режим. Это позволяет избежать накладных расходов на скорость выделения хранилища для хранения каждого узла и накладных расходов памяти, связанных с необходимостью второй немодифицированной копии. - person Roddy; 01.10.2013
comment
@ Родди Попался! Благодарю вас! - person Dreamer; 01.10.2013