Qt C++ :XML文件处理工具 <QXml>模块

文章目录

  • [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 处理
  • QXmlStreamReaderQXmlStreamWriter 是现代 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):启用自动缩进和换行。
相关推荐
扶尔魔ocy10 小时前
【QT常用技术讲解】QSerialPort串口开发,包含文件发送功能
qt
一只鱼^_10 小时前
力扣第470场周赛
数据结构·c++·算法·leetcode·深度优先·动态规划·启发式算法
greentea_201315 小时前
Codeforces Round 65 A. Way Too Long Words(71)
c++
Overboom17 小时前
[C++] --- 常用设计模式
开发语言·c++·设计模式
Univin17 小时前
C++(10.4)
开发语言·数据结构·c++
YxVoyager17 小时前
Qt C++ :QLayout 布局管理
c++·qt
KyollBM17 小时前
每日羊题 (质数筛 + 数学 | 构造 + 位运算)
开发语言·c++·算法
Univin19 小时前
C++(10.5)
开发语言·c++·算法
AA陈超20 小时前
虚幻引擎UE5专用服务器游戏开发-33 在上半身播放组合蒙太奇
c++·游戏·ue5·游戏引擎·虚幻