Qt读写XML文档

发布于:2025-05-12 ⋅ 阅读:(19) ⋅ 点赞:(0)

XML 结构与概念简介

XML(可扩展标记语言) 是一种用于存储和传输结构化数据的标记语言。其核心特性包括:

1、树状结构:XML 数据以层次化的树形结构组织,包含一个根元素(Root Element),其他元素作为其子节点。
2、标签(Tag):通过开始标签(如 )和结束标签(如 )定义元素,标签名区分大小写。
3、属性(Attribute):附加在标签上的键值对,如 。
4、文本内容:元素之间的纯文本,如 Qt5 Cadaques
5、注释与声明:以 标记注释,以 <?xml version="1.0" encoding="UTF-8"?> 开头声明版本和编码。

Qt 读写 XML 示例

<?xml version='1.0' encoding='UTF-8'?>
<books>
    <book id="1">
        <title>Qt5 Cadaques</title>
        <author>Jake Petroules</author>
        <price>29.99</price>
    </book>
    <book id="2">
        <title>C++ Primer</title>
        <author>Stanley B. Lippman</author>
        <price>39.99</price>
    </book>
    <mybook id="3" title="C# forever"/>
    <book id="4">
        <title>Effective Modern C++</title>
        <author>Scott Meyers</author>
        <price>49.99</price>
    </book>
</books>

在Qt中读写XML文档常用的两种方式:

1、基于DOM(文档对象模型),核心类为QDomDocument

优点:
易于操作:支持XPath查询,便于遍历和修改节点。
完整文档处理:适合需要整体分析或频繁修改文档结构的场景。
读写功能:既能读取XML文件,也可生成并保存XML文档。
缺点:
内存消耗高:需将整个文档加载到内存,处理大文件时效率低下。
性能瓶颈:解析和生成速度较慢,不适合流式或实时处理。
适用场景:
中小型XML文件、需要随机访问节点或修改文档结构的场景。
示例代码

// 读取 XML 文件,展示所有书籍信息
void DomReadXML(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "无法打开文件:" << filePath;
        return;
    }

    QDomDocument doc;
    if (!doc.setContent(&file)) {
        qDebug() << "无法解析 XML 文件";
        file.close();
        return;
    }
    file.close();

    QDomElement root = doc.documentElement();
    QDomNodeList bookList = root.elementsByTagName("book");

    for (int i = 0; i < bookList.count(); ++i) {
        QDomElement book = bookList.at(i).toElement();
        QString id = book.attribute("id");
        qDebug() << "书籍 ID:" << id;

        QDomElement title = book.firstChildElement("title");	
        qDebug() << "标题:" << (title.isNull() ? "N/A" : title.text());

        QDomElement author = book.firstChildElement("author");
        qDebug() << "作者:" << (author.isNull() ? "N/A" : author.text());

        QDomElement price = book.firstChildElement("price");
        qDebug() << "价格:" << (price.isNull() ? "N/A" : price.text());

        qDebug() << "-------------------";
    }
}
// 写入 XML 文件,追加新书籍
void DomWriteXML(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "无法打开文件用于读取:" << filePath;
        return;
    }

    QDomDocument doc;
    if (!doc.setContent(&file)) {
        qDebug() << "无法读取文档内容";
        file.close();
        return;
    }
    file.close();

    QDomElement root = doc.documentElement();

    // 创建新 <book> 元素
    QDomElement newBook = doc.createElement("book");
    newBook.setAttribute("id", "4");

    QDomElement title = doc.createElement("title");
    title.appendChild(doc.createTextNode("Effective Modern C++"));

    QDomElement author = doc.createElement("author");
    author.appendChild(doc.createTextNode("Scott Meyers"));

    QDomElement price = doc.createElement("price");
    price.appendChild(doc.createTextNode("49.99"));

    newBook.appendChild(title);//title作为newBook的子节点
    newBook.appendChild(author);//author作为newBook的子节点
    newBook.appendChild(price);//price作为newBook的子节点

    root.appendChild(newBook);//newBook作为根元素的子节点

    // 保存更新后的文档
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
        qDebug() << "无法打开文件用于写入:" << filePath;
        return;
    }

    QTextStream stream(&file);
    doc.save(stream, 4); // 缩进 4 空格
    file.close();

    qDebug() << "成功写入 XML 文件";
}

2、流式处理,核心类为QXmlStreamReader(读取) 和 QXmlStreamWriter(写入)

流式读取(QXmlStreamReader)
基本概念:
基于拉模型的流式解析器,逐行读取XML文件,按需处理标记(Token),无需加载整个文档。
优点:
高效低内存:适合处理超大XML文件,内存占用低。
易用性:相比SAX更简洁,通过循环读取Token解析数据。
快速访问:仅解析所需部分,跳过无关内容。
缺点:
顺序访问限制:只能向前遍历,无法回溯或随机访问。
状态管理复杂:需手动维护解析状态,处理嵌套结构时逻辑较繁琐。
适用场景:
读取大文件、仅需提取部分数据或流式处理场景(如日志解析)。
示例代码

// 读取 XML 文件
void StreamReadXML(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "无法打开文件:" << filePath;
        return;
    }

    QXmlStreamReader reader(&file);
    while (!reader.atEnd()) {
        QXmlStreamReader::TokenType token = reader.readNext();
        if (token == QXmlStreamReader::StartElement) {
            if (reader.name() == "book") {
                QXmlStreamAttributes attrs = reader.attributes();
                QString id = attrs.value("id").toString();
                qDebug() << "书籍 ID:" << id;
            } else if (reader.name() == "title") {
                qDebug() << "标题:" << reader.readElementText();
            } else if (reader.name() == "author") {
                qDebug() << "作者:" << reader.readElementText();
            } else if (reader.name() == "price") {
                qDebug() << "价格:" << reader.readElementText();
            } else if (reader.name() == "mybook") {
                QXmlStreamAttributes attrs = reader.attributes();
                qDebug() << "mybook id:" << attrs.value("id").toString();
                qDebug() << "mybook title:" << attrs.value("title").toString();
            }
        }
    }

    if (reader.hasError()) {
        qDebug() << "读取错误:" << reader.errorString();
    }

    file.close();
}

流式写入(QXmlStreamWriter)
基本概念:
用于顺序生成XML文档,通过API逐步写入标签、属性和内容。
优点:
高效写入:逐步生成XML,无需构建完整结构。
代码简洁:API设计直观,易于生成标准XML格式。
低内存占用:适合动态生成大型XML文件。
缺点:
结构依赖性强:需手动管理标签闭合和嵌套,易因逻辑错误导致格式异常。
不可修改:生成后无法直接修改已写入内容。
适用场景:
顺序生成XML文件、数据导出或日志记录等场景。
示例代码

// 写入 XML 文件
void StreamWriteXML(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
        qDebug() << "无法打开文件:" << filePath;
        return;
    }

    QXmlStreamWriter writer(&file);
    writer.setAutoFormatting(true); // 自动缩进
    writer.writeStartDocument();
    writer.writeStartElement("book");
    writer.writeAttribute("id", "4");

    writer.writeTextElement("title", "Effective Modern C++");
    writer.writeTextElement("author", "Scott Meyers");
    writer.writeTextElement("price", "49.99");

    writer.writeEndElement(); // book
    writer.writeEndDocument();

    file.close();
}

使用建议

1、对于纯读取、纯写入、纯追加(即对原文档不做修改)的场景,优先考虑流式处理,效率更高。
2、对于中小型XML文档且需要修改原有结构和内容,考虑使用DOM方式。


网站公告

今日签到

点亮在社区的每一天
去签到