文章目录
- [QXml 模块概览](#QXml 模块概览)
- [QDOM(Document Object Model)](#QDOM(Document Object Model))
- [QXmlStreamReader 高效 XML 读取器](#QXmlStreamReader 高效 XML 读取器)
- [QXmlStreamWriter 结构化 XML 写入器](#QXmlStreamWriter 结构化 XML 写入器)
Qt 提供了一套完善的 XML 处理工具,统称为 QXml
模块。它包含多种解析器和操作方式,适用于不同场景下的 XML 读写需求。
QXml 模块概览
Qt 的 XML 处理能力主要通过以下几类技术实现:
类/模块 | 类型 | 特点 | 适用场景 |
---|---|---|---|
QXmlStreamReader |
流式读取 | 低内存、高效、只进 | 大文件解析、配置读取 |
QXmlStreamWriter |
流式写入 | 高效、结构化输出 | 生成 XML 文件 |
QDomDocument / QDomElement |
DOM 模型 | 随机访问、可修改 | 小型 XML、频繁修改 |
QXmlQuery / QXmlSchema |
XPath/XSLT/Schema | 复杂查询与验证 | 高级 XML 处理 |
QXmlStreamReader
和QXmlStreamWriter
是现代 Qt 开发的首选,性能高、内存友好。QDom
适合小型、需要频繁修改的 XML 文档。
QDOM(Document Object Model)
QDom
模块提供了对 XML 文档的 DOM(Document Object Model)
解析支持,适用于需要随机访问、修改和构建 XML 文档的场景。
QDom
模块主要由以下几个核心类构成:
QDomDocument
: 表示整个 XML 文档,是所有其他节点的根容器。QDomElement
: 表示 XML 元素(标签),可以包含属性和子节点。QDomNode
: 所有节点类型的基类(如元素、文本、注释等)。QDomNodeList
: 存储一组 QDomNode 对象的列表,常用于存储查询结果。QDomAttr
: 表示元素的属性。QDomText
: 表示元素内的文本内容。QDomProcessingInstruction
: 表示处理指令(如<?xml version="1.0"?>
)。
创建与加载 XML 文档
创建空文档并添加根元素
clike
#include <QDomDocument>
#include <QFile>
#include <QTextStream>
QDomDocument doc("mydocument");
QDomElement root = doc.createElement("root");
doc.appendChild(root);
从文件加载 XML
clike
QFile file("config.xml");
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Cannot open file";
return;
}
QDomDocument doc("mydoc");
if (!doc.setContent(&file)) {
qWarning() << "Failed to parse XML";
file.close();
return;
}
file.close();
// 获取根元素
QDomElement root = doc.documentElement();
从字符串加载 XML
clike
QString xmlString = "<data><item>Value</item></data>";
QDomDocument doc;
doc.setContent(xmlString);
遍历与查询节点
获取根元素
clike
QDomElement root = doc.documentElement(); // 获取文档根元素
遍历子节点
clike
QDomNode node = root.firstChild();
while (!node.isNull()) {
if (node.isElement()) {
QDomElement element = node.toElement();
qDebug() << "Element:" << element.tagName();
}
node = node.nextSibling();
}
根据标签名查找元素
clike
QDomNodeList elements = root.elementsByTagName("item");
for (int i = 0; i < elements.count(); ++i) {
QDomElement item = elements.at(i).toElement();
qDebug() << "Item value:" << item.text();
}
QString text = element.text(); // QDomElement 的便捷方法,比 firstChild().nodeValue() 更安全
使用 firstChildElement() 快速定位
clike
QDomElement child = root.firstChildElement("child"); // 获取第一个名为 "child" 的子元素
QDomElement grandChild = child.firstChildElement("grandChild");
创建与修改节点
创建新元素并添加属性
clike
QDomElement newElement = doc.createElement("user");
newElement.setAttribute("id", "123");
newElement.setAttribute("name", "Alice");
添加文本内容
clike
QDomText textNode = doc.createTextNode("Hello World");
newElement.appendChild(textNode);
将新元素添加到父节点
clike
root.appendChild(newElement);
修改现有元素内容
clike
QDomElement firstItem = root.firstChildElement("item");
firstItem.setTagName("updatedItem"); // 修改标签名
firstItem.setAttribute("status", "processed");
firstItem.firstChild().setNodeValue("New Value"); // 修改文本内容
删除节点
clike
QDomElement elementToRemove = root.firstChildElement("obsolete");
if (!elementToRemove.isNull()) {
root.removeChild(elementToRemove);
}
保存 XML 到文件
clike
QFile outFile("output.xml");
if (outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream stream(&outFile);
doc.save(stream, 4); // 4 表示缩进空格数
outFile.close();
}
使用示例
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings>
<appName>MyAwesomeApp</appName>
<version>1.0.0</version>
<debugMode>true</debugMode>
<logLevel>INFO</logLevel>
</appSettings>
<userPreferences>
<theme>Dark</theme>
<language>en_US</language>
<autoSaveInterval>300</autoSaveInterval>
</userPreferences>
</configuration>
clike
// modify_xml.cpp
#include <QDomDocument>
#include <QFile>
#include <QTextStream>
#include <QDebug>
bool modifyConfig() {
QFile file("config.xml");
// 步骤1:读取文件
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "❌ 无法打开文件:" << file.fileName();
return false;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
file.close();
qDebug() << "❌ 无法解析XML内容";
return false;
}
file.close();
// 步骤2:获取根元素
QDomElement root = doc.documentElement();
if (root.tagName() != "configuration") {
qDebug() << "❌ 无效的根元素:" << root.tagName();
return false;
}
// 步骤3:定位并修改节点(仅修改,不添加/删除)
// 修改应用名称
QDomElement appNameElem = root.firstChildElement("appSettings")
.firstChildElement("appName");
if (!appNameElem.isNull()) {
appNameElem.firstChild().setNodeValue("UpdatedApp");
qDebug() << "✅ 已修改 appName 为:UpdatedApp";
}
// 修改版本号
QDomElement versionElem = root.firstChildElement("appSettings")
.firstChildElement("version");
if (!versionElem.isNull()) {
versionElem.firstChild().setNodeValue("2.1.0");
qDebug() << "✅ 已修改 version 为:2.1.0";
}
// 修改调试模式
QDomElement debugElem = root.firstChildElement("appSettings")
.firstChildElement("debugMode");
if (!debugElem.isNull()) {
debugElem.firstChild().setNodeValue("false");
qDebug() << "✅ 已修改 debugMode 为:false";
}
// 修改主题
QDomElement themeElem = root.firstChildElement("userPreferences")
.firstChildElement("theme");
if (!themeElem.isNull()) {
themeElem.firstChild().setNodeValue("Light");
qDebug() << "✅ 已修改 theme 为:Light";
}
// 修改语言
QDomElement langElem = root.firstChildElement("userPreferences")
.firstChildElement("language");
if (!langElem.isNull()) {
langElem.firstChild().setNodeValue("zh_CN");
qDebug() << "✅ 已修改 language 为:zh_CN";
}
// 步骤4:保存修改回文件
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug() << "❌ 无法写入文件:" << file.fileName();
return false;
}
QTextStream stream(&file);
stream.setCodec("UTF-8"); // 确保编码正确
doc.save(stream, 4); // 4个空格缩进,格式清晰
file.close();
qDebug() << "✅ 所有修改已成功保存到 config.xml";
return true;
}
QXmlStreamReader 高效 XML 读取器
QXmlStreamReader
采用"拉式解析"(pull parsing)模型,逐个读取 XML 事件(如开始标签、文本、结束标签),内存占用极小。
clike
#include <QXmlStreamReader>
#include <QFile>
QFile file("data.xml");
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Cannot open file";
return;
}
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartDocument) {
qDebug() << "Start document:" << reader.documentVersion();
}
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == "book") {
// 读取属性
QString id = reader.attributes().value("id").toString();
qDebug() << "Found book with ID:" << id;
}
}
if (token == QXmlStreamReader::Characters && !reader.isWhitespace()) {
qDebug() << "Text:" << reader.text().toString();
}
if (token == QXmlStreamReader::EndElement) {
if (reader.name() == "book") {
qDebug() << "End of book element";
}
}
}
if (reader.hasError()) {
qWarning() << "XML Error:" << reader.errorString();
}
file.close();
常用方法:
- readNext():读取下一个 XML 事件。
- name():获取当前元素或属性的名称。
- attributes():返回当前元素的属性集合(QXmlStreamAttributes)。
- text():获取文本内容。
- skipCurrentElement():跳过当前元素及其所有子元素(处理未知或复杂嵌套时非常有用)。
QXmlStreamWriter 结构化 XML 写入器
QXmlStreamWriter
提供了简单、安全的方式来生成格式良好的 XML 文件。
clike
#include <QXmlStreamWriter>
#include <QFile>
QFile file("output.xml");
if (!file.open(QIODevice::WriteOnly)) {
return;
}
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true); // 自动格式化(缩进)
writer.writeStartDocument(); // <?xml version="1.0" encoding="UTF-8"?>
writer.writeStartElement("library");
writer.writeStartElement("book");
writer.writeAttribute("id", "1");
writer.writeTextElement("title", "C++ Primer");
writer.writeTextElement("author", "Stanley Lippman");
writer.writeEndElement(); // </book>
writer.writeEndElement(); // </library>
writer.writeEndDocument(); // 结束文档
file.close();
常用方法:
- writeStartDocument() / writeEndDocument():文档开始与结束。
- writeStartElement() / writeEndElement():元素开始与结束。
- writeAttribute():写入属性。
- writeTextElement():快速写入带文本的元素。
- writeComment():写入注释。
- setAutoFormatting(bool):启用自动缩进和换行。