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 类表示。
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