Oct. 4, 2019, 6:36 a.m.

XML парсинг сложного тега <tag1> text part 1 <tag2> text </tag2> text part 2 </tag1>

Всем доброго времени суток.
Например есть вот такой тег:

<tag1> any text part 1 <tag2> text </tag2> any text part 2 </tag1>

Как реализовать корректное чтение и запись такой конструкции в объектную модель и модель QDom? С таким тегом сталкиваюсь впервые, поэтому не совсем понятно как действовать в такой ситуации.

Всем спасибо за помощь в решении даннго о вопроса.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
7

Я там описался, закрывающий последний тег - это

</tag1>

Добрый день.
А какой хотите получить итоговый результат? В том же QDomNode есть метод QDomNode::childNodes(), который возвратит список все вложенных тегов.

То есть как раз для подобных случаев

<body>
<h1>Heading</h1>
<p>Hello <b>you</b></p>
</body>

Евгений, задача у меня следующая:
1. Есть файл XML.
2. Есть объектная модель, которая соответствует файлу XML.
Мне нужно прорпарсить xml файл и записать значения в объектную модель.
Я написал следующий код, примерный:

#include <iostream>
#include <QtXml/QDomDocument>
#include <QFile>
#include <QTextStream>

int main()
{
    QDomDocument doc;
    doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""));
    QDomElement element = doc.createElement("element");
    element.appendChild(doc.createTextNode("TEXT 1"));
    QDomElement element1 = doc.createElement("element1");
    element1.appendChild(doc.createTextNode("text1"));
    element.appendChild(element1);
    element.appendChild(doc.createTextNode("TEXT 2"));
    doc.appendChild(element);
    QFile file("C:/TEMP/test.xml");
    if(file.open(QIODevice::WriteOnly)){
        QTextStream out(&file);
        out.setCodec("UTF-8");
        out << doc.toString();
        file.close();
    }
    std::cout << "start import" << std::endl;

    QDomDocument doc1;

    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        std::cout << "File not exist";
        return -1;
    }
    if(!doc1.setContent(&file)){
        file.close();
        return -1;
    }
    file.close();
        QDomNode node = doc1.firstChild();
            while (!node.isNull()) {
                QDomElement el1 = node.toElement();
                std::cout << el1.tagName().toStdString() + el1.text().toStdString();
                if(el1.hasChildNodes()){
                    QDomNode node1 = el1.firstChild();
                    while (!node1.isNull()) {
                        QDomElement el2 = node1.toElement();
                        std::cout << el2.tagName().toStdString() + " " + el2.text().toStdString() << std::endl;
                        node1 = node1.nextSibling();
                    }
                }
                node = node.nextSibling();
            }
    return 0;
}

Так вот после создания файла XML получаю вот такое содержимое файла:

<?xml version="1.0" encoding="UTF-8"?>
<element>TEXT 1<element1>text1</element1>TEXT 2</element>


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

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

Что-нибудь вроде такого

class TreeItem
{
public:
    TreeItem(TreeItem* parent = nullptr)
    {
        if (parent)
        {
            parent->addChild(this);
        }
    }

    void addChild(TreeItem* child)
    {
        m_children.push_back(child);
    }

private:
    TreeItem* m_parent;
    std::vector<TreeItem*> m_children;
}

QDomDocument - это тоже дерево. Поэтому при прохождении тегов можно составить своё собственное дерево. Но нужно понимать конечную цель.

Евгений, я думаю, что тут нужно будет разбирать строку. Дерево из QDomElement я построить могу - это не является какой-то сложной задачей. Задача не тривиальная потому, что если текст разбит на части внутри одного тега и эти части могут быть обернуты в дргуие теги, то, если взять значение головного тега, то он вернет строку целиком, т.е. захватит и текст других тегов. Вот в чем задача. Как разобрать строку и вернуть ее обратно именно в той последовательности, которая присутвует в файле. Есть наметки, но нужно проверить.

Евгений, а можно тогда уточнить вот такой момент. Были ли у вас случаи плана Мама мыла раму ? У меня собственно вопрос именно в этом, как взять и положить текст так в объект класса, чтобы потом модно было посторить обратно вышеописанную последовательность тегов?

Добрый день.

Нет, я таким не сталкивался, но вот таким образом вы можете разбить тот тег, на ноды, и забрать текст в нормально порядке, а потом вам уже не составит труда, как я думаю, записать всё обратно.

#include <iostream>
#include <QtXml/QDomDocument>
#include <QFile>
#include <QTextStream>
#include <QDebug>

int main()
{
    QDomDocument doc;
    doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""));
    QDomElement element = doc.createElement("element");
    element.appendChild(doc.createTextNode("TEXT 1"));
    QDomElement element1 = doc.createElement("element1");
    element1.appendChild(doc.createTextNode("text1"));
    element.appendChild(element1);
    element.appendChild(doc.createTextNode("TEXT 2"));
    doc.appendChild(element);
    QFile file("/home/dekadent/test.xml");
    if(file.open(QIODevice::WriteOnly)){
        QTextStream out(&file);
        out.setCodec("UTF-8");
        out << doc.toString();
        file.close();
    }
    std::cout << "start import" << std::endl;

    QDomDocument doc1;

    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        std::cout << "File not exist";
        return -1;
    }
    if(!doc1.setContent(&file)){
        file.close();
        return -1;
    }

    file.close();
    QDomNode node = doc1.firstChild();

    while (!node.isNull()) {
        QDomElement el1 = node.toElement();
        std::cout << el1.tagName().toStdString() << " " << el1.text().toStdString() << std::endl;
        if(el1.hasChildNodes()){
            std::cout << "size of child nodes " << el1.childNodes().size() << std::endl;
            for (int i = 0; i < el1.childNodes().size(); ++i)
            {
                std::cout << i << std::endl;
                QDomNode node2 = el1.childNodes().item(i);
                if (node2.isText())
                {
                    // Это текстовая нода, нужна иная обработка.
                    std::cout << node2.toText().data().toStdString();
                }
                QDomElement el2 =  node2.toElement();
                std::cout << el2.tagName().toStdString() << " " << el2.text().toStdString() << std::endl;
            }
        }
        node = node.nextSibling();
    }
    return 0;
}

Весь прикол в том, что метод nextSibling() , который вы использовали, не работает на текстовые ноды, то есть на QDomText. Я сам об этом не знал. Сейчас только попробовал, поэкспериментировал и догадался, как это дело работает.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Looking for a Job?
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

SV
Oct. 23, 2019, 1 a.m.
Semen Voloh

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:70points,
  • Rating points1
SS
Oct. 22, 2019, 2:31 p.m.
Samantha Smith

Qt - Test 001. Signals and slots

  • Result:52points,
  • Rating points-4
MB
Oct. 21, 2019, 1:25 a.m.
Mihail Bulatov

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
Last comments
Oct. 17, 2019, 2:17 a.m.
Evgenij Legotskoj

Используем, там где требуется :)
MP
Oct. 17, 2019, 2:15 a.m.
Mikhail Petrov

Совет: подключайте ресурсы динамически. Используйте Resource Compiler: https://doc.qt.io/qt-5/rcc.html
Oct. 16, 2019, 6:45 a.m.
Evgenij Legotskoj

Если это не чистой воды спам, а по делу, то без проблем. Но в таком случае лучше создавайте отдельный вопрос на форуме . При создании вопроса есть поле, в котором можно указать статью…
KK
Oct. 16, 2019, 6:39 a.m.
Kirill Kirilych

А тут можно ссылки на сторонний ресурс показывать? Нашёл на habr похожую статью, только там чуток отличается код и про локальный сервер написано, нужно чтоб кто то понимающий посмотрел и своё …
Now discuss on the forum
Oct. 23, 2019, 4:06 a.m.
Evgenij Legotskoj

Ну если после обновления начало появляться, то тогда откатить драйвера. А вообще, если это жить не мешает и код работает как и раньше, то просто проигнорировать эти сообщения.
Oct. 22, 2019, 2:42 a.m.
Pavel K.

Всем привет , Пытаюсь реализовать класс для работы с блютуз (Bluetooth Handler) для мобилки , с использование QBluetoothDeviceInfo и QBluetoothDeviceDiscoveryAgent . Может у кого е…
Oct. 22, 2019, 2:16 a.m.
Pavel K.

попробуй сделать через свой собственный компонет , те возьми контрол Component, например , переорпедели как свой , в нем что нить типо проперти type : disk1, disk2 (сделай метод в структуре …
E
Oct. 22, 2019, 12:03 a.m.
Evgenij_Kanusovskij@1981

Этот алгоритм предназначен для того чтобы исключить из обработки строки содержащие буквенные символы. Если Вам не трудно опишите пожалуйста как бы Вы написали этот алгоритм, желательно в коде?
MP
Oct. 21, 2019, 7:03 a.m.
Mikhail Petrov

Зависит от вашей задачи. Можете обратить внимание на этот пример: https://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html QQmlListProperty используется мною достаточно ч…
EVILEG
About
Services
© EVILEG 2015-2019
Recommend hosting TIMEWEB