简体   繁体   English

QML Qt-解析XML并将其转换为LisView的ListModel

[英]QML Qt- Parse XML and convert it as a LisView's ListModel

I'm new to Qt and QML. 我是Qt和QML的新手。 With that said, I am making a editable list in QML which I would like to import and export as XML file. 话虽如此,我正在QML中创建一个可编辑列表,我想将其导入和导出为XML文件。 Right now I'm stuck on importing it from XML file and setting it as my ListView 's model from the C++ side. 现在,我停留在从XML文件导入并将其设置为C ++端的ListView模型上。

I'm hoping I can transform the XML to a form I want to be able to add, remove and edit rows in my ListView from the QML side, so using XmlListModel looks like a bad idea, ie it doesn't offer those abilities. 我希望可以将XML转换为希望从QML端添加,删除和编辑ListView中的行的XmlListModel ,因此使用XmlListModel看起来是个坏主意,即它不提供这些功能。

my main.qml in which I am choosing the file location: 我在其中选择文件位置的main.qml:

    FileDialog {
        id: exportDialog
        title: "Please choose an XML TV file"
        nameFilters: [("*.xml")]

        onAccepted: {
            fileio.parse(importDialog.fileUrl)
        }
        onRejected: {
            console.log("Canceled")
        }
    }

My C++ header file in which I would like the conversion to happen: 我希望在其中进行转换的C ++头文件:

#ifndef FILEIO_H
#define FILEIO_H

#include <QObject>
#include <QFile>
#include <QTextStream>
#include <QXmlStreamReader>
#include <QDebug>

class FileIO : public QObject
{
    Q_OBJECT

public slots:
    bool parse(const QString& source)
    {
        if (source.isEmpty())
            return false;

        QFile file(source);
        if (!file.open(QFile::WriteOnly | QFile::Truncate))
            return false;    

        QFile* mjau = new QFile(source);
        if (!mjau->open(QIODevice::ReadOnly | QIODevice::Text)) {
                printf("Load XML File Problem");
                return false;
        }

        QXmlStreamReader reader(mjau);
        while(!reader.atEnd() && !reader.hasError()) {
            if(reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "parent") {
                 qDebug() << reader.readElementText();
                //printf(reader.readElementText())
            }
        }
    }
public:
    FileIO() {}
};

#endif // FILEIO_H

Example of xml file I'd like to parse, multitude of entries: 我想解析的xml文件示例,条目众多:

<notes>
    <note>
        <heading>Help</heading>
        <body>I want to make this work!</body>
    </note>
    <note>
        <heading>Because</heading>
        <body>I love QML <3</body>
    </note>
    ...
</notes>

To something like this: 对于这样的事情:

ListModel {
    id: notes
    ListElement {
        heading: "Help"
        body: "I want to make this work!"
    }
    ListElement {
        heading: "Because"
        body: "I love QML <3"
    }
}

Right now, when I choose the XML file nothing happens, but that same file is "cleaned out", becomes a blank .xml file. 现在,当我选择XML文件时,什么也没发生,但是该文件被“清除”了,成为空白的.xml文件。 How could I parse it properly, and after that, convert the parsed data into QML's ListView ListModel or any model that can support editing from the QML's side? 我如何正确解析它,然后将解析后的数据转换为QML的ListView ListModel或任何支持从QML一侧进行编辑的模型?

--UPDATE-- Parsing of the XML file will be a one-time procedure, after the parse I intend to work with the data in javascript, so it would be cool if the data could be parsed in JSON object structure. --UPDATE-- XML文件的解析将是一次性过程,在解析之后,我打算使用javascript中的数据,因此如果可以用JSON对象结构解析数据,那将是很酷的事情。

You should not convert it into a ListModel . 您不应该将其转换为ListModel Instead implement your own descendent of the QAbstractListModel that has your needed capatibilities. 而是实现您自己的具有所需功能的QAbstractListModel的后代。

However there is likely a reason, why Qt does provide the XmlListModel as read-only. 但是,可能有一个原因,为什么Qt确实将XmlListModel提供为只读。 You can't just insert into a file. 您不能只插入文件中。 (AFAIK) So if a entry is added or removed, and that change is not at the very end of the file, the whole content needs to be copied. (AFAIK)因此,如果添加或删除条目,并且该更改不在文件的最后,则需要复制整个内容。 And that is needed to be done, when ever the data changes. 每当数据更改时,都需要这样做。 Not good for performance. 对性能不好。

If you consider doing something like that, don't write back permanently. 如果您考虑进行此类操作,请不要永久回信。 Think, when it is a good time to do the write-back. 想一想,何时是进行回写的好时机。 An obvious point is when the model is being destroyed. 一个明显的观点是何时模型被销毁。 But as there might be some problems, so the object can't be destroyed properly, you might want to save every now and then. 但是由于可能存在一些问题,因此无法正确销毁该对象,因此您可能希望不时地保存该对象。

You might use a timer, to save, eg 10 Seconds after a change (expecting, that if one change happened, many changes will happen soon after) 您可以使用计时器来保存例如更改后的10秒(期望如果发生了一项更改,则不久之后将发生许多更改)

You might also use a more complex format for the XML, where you indeed just append basically logging the changes. 您可能还会对XML使用更复杂的格式,实际上,您实际上只是追加基本记录更改的日志。 From time to time you do a clean-up rewriting the file, so that the history is lost, but the changes are really applied to your xml structure. 有时您会进行清理以重写该文件,以便丢失历史记录,但所做的更改实际上已应用于您的xml结构。

In the end, I've used QDomDocument class to read XML file, iterate through all of the nodes and write values that I want to JSON objects like so: 最后,我使用QDomDocument类读取XML文件,遍历所有节点,并将想要的值写入JSON对象,如下所示:

QDomElement root = doc.firstChildElement();
QDomNodeList programme = root.elementsByTagName("node");
nodeCollection.push_back(ListElements(program, "title", "lang"));

... ...

QJsonObject ListElements (QDomElement root, QString tagname, QString attribute)
{

        QDomNodeList items = root.elementsByTagName(tagname);

        for(int i = 0; i < items.count(); i++)
        {
            QDomNode itemnode = items.at(i);
            if (itemnode.isElement())
            {
                QDomElement itemElement = itemnode.toElement();
                qInfo() << itemElement.tagName(); // <-element name
                qInfo() << itemElement.attribute("lang"); // <-element attribute
                qInfo() << itemElement.text(); // <-element text

// putting the values above inside JSOn object:

                auto nodeData = QJsonObject(
                {
                qMakePair(QString(itemElement.tagName()), QJsonValue(itemElement.text())),
                qMakePair(QString("lang"), QJsonValue(itemElement.attribute("lang"))),
                });

                return nodeData;
            }
        }
    }

so this: 所以这:

  <node>
    <title lang="en">Title1</title>
    <category lang="en">Category1</category>
    <desc lang="en">Description1</desc>
  </node>

becomes (this is what ListElements returns): 变为(这是ListElements返回的内容):

 QJsonObject({"title":"Title1","lang":"en"})
 QJsonObject({"category":"Category1","lang":"en"})
 QJsonObject({"desc":"Description1","lang":"en"})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM