Qt中解析XML文件
在 Qt 里解析 XML 文件通常有两种主流方式:
- DOM(QDomDocument)
一次性把整个 XML 读进内存,生成一棵 DOM 树,适合体积不大、需要频繁随机访问或修改节点的场景。 - SAX(QXmlSimpleReader / QXmlStreamReader)
按事件流顺序读取,只占用很小内存,适合只读或解析超大 XML 的场景。
下面分别介绍:
一、DOM(QDomDocument)方式
1.首先pro 文件需加模块:
QT += xml
2.book.xml内容如下:
<bookstore>
<book id="1">
<title>Qt6 C++ GUI Programming</title>
<author>Lee</author>
<year>2022</year>
</book>
<book id="2">
<title>Advanced Qt</title>
<author>Smith</author>
<year>2023</year>
</book>
</bookstore>
具体代码如下:
#include <QCoreApplication>
#include<QFile>
#include<QDomDocument>
#include<QDebug>
bool LoadXmlDom(const QString& strFile)
{
QFile file(strFile);
if(!file.open(QIODevice::ReadOnly))
{
qWarning() << "Can Not Open File" << strFile;
return false;
}
QDomDocument doc;
QString strError;
int nErrLine = 0,nErrCol = 0;
if(!doc.setContent(&file,&strError,&nErrLine,&nErrCol))
{
qWarning() << "Prase Error at " << nErrLine <<":"<< nErrCol << ":"<< strError;
return false;
}
file.close();
QDomElement root = doc.documentElement();
QDomNodeList books = root.elementsByTagName("book");
for(int i=0;i<books.size();i++)
{
QDomElement book = books.at(i).toElement();
qDebug() << "id = "<< book.attribute("id");
qDebug() << "title = "<< book.firstChildElement("title").text();
qDebug() << "author = "<< book.firstChildElement("author").text();
qDebug() << "year = "<< book.firstChildElement("year").text();
}
return true;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Set up code that uses the Qt event loop here.
// Call a.quit() or a.exit() to quit the application.
// A not very useful example would be including
// #include <QTimer>
// near the top of the file and calling
// QTimer::singleShot(5000, &a, &QCoreApplication::quit);
// which quits the application after 5 seconds.
// If you do not need a running Qt event loop, remove the call
// to a.exec() or use the Non-Qt Plain C++ Application template.
LoadXmlDom(":/XML/res/xml_file/book.xml");
return a.exec();
}
代码运行结果:
小结:
1.QDomDocument:
QDomDocument
类是 Qt 中用于表示整个 XML 文档的核心类。 它作为整个 XML 文档树的入口点和容器,承载了文档的所有内容,包括元素、属性、注释、处理指令等。
QDomDocument
可以将一个符合格式的 XML 字符串或文件解析(“加载”)到内存中,并构建成一棵节点树(DOM 树)。
2.QDomNodeList:
QDomNodeList
类代表一个 QDomNode
对象的列表(集合)。 它本质上是一个只读的、动态的容器,用于存储和访问通过某些 DOM 操作(特别是查询)返回的多个节点。
你可以把它想象成一个临时的快照或查询结果集,里面包含了符合特定条件的所有节点。
QDomNodeList
通常不是由你手动创建的,而是通过调用其他 DOM 方法返回的。它的主要作用是提供一种统一的方式来处理和遍历查询到的节点集合。
3.QDomElement:
QDomElement
类是 Qt DOM 模块中用于表示 XML 元素(标签)的核心类。 它继承自 QDomNode
,是 DOM 树中最重要的节点类型,用于构建 XML 文档的骨架结构。
你可以把它想象成 XML 文档中的一个个带名字的容器或标签,比如 <book>
、 <name>
、 <price>
等,它既可以包含文本内容,也可以包含属性,还可以包含其他子元素。
二、SAX(QXmlSimpleReader / QXmlStreamReader)
使用QXmlStreamReader解析XML文件方式如下:
#include <QCoreApplication>
#include<QFile>
#include<QXmlStreamReader>
#include<QDebug>
bool LoadXmlStream(const QString& strFile)
{
QFile file(strFile);
if(!file.open(QIODevice::ReadOnly))
{
qWarning() << "Can Not Open File" << strFile;
return false;
}
QXmlStreamReader reader(&file);
// 用于临时存储当前book的数据
QString currentTag;
QMap<QString, QString> currentBook;
int bookCount = 0;
while (!reader.atEnd() && !reader.hasError()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartDocument) {
continue; // 跳过文档开始
}
if (token == QXmlStreamReader::StartElement) {
currentTag = reader.name().toString();
if (currentTag == "book")
{
// 开始一本新书,清空临时存储
currentBook.clear();
// 读取属性
QXmlStreamAttributes attributes = reader.attributes();
if (attributes.hasAttribute("id"))
{
currentBook["id"] = attributes.value("id").toString();
}
bookCount++;
qDebug() << "\n开始解析第" << bookCount << "本书,ID:" << currentBook["id"];
}
}
if (token == QXmlStreamReader::Characters)
{
// 只有当Characters不在空白处,且上一个StartElement是我们感兴趣的标签时才读取文本
if (!reader.isWhitespace() && !currentTag.isEmpty())
{
QString text = reader.text().toString();
// 存储文本到当前book的map中,键为标签名
if (currentTag != "bookstore" && currentTag != "book")
{
currentBook[currentTag] = text;
}
}
}
if (token == QXmlStreamReader::EndElement)
{
QString elementName = reader.name().toString();
if (elementName == "book")
{
// 一本书结束,输出或保存这本书的信息
qDebug() << "书名:" << currentBook.value("title");
qDebug() << "作者:" << currentBook.value("author");
qDebug() << "年份:" << currentBook.value("year");
qDebug() << "------";
}
// 遇到结束标签,清空当前标签,防止后面的Characters被误读
currentTag.clear();
}
}
if (reader.hasError())
{
qWarning() << "XML解析错误:" << reader.errorString();
}
file.close();
return 0;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Set up code that uses the Qt event loop here.
// Call a.quit() or a.exit() to quit the application.
// A not very useful example would be including
// #include <QTimer>
// near the top of the file and calling
// QTimer::singleShot(5000, &a, &QCoreApplication::quit);
// which quits the application after 5 seconds.
// If you do not need a running Qt event loop, remove the call
// to a.exec() or use the Non-Qt Plain C++ Application template.
qDebug() << "stream流 读取方式";
LoadXmlStream(":/XML/res/xml_file/book.xml");
return a.exec();
}
代码运行结果:
小结:
QXmlStreamReader:QXmlStreamReader 类概述
QXmlStreamReader
是 Qt 提供的一个用于读取 XML 文件的快速、高效的流式解析器。它采用"拉模式"(pull parser)解析方式,允许应用程序控制解析过程,按需读取XML内容。
三、两种方式的对比:
总结与选择
特性 | QXmlStreamReader (流) | QDomDocument (DOM) |
---|---|---|
内存使用 | 低,逐次读取 | 高,整体加载 |
性能 | 高,尤其对于大文件 | 相对较低,文件越大越明显 |
访问方式 | 顺序、只读、只向前 | 随机访问,可前后遍历 |
功能 | 读取 | 读取、修改、创建 |
易用性 | 需要手动控制流程,稍复杂 | API直观,易于理解和上手 |
适用场景 | 大型文件、只读、只需部分数据 | 小型配置文件、需要修改XML、结构简单 |
选择建议:
- 绝大多数情况下,优先选择
QXmlStreamReader
。特别是处理网络数据、日志文件等大型或未知大小的XML时,它的效率和稳定性更好。 - 当你需要修改XML结构或内容,或者XML文件很小,并且你希望代码更直观易读时,使用
QDomDocument
。 - 对于非常简单的配置读取,有时结合
QSettings
(支持XML格式)也可能是更便捷的选择。
适用场景 大型文件、只读、只需部分数据 | 小型配置文件、需要修改XML、结构简单 |