Qt文件:XML文件

XML文件

  • [1. XML文件结构](#1. XML文件结构)
    • [1.1 基本结构](#1.1 基本结构)
    • [1.2 XML 格式规则](#1.2 XML 格式规则)
    • [1.3 XML vs HTML](#1.3 XML vs HTML)
  • [2. XML文件操作](#2. XML文件操作)
    • [2.1 DOM 方式(QDomDocument)](#2.1 DOM 方式(QDomDocument))
    • [2.2 SAX 方式(QXmlStreamReader/QXmlStreamWriter)](#2.2 SAX 方式(QXmlStreamReader/QXmlStreamWriter))
    • [2.3 对比分析](#2.3 对比分析)
  • [3. 使用场景](#3. 使用场景)
    • [3.1 存储配置信息](#3.1 存储配置信息)
    • [3.2 数据交换与存储](#3.2 数据交换与存储)
    • [3.3 界面布局与资源定义](#3.3 界面布局与资源定义)
    • [3.4 网络通信与 API 交互](#3.4 网络通信与 API 交互)
    • [3.5 插件与扩展系统](#3.5 插件与扩展系统)
    • [3.6 国际化(i18n)与翻译文件](#3.6 国际化(i18n)与翻译文件)

1. XML文件结构

XML(eXtensible Markup Language,可扩展标记语言)是一种用于存储和传输数据的标记语言,具有平台无关性、结构清晰、易于阅读和编写等特点。

1.1 基本结构

一个标准的 XML 文件通常包含以下部分:

  1. XML 声明(可选):指定 XML 版本、编码方式(如 UTF-8)等信息。
xml 复制代码
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
复制代码
version:必填,指定 XML 版本(常用1.0)。
encoding:可选,指定字符编码(默认UTF-8,需与文件实际编码一致)。
standalone:可选,指定是否为独立文件(yes表示不依赖外部 DTD / 模式,no表示依赖)。
  1. 文档类型定义(DTD,可选):定义 XML 文档的结构和元素规则(可引用外部 DTD 或内嵌)。
xml 复制代码
<!DOCTYPE root-element SYSTEM "filename.dtd">
复制代码
root-element:根元素名称。
SYSTEM:引用外部 DTD 文件。
xml 复制代码
<!DOCTYPE books [
    <!ELEMENT books (book+)>
    <!ELEMENT book (title, author)>
    <!ATTLIST book id CDATA #REQUIRED>
]>
  1. 根元素:XML 文档的顶级元素,所有内容必须包含在根元素内。
xml 复制代码
<root>
    <!-- 子元素 -->
</root>
xml 复制代码
<books>
    <book id="1">
        <title>Qt编程</title>
    </book>
</books>
  1. 元素(标签):由开始标签()、结束标签()和内容(可选)组成。
    规则:
    • 标签名区分大小写(如和是不同标签)。
    • 必须正确嵌套,不能交叉。
    • 空元素可使用自闭合标签(如<-img src="image.jpg" />)。
xml 复制代码
<book id="1">
    <title>XML入门</title>
    <author>John Doe</author>
</book>
  1. 属性:为元素提供额外信息(键值对形式)。
    规则:
    • 属性值必须用双引号(")或单引号(')包裹。
    • 同一元素中属性名唯一。
xml 复制代码
<book id="1" category="technology">
    <title>XML实战</title>
</book>
  1. 文本内容:元素内部的文本内容,可包含转义字符或 CDATA 节。

    CDATA 节:用于包含无需转义的原始文本(如代码片段),语法:
xml 复制代码
<description><![CDATA[内容不转义 <script>...</script>]]></description>

1.2 XML 格式规则

  1. 严格区分大小写:标签名、属性名、属性值均区分大小写(如和<title>是不同标签)。
  2. 正确闭合标签:每个开始标签必须有对应的结束标签,空元素需自闭合(如<''br />)。
  3. 唯一根元素:每个 XML 文档必须有且仅有一个根元素,所有其他元素都是根元素的子元素。
  4. 正确嵌套标签:标签必须逐层嵌套,不能交叉。例如:
xml 复制代码
<!-- 正确嵌套 -->
<parent>
    <child>内容</child>
</parent>

<!-- 错误(交叉嵌套) -->
<parent>
    <child>内容
</parent>
</child>
  1. 属性值必须加引号:属性值必须用单引号或双引号包裹,例如:
xml 复制代码
<book id='1' name="XML教程" />
  1. 禁止使用特殊字符:文本内容中不能直接使用<、>、&等特殊字符,需用转义代码或 CDATA 节处理。

1.3 XML vs HTML

特性 XML HTML
设计目标 存储和传输数据 展示数据和定义网页结构
标签定义 自定义标签(可扩展) 预定义标签(如 , )
语法严格性 严格(必须正确闭合、嵌套) 相对宽松(部分浏览器可容错)
用途 配置文件、数据交换、API 返回格式等 网页内容呈现
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<students>
    <student id="S001">
        <name>Alice</name>
        <age>20</age>
        <courses>
            <course name="Math" score="90" />
            <course name="Physics" score="85" />
        </courses>
    </student>
    <student id="S002">
        <name>Bob</name>
        <age>21</age>
        <courses>
            <course name="Programming" score="95" />
        </courses>
    </student>
</students>

2. XML文件操作

在 Qt 中处理 XML 文件主要有两种方式:DOM 方式(使用QDomDocument)和SAX 方式(使用QXmlStreamReader和QXmlStreamWriter)。

2.1 DOM 方式(QDomDocument)

特点:

  1. 将整个 XML 文档加载到内存中,形成树形结构。
  2. 支持随机访问和修改节点。
  3. 适合处理小型 XML 文件。

读取 XML

cpp 复制代码
#include <QFile>
#include <QDomDocument>
#include <QDebug>

void readXmlWithDom() {
    QFile file("example.xml");
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open file!";
        return;
    }

    QDomDocument doc;
    if (!doc.setContent(&file)) {
        qDebug() << "Failed to parse XML!";
        file.close();
        return;
    }
    file.close();

    // 获取根节点
    QDomElement root = doc.documentElement();
    qDebug() << "Root tag:" << root.tagName();

    // 遍历子节点
    QDomNode node = root.firstChild();
    while (!node.isNull()) {
        if (node.isElement()) {
            QDomElement element = node.toElement();
            qDebug() << "Tag:" << element.tagName()
                     << "Text:" << element.text();
        }
        node = node.nextSibling();
    }
}

写入XML

cpp 复制代码
void writeXmlWithDom() {
    QDomDocument doc;
    
    // 添加XML声明
    QDomProcessingInstruction instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);
    
    // 创建根节点
    QDomElement root = doc.createElement("books");
    doc.appendChild(root);
    
    // 添加子节点
    QDomElement book1 = doc.createElement("book");
    book1.setAttribute("id", "1");
    
    QDomElement title1 = doc.createElement("title");
    title1.appendChild(doc.createTextNode("Qt Programming"));
    book1.appendChild(title1);
    
    root.appendChild(book1);
    
    // 保存到文件
    QFile file("output.xml");
    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream stream(&file);
        stream << doc.toString();
        file.close();
    }
}

2.2 SAX 方式(QXmlStreamReader/QXmlStreamWriter)

特点

  1. 流式解析,逐行读取 XML,不加载整个文档。
  2. 内存占用小,适合处理大型 XML 文件。
  3. 只支持顺序访问,不支持随机修改。

读取XML

cpp 复制代码
#include <QFile>
#include <QXmlStreamReader>
#include <QDebug>

void readXmlWithStream() {
    QFile file("example.xml");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Failed to open file!";
        return;
    }

    QXmlStreamReader xml(&file);
    while (!xml.atEnd() && !xml.hasError()) {
        QXmlStreamReader::TokenType token = xml.readNext();
        
        if (token == QXmlStreamReader::StartElement) {
            if (xml.name() == "book") {
                QString id = xml.attributes().value("id").toString();
                qDebug() << "Book ID:" << id;
            } else if (xml.name() == "title") {
                qDebug() << "Title:" << xml.readElementText();
            }
        }
    }

    if (xml.hasError()) {
        qDebug() << "XML error:" << xml.errorString();
    }
    file.close();
}

写入XML

cpp 复制代码
void writeXmlWithStream() {
    QFile file("output.xml");
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "Failed to open file!";
        return;
    }

    QXmlStreamWriter xml(&file);
    xml.setAutoFormatting(true);  // 自动格式化XML
    xml.writeStartDocument();
    
    xml.writeStartElement("books");
    
    xml.writeStartElement("book");
    xml.writeAttribute("id", "1");
    xml.writeTextElement("title", "Qt Programming");
    xml.writeEndElement();  // </book>
    
    xml.writeEndElement();  // </books>
    xml.writeEndDocument();
    
    file.close();
}

2.3 对比分析

场景 推荐类 优点
小型 XML 文件,需随机修改 QDomDocument 操作简单,支持 DOM 树遍历
大型 XML 文件,仅需读取 QXmlStreamReader 内存占用低,解析速度快
生成 XML 文件 QXmlStreamWriter 代码简洁,性能高
需要 XPath 查询 QXmlQuery 支持 XPath 表达式
Qt Quick 应用 XmlListModel 直接集成到 QML 中
  1. 命名空间处理:
    DOM 方式:使用QDomNode::namespaceURI()获取命名空间。
    流方式:使用QXmlStreamReader::namespaceUri()。
  2. 错误处理:
    DOM 方式:检查QDomDocument::setContent()的返回值。
    流方式:检查QXmlStreamReader::hasError()。
  3. 性能考虑:
    处理大型文件时,优先选择 SAX 方式,避免内存溢出。

3. 使用场景

在 Qt 应用开发中,XML 文件常用于存储配置信息、交换数据、定义界面结构等场景。Qt 提供了多种处理 XML 的类和工具,使 XML 文件成为应用程序与外部数据交互的重要载体。

3.1 存储配置信息

XML 文件可用于保存应用程序的配置参数,如窗口尺寸、用户偏好等。通过读取和写入 XML 配置文件,实现应用状态的持久化。

xml 复制代码
<!-- config.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <window>
        <width>800</width>
        <height>600</height>
        <maximized>true</maximized>
    </window>
    <appearance>
        <theme>dark</theme>
        <font>Roboto</font>
        <fontSize>12</fontSize>
    </appearance>
</config>
  • 读取文件:
cpp 复制代码
#include <QFile>
#include <QXmlStreamReader>

void loadConfig() {
    QFile file("config.xml");
    if (file.open(QIODevice::ReadOnly)) {
        QXmlStreamReader xml(&file);
        
        while (!xml.atEnd()) {
            if (xml.readNextStartElement()) {
                if (xml.name() == "window") {
                    // 读取窗口配置
                    xml.readNextStartElement(); // <width>
                    int width = xml.readElementText().toInt();
                    xml.readNextStartElement(); // <height>
                    int height = xml.readElementText().toInt();
                    // 设置窗口大小...
                } else if (xml.name() == "appearance") {
                    // 读取外观配置
                    // ...
                }
            }
        }
        
        file.close();
    }
}

3.2 数据交换与存储

XML 是一种通用的数据交换格式,可用于在 Qt 应用与其他系统(如 Web 服务、数据库)之间传输数据。

xml 复制代码
<!-- books.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id="1">
        <title>Qt编程实战</title>
        <author>John Doe</author>
        <price currency="CNY">89.00</price>
    </book>
    <book id="2">
        <title>C++ Primer</title>
        <author>Stanley Lippman</author>
        <price currency="USD">45.99</price>
    </book>
</books>

解析数据:

cpp 复制代码
#include <QFile>
#include <QXmlStreamReader>
#include <QDebug>

struct Book {
    int id;
    QString title;
    QString author;
    double price;
    QString currency;
};

QList<Book> parseBooks() {
    QList<Book> bookList;
    QFile file("books.xml");
    
    if (file.open(QIODevice::ReadOnly)) {
        QXmlStreamReader xml(&file);
        Book currentBook;
        
        while (!xml.atEnd()) {
            if (xml.readNextStartElement()) {
                if (xml.name() == "book") {
                    currentBook.id = xml.attributes().value("id").toInt();
                } else if (xml.name() == "title") {
                    currentBook.title = xml.readElementText();
                } else if (xml.name() == "author") {
                    currentBook.author = xml.readElementText();
                } else if (xml.name() == "price") {
                    currentBook.price = xml.readElementText().toDouble();
                    currentBook.currency = xml.attributes().value("currency").toString();
                }
            } else if (xml.tokenType() == QXmlStreamReader::EndElement && 
                       xml.name() == "book") {
                bookList.append(currentBook);
            }
        }
        
        file.close();
    }
    
    return bookList;
}

3.3 界面布局与资源定义

XML 可用于定义 Qt 应用的界面结构(如 Qt Designer 生成的.ui文件)或资源文件(如.qrc)。

UI文件片段:

xml 复制代码
<!-- mainwindow.ui (简化版) -->
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
    <class>MainWindow</class>
    <widget class="QMainWindow" name="MainWindow">
        <property name="geometry">
            <rect>
                <x>0</x>
                <y>0</y>
                <width>800</width>
                <height>600</height>
            </rect>
        </property>
        <widget class="QWidget" name="centralWidget">
            <layout class="QVBoxLayout" name="verticalLayout">
                <widget class="QLabel" name="label">
                    <property name="text">
                        <string>Hello Qt!</string>
                    </property>
                </widget>
                <widget class="QPushButton" name="pushButton">
                    <property name="text">
                        <string>Click Me</string>
                    </property>
                </widget>
            </layout>
        </widget>
    </widget>
</ui>

3.4 网络通信与 API 交互

Qt 应用可通过 XML 格式与 Web 服务通信(如 SOAP 协议),或解析远程 API 返回的 XML 数据。

cpp 复制代码
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QXmlStreamReader>

void fetchRemoteXml() {
    QNetworkAccessManager manager;
    QNetworkRequest request(QUrl("https://api.example.com/data.xml"));
    
    QNetworkReply *reply = manager.get(request);
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    
    if (reply->error() == QNetworkReply::NoError) {
        QXmlStreamReader xml(reply->readAll());
        // 解析XML数据...
    }
    
    reply->deleteLater();
}

3.5 插件与扩展系统

XML 可用于描述插件信息或应用扩展点,使应用支持动态加载插件。

xml 复制代码
<!-- plugin.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <id>com.example.texteditor</id>
    <name>Text Editor Plugin</name>
    <version>1.0.0</version>
    <author>Example Inc.</author>
    <class>TextEditorPlugin</class>
    <dependencies>
        <dependency>core</dependency>
    </dependencies>
</plugin>

3.6 国际化(i18n)与翻译文件

Qt 的翻译文件(.ts)基于 XML 格式,用于存储不同语言的翻译文本。

xml 复制代码
<!-- translations.ts -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
    <context>
        <name>MainWindow</name>
        <message>
            <source>File</source>
            <translation>文件</translation>
        </message>
        <message>
            <source>Edit</source>
            <translation>编辑</translation>
        </message>
    </context>
</TS>
相关推荐
xuyin12044 分钟前
SQLite基础及优化
数据库·sqlite
Faith_xzc31 分钟前
MySQL 迁移至 Doris 最佳实践方案
数据库·mysql·adb
ikun·33 分钟前
MySQL高可用
数据库·mysql
Bug退退退1231 小时前
分析 redis 的 exists 命令有一个参数和多个参数的区别
数据库·redis·缓存
老天文学家了1 小时前
蓝桥杯-不完整的算式
数据库·职场和发展·蓝桥杯
YUNYINGXIA1 小时前
PostgreSQL初体验
数据库·postgresql
舰长1151 小时前
ubuntu 安装 Redis新版Redis 7.x
数据库·redis·ubuntu
文牧之2 小时前
Oracle 数据库的默认隔离级别
运维·数据库·oracle
洁✘2 小时前
POSTGRESQL 初体验
数据库·postgresql
李昊翔的博客3 小时前
保证数据库 + redis在读写分离场景中事务的一致性
数据库·redis·oracle