天天看点

【Qt】DOM读取XML文档

00. 目录

文章目录

    • 01. 概述
    • 02. 开发环境
    • 03. XML文档示例
    • 04. DOM读取XML文档内容
    • 05. 预留
    • 06. 附录

DOM(Document Object Model,文档对象模型),是W3C的推荐标准。它提供了一个接口来访问和改变一个XML文件的内容和结构,可以将XML文档表示为一个存储在内存中具有层次的树视图。文档本身由QDomDocument对象来表示,而文档树中所有的DOM节点都是QDomNode类的子类。

在Qt中使用QDomProcessingInstruction类来表示XML说明。元素对应QDomElement类。属性对应QDomAttr类。文本内容由QDomText类表示。所有的DOM节点,比如这里的说明、元素、属性和文本等,都使用QDomNode来表示。

元素对应QDomElement 类。元素可以包含属性,用来描述元素的相关信息,属性名和属性值在元素的起始标签中给出。

属性值必须在单引号或者双引号中。属性对应QDomAttr 类。

元素中可以包含子元素,也可以只包含文本内容,比如这里<first-name> Mary </first-name>中的Mary就是文本内容,文本内容由QDomText 类表示。

【Qt】DOM读取XML文档

XML(ExtensibleMarkup Language,可扩展标记语言),是一种类似于HTML的标记语言,但它的设计目的是用来传输数据,而不是显示数据。XML的标签没有被预定义,用户需要在使用时自行进行定义。XML是W3C(万维网联盟)的推荐标准。相对于数据库表格的二维表示,XML使用的树形结构更能表现出数据的包含关系,作为一种文本文件格式,XML简单明了的特性使得它在信息存储和描述领域非常流行。

​ 在Qt中提供了Qt XML模块来进行XML文档的处理,这里主要提供了两种解析方法: DOM方法,可以进行读写;SAX方法,可以进行读取。从Qt 5开始,Qt XML模块不再进行维护,而是推荐使用Qt Core模块中基于流的方法,分别使用QXmlStreamReader和QXmlStreamWriter进行读取和写入。本文档先来讲解一下DOM的方法。要在项目中使用Qt XML模块,需要在项目文件(.pro文件)中添加QT += xml一行代码。

Windows系统:Windows10

Qt版本:Qt5.15、Qt6

规范的XML文档如下所示:

<?xml version="1.0"encoding="UTF-8"?>
<library>
   <book id="01">
       <title>Qt</title>
       <author>LiMing</author>
   </book>
   <book id="02">
       <title>Linux</title>
       <author>ZhengGang</author>
   </book>
</library>
           

每个XML文档都由XML说明(或者称为XML序言)开始,它是对XML文档处理的环境和要求的说明,比如这里的,其中xml version=“1.0”,表明使用的XML版本号,这里字母是区分大小写的;encoding=“UTF-8”是使用的编码,指出文档是使用何种字符集建立的,默认值为Unicode编码。XML文档内容由多个元素组成,一个元素由起始标签<标签名>和终止标签以及两个标签之间的内容组成,而文档中第一个元素被称为根元素,比如这里的,XML文档必须有且只有一个根元素。元素的名称是区分大小写的,元素还可以嵌套,比如这里的library、book、title和author等都是元素。元素可以包含属性,用来描述元素的相关信息,属性名和属性值在元素的起始标签中给出,格式为<元素名 属性名=“属性值”>,如,属性值必须在单引号或者双引号中。在元素中可以包含子元素,也可以只包含文本内容,比如这里的中的Qt就是文本内容。

Dom(Document Object Model,即文档对象模型)把XML文档转换成应用程序可以遍历的树形结构,这样便可以随机访问其中的节点。它的缺点是需要将整个XML文档读入内存,消耗内存较多。

在Qt中使用QDomProcessingInstruction类来表示XML说明,元素对应QDomElement类,属性对应QDomAttr类,文本内容由QDomText类表示。所有的DOM节点,比如这里的说明、元素、属性和文本等,都使用QDomNode来表示,然后使用对应的isProcessingInstruction()、isElement()、isAttr()和isText()等函数来判断是否是该类型的元素,如果是,那么就可以使用toProcessingInstruction()、toElement()、toAttr()和toText()等函数转换为具体的节点类型。

4.1 新建Qt控制台应用QtConsole Application,项目名称为16XML。

4.2 在16XML.pro配置文件中添加下一行

QT += xml
           

4.3 main.cpp内容如下

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    //新建QDomDocument类对象 代表一个XML文档
    QDomDocument doc;

    //创建test.xml文件
    QFile file("../test.xml");

    //以只读方式打开该文件
    bool ret = file.open(QIODevice::ReadOnly);
    if (!ret)
    {
        qDebug() << "打开文件失败";
        file.close();
        return 1;
    }

    //将文件内容读到doc中
    ret = doc.setContent(&file);
    if (!ret)
    {
        qDebug() << "设置内容失败";
        file.close();
        return 1;
    }

    file.close();

    //获取doc第一个节点 即XML说明
    QDomNode firstNode = doc.firstChild();

    //输出XML说明
    qDebug() << firstNode.nodeName() << firstNode.nodeValue();


    return 0;
    //return a.exec();
}
           

执行结果

“xml” “version=‘1.0’ encoding=‘UTF-8’”

不愿意看到字符串两边的引号,可以将源码中得qDebug()语句更改如下:

//输出XML说明
    //qDebug() << firstNode.nodeName() << firstNode.nodeValue();
    qDebug() << qPrintable(firstNode.nodeName())
             << qPrintable(firstNode.nodeValue());
           
xml version='1.0' encoding='UTF-8'
           

4.4 继续修改main.cpp文件内容如下:

#include <QCoreApplication>
#include <QDebug>
#include <QDomDocument>
#include <QDomNode>
#include <QtXml>
#include <QFile>


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    //新建QDomDocument类对象 代表一个XML文档
    QDomDocument doc;

    //创建test.xml文件
    QFile file("../test.xml");

    //以只读方式打开该文件
    bool ret = file.open(QIODevice::ReadOnly);
    if (!ret)
    {
        qDebug() << "打开文件失败";
        file.close();
        return 1;
    }

    //将文件内容读到doc中
    ret = doc.setContent(&file);
    if (!ret)
    {
        qDebug() << "设置内容失败";
        file.close();
        return 1;
    }

    file.close();

    //获取doc第一个节点 即XML说明
    QDomNode firstNode = doc.firstChild();

    //输出XML说明
    //qDebug() << firstNode.nodeName() << firstNode.nodeValue();
    qDebug() << qPrintable(firstNode.nodeName())
             << qPrintable(firstNode.nodeValue());


    //返回根元素
    QDomElement docElem = doc.documentElement();
    //返回根节点的第一个子节点
    QDomNode root = docElem.firstChild();
    while(!root.isNull())
    {
        //如果节点是元素
        if (root.isElement())
        {
            //将其转换为元素
            QDomElement e = root.toElement();
            //返回元素的标记 和id属性的值
            qDebug() << qPrintable(e.tagName())
                     << qPrintable(e.attribute("id"));
        }

        //下一个兄弟节点
        root = root.nextSibling();
    }

    return 0;
    //return a.exec();
}

           

执行结果如下:

xml version='1.0' encoding='UTF-8'
book 01
book 02
           

4.5 继续修改main.cpp文件,得到所有节点

#include <QCoreApplication>
#include <QDebug>
#include <QDomDocument>
#include <QDomNode>
#include <QtXml>
#include <QFile>


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    //新建QDomDocument类对象 代表一个XML文档
    QDomDocument doc;

    //创建test.xml文件
    QFile file("../test.xml");

    //以只读方式打开该文件
    bool ret = file.open(QIODevice::ReadOnly);
    if (!ret)
    {
        qDebug() << "打开文件失败";
        file.close();
        return 1;
    }

    //将文件内容读到doc中
    ret = doc.setContent(&file);
    if (!ret)
    {
        qDebug() << "设置内容失败";
        file.close();
        return 1;
    }

    file.close();

    //获取doc第一个节点 即XML说明
    QDomNode firstNode = doc.firstChild();

    //输出XML说明
    //qDebug() << firstNode.nodeName() << firstNode.nodeValue();
    qDebug() << qPrintable(firstNode.nodeName())
             << qPrintable(firstNode.nodeValue());


    //返回根元素
    QDomElement docElem = doc.documentElement();
    //返回根节点的第一个子节点
    QDomNode root = docElem.firstChild();
    while(!root.isNull())
    {
        //如果节点是元素
        if (root.isElement())
        {
            //将其转换为元素
            QDomElement e = root.toElement();
            //返回元素的标记 和id属性的值
            qDebug() << qPrintable(e.tagName())
                     << qPrintable(e.attribute("id"));

            //获取元素e的所有子节点的列表
            QDomNodeList list = e.childNodes();
            //遍历该列表
            for (int i = 0; i < list.size(); i++)
            {
                QDomNode node = list.at(i);
                if (node.isElement())
                {
                    qDebug() << " " << qPrintable(node.toElement().tagName())
                             << qPrintable(node.toElement().text());
                }
            }


        }

        //下一个兄弟节点
        root = root.nextSibling();
    }

    return 0;
    //return a.exec();
}

           
xml version='1.0' encoding='UTF-8'
book 01
  title Qt
  author LiMing
book 02
  title Linux
  author ZhengGang
           

继续阅读