C++, RapidXML: Разбор больших файлов

Я хочу разобрать большой файл XML (33000 строк). Следуя структуре моего xml-файла:

<?xml version="1.0" encoding="UTF-8"?><Root_2010 xmlns:noNamespaceSchemaLocation="textpool_1.2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" lang="de-DE">
<Textpool Version="V20.12.08">
<TextpoolList FontFamily="Standard" FontSize="16" FontStyle="normal" FontWeight="bold" SID="S1" TextCharacterLength="0" TextLength="135">
<Text>GlobalCommonTextBook</Text>
</SID_Name>
<TextpoolBlock>
<TextpoolRecord CharacterLengthCheck="Ok" Status="Released" StdTextCharacterLength="4" StdTextLength="???" TID="Txt0_0" TermCheck="NotChecked" TermCheckDescription="NotChecked" TextLengthCheck="Ok" fixed="true">
<IEC translate="no">
<Text/>
</IEC>
<ExplanationText/>
<Text>nein</Text>
</ShortText>
</Description>
<Creator>z0046abb</Creator>
</TextpoolRecord>
</TextpoolBlock>
</TextpoolList>
</Textpool>
</Root_2010>

Элемент TextpoolList хранит две части. Его имя хранится в первом элементе Text. В TextpoolBlock хранится несколько записей. Интересующий элемент снова Text.

Мне нужно проанализировать этот файл и извлечь все элементы Text из определенного TextpoolList, чтобы экспортировать его в другой файл. Будущая перспектива состоит в том, чтобы воспользоваться атрибутами TextpoolList и отсканировать записи, добавленные в ShortText. Вот почему я хочу использовать XMLParser.

Я решил дать XMLRapid шанс. Поскольку этот файл довольно большой, мне нужно переключить некоторые данные из стека в кучу. Поскольку я действительно не знаю, как это сделать, я прошу вас о помощи. Я пробовал что-то похожее на https://linuxhint.com/parse_xml_in_c__/.

    rapidxml::xml_document<> doc;
    rapidxml::xml_node<>* root_node = NULL;
    rapidxml::xml_node<>* block_node = NULL;
    rapidxml::xml_node<>* record_node = NULL;
    rapidxml::xml_node<>* text_node = NULL;

    std::ifstream infile(file);
    std::string line;
    std::string tp_data;

    while (std::getline(infile, line))
        tp_data += line;

    std::vector<char> tp_data_copy(tp_data.begin(), tp_data.end());

    tp_data_copy.push_back('\0');

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

    root_node = doc.first_node("TextpoolList");

    for (rapidxml::xml_node<>* textpool_node = root_node->first_node("Textpool"); textpool_node; textpool_node = textpool_node->next_sibling())
    {
        for (rapidxml::xml_node<>* list_node = textpool_node->first_node("TextpoolList"); list_node; list_node = list_node->next_sibling())
        {
            for (rapidxml::xml_node<>* block_node = list_node->first_node("TextpoolBlock"); block_node; block_node = block_node->next_sibling())
            {
                for (rapidxml::xml_node<>* record_node = block_node->first_node("TextpoolRecord"); record_node; record_node = record_node->next_sibling())
                {
                    for (rapidxml::xml_node<>* text_node = record_node->first_node("Text"); text_node; text_node = text_node->next_sibling())
                    {
                        std::cout << "record =   " << text_node->value();
                        std::cout << std::endl;
                    }
                    std::cout << std::endl;
                }
            }
        }
    }
    }

Изменить: я изменил свой код так, как я думал, что данные попадут в кучу, но я все еще получаю ту же ошибку, чтобы хранить данные в куче, а не в стеке.

Спасибо за все ваши идеи!


person doublesobig    schedule 03.05.2021    source источник
comment
This example doesn't work out. - что именно не получилось?   -  person SergeyA    schedule 03.05.2021
comment
root_node->first_node("TextpoolList") разве это не должно быть TextpoolBlock ?   -  person acraig5075    schedule 03.05.2021
comment
Для задачи лучше использовать XSLT-преобразование.   -  person Yitzhak Khabinsky    schedule 03.05.2021
comment
В целом это выглядит нормально, хотя чтение в std::string, а не std::vector<char> чище, а также на основе кучи. Однако ваш обход документа не соответствует образцу XML. Вы не проходите TextpoolBlocks, И вы печатаете ->value() из TextPoolRecords, но у них их нет - только подэлементы. Вы хотели вместо этого напечатать значение их узла Text?   -  person Roddy    schedule 04.05.2021
comment
Если я хочу прочитать это в std::string, какая-то внутренняя функция rapidxml не работает. Да, я хотел напечатать значение их узла Text, но я не знал, как получить к нему доступ.   -  person doublesobig    schedule 04.05.2021


Ответы (1)


Ладно, наконец-то все работает. Это моя рутина:

    rapidxml::xml_document<> doc;
    rapidxml::xml_node<>* root_node = NULL;
    rapidxml::xml_node<>* block_node = NULL;
    rapidxml::xml_node<>* record_node = NULL;
    rapidxml::xml_node<>* text_node = NULL;
    rapidxml::xml_node<>* list_node = NULL;

    std::ifstream infile(file);
    std::string line;
    std::string tp_data;

    while (std::getline(infile, line))
        tp_data += line;

    std::vector<char> tp_data_copy(tp_data.begin(), tp_data.end());

    tp_data_copy.push_back('\0');

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

    root_node = doc.first_node("Root_2010");

    for (rapidxml::xml_node<>* textpool_node = root_node->first_node("Textpool"); textpool_node; textpool_node = textpool_node->next_sibling())
    {
        for (rapidxml::xml_node<>* list_node = textpool_node->first_node("TextpoolList"); list_node; list_node = list_node->next_sibling())
        {
            for (rapidxml::xml_node<>* block_node = list_node->first_node("TextpoolBlock"); block_node; block_node = block_node->next_sibling())
            {
                for (rapidxml::xml_node<>* record_node = block_node->first_node("TextpoolRecord"); record_node; record_node = record_node->next_sibling())
                {
                    for (rapidxml::xml_node<>* text_node = record_node->first_node("Text"); text_node; text_node = text_node->next_sibling())
                    {
                        std::cout << "record =   " << text_node->value();
                        std::cout << std::endl;
                    }
                    std::cout << std::endl;
                }
            }
        }
    }

Если останется немного времени, я попытаюсь найти какой-нибудь обходной путь для этого гребаного чтения файлов.

person doublesobig    schedule 04.05.2021
comment
Подумайте о том, чтобы перевернуть условные операторы, чтобы уменьшить количество кода со стрелкой. - person Casey; 04.05.2021
comment
Несколько комментариев: #1 Вам не нужны переменные rapidxml::xml_node<>* вверху, потому что вы (правильно) используете объявление их в области действия цикла. Кроме root_node, конечно, который вы должны объявить и инициализировать в одной строке. rapidxml::xml_node<>* root_node = doc.first_node(... - person Roddy; 05.05.2021
comment
# 2: ваши вызовы next_sibling() не указывают имя узла, поэтому вы получите следующего брата или сестру, независимо от имени. - person Roddy; 05.05.2021
comment
№ 3: Ваш образец XML серьезно искажен. xmlvalidation.com/index.php?id=1&L=0 - person Roddy; 05.05.2021
comment
# 4: Чтение вашего файла очень странное и удалит все последовательности новой строки, поэтому многострочные Text узлы не будут работать. Используйте rapidxml::file. stackoverflow. ком/вопросы/2808022/ - person Roddy; 05.05.2021
comment
# 5: Действительно ли вашему формату данных требуется несколько текстовых узлов под каждым Textpool? если нет, вы можете удалить петлю. - person Roddy; 05.05.2021