Qt 提供了强大且易用的 XML 和 JSON 数据处理模块,使开发者能够轻松解析、生成和操作结构化数据。本文将从基础到高级全面解析 Qt 中处理 XML 和 JSON 的方法,包括核心类、使用示例和最佳实践。
一、XML 数据处理
1. Qt XML 模块核心类
类名 | 作用 |
---|---|
QXmlStreamReader | 基于流的 XML 读取器,逐行解析 XML,适合处理大型文件(内存效率高) |
QXmlStreamWriter | 基于流的 XML 写入器,用于生成 XML 文档 |
QDomDocument | 基于 DOM(文档对象模型)的 XML 解析器,将整个文档加载到内存中,支持随机访问和修改 |
QDomElement | 表示 XML 文档中的元素节点 |
QDomNode | 表示 XML 文档中的通用节点(可表示元素、文本、注释等) |
2. XML 解析示例:QXmlStreamReader
cpp
#include <QCoreApplication>
#include <QFile>
#include <QXmlStreamReader>
#include <QDebug>
void parseXML(const QString &fileName) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "无法打开文件:" << fileName;
return;
}
QXmlStreamReader xml(&file);
// 遍历 XML 文档
while (!xml.atEnd() && !xml.hasError()) {
QXmlStreamReader::TokenType token = xml.readNext();
// 处理开始元素
if (token == QXmlStreamReader::StartElement) {
if (xml.name() == "book") {
// 获取元素属性
QXmlStreamAttributes attributes = xml.attributes();
if (attributes.hasAttribute("id")) {
QString id = attributes.value("id").toString();
qDebug() << "Book ID:" << id;
}
} else if (xml.name() == "title") {
// 获取元素文本
QString title = xml.readElementText();
qDebug() << "Title:" << title;
} else if (xml.name() == "author") {
QString author = xml.readElementText();
qDebug() << "Author:" << author;
}
}
}
if (xml.hasError()) {
qDebug() << "XML 解析错误:" << xml.errorString();
}
file.close();
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
parseXML("books.xml");
return a.exec();
}
3. XML 生成示例:QXmlStreamWriter
cpp
#include <QCoreApplication>
#include <QFile>
#include <QXmlStreamWriter>
void createXML(const QString &fileName) {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
QXmlStreamWriter xml(&file);
xml.setAutoFormatting(true); // 自动格式化(缩进)
// 写入 XML 声明
xml.writeStartDocument();
// 写入根元素
xml.writeStartElement("library");
// 写入第一个书籍元素
xml.writeStartElement("book");
xml.writeAttribute("id", "1");
xml.writeTextElement("title", "C++ Primer");
xml.writeTextElement("author", "Stanley Lippman");
xml.writeEndElement(); // 结束 book 元素
// 写入第二个书籍元素
xml.writeStartElement("book");
xml.writeAttribute("id", "2");
xml.writeTextElement("title", "Qt 5 C++ GUI Programming Cookbook");
xml.writeTextElement("author", "Mark Summerfield");
xml.writeEndElement(); // 结束 book 元素
// 结束根元素
xml.writeEndElement(); // 结束 library 元素
// 写入 XML 文档结束
xml.writeEndDocument();
file.close();
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
createXML("library.xml");
return a.exec();
}
4. DOM 方式处理 XML(QDomDocument)
cpp
#include <QCoreApplication>
#include <QFile>
#include <QDomDocument>
#include <QDomElement>
#include <QDebug>
void modifyXML(const QString &fileName) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return;
}
QDomDocument doc;
QString errorMsg;
int errorLine, errorColumn;
// 加载 XML 文档
if (!doc.setContent(&file, &errorMsg, &errorLine, &errorColumn)) {
qDebug() << "XML 加载错误:" << errorMsg << "Line:" << errorLine << "Column:" << errorColumn;
file.close();
return;
}
file.close();
// 获取根元素
QDomElement root = doc.documentElement();
// 遍历所有书籍元素
QDomNodeList bookList = root.elementsByTagName("book");
for (int i = 0; i < bookList.size(); ++i) {
QDomElement book = bookList.at(i).toElement();
if (!book.isNull()) {
// 修改书籍元素的属性
if (book.attribute("id") == "1") {
book.setAttribute("category", "Programming");
}
// 添加新元素
QDomElement publisher = doc.createElement("publisher");
QDomText publisherText = doc.createTextNode("Addison-Wesley");
publisher.appendChild(publisherText);
book.appendChild(publisher);
}
}
// 保存修改后的 XML
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
doc.save(stream, 4); // 缩进为4个空格
file.close();
}
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
modifyXML("library.xml");
return a.exec();
}
二、JSON 数据处理
1. Qt JSON 模块核心类
类名 | 作用 |
---|---|
QJsonDocument | 表示完整的 JSON 文档,可从 JSON 文本解析或生成 JSON 文本 |
QJsonObject | 表示 JSON 对象(键值对集合),类似 std::map<QString, QJsonValue> |
QJsonArray | 表示 JSON 数组(值的有序列表) |
QJsonValue | 表示 JSON 值(可以是 null、bool、number、string、object 或 array) |
QJsonParseError | 用于存储 JSON 解析过程中的错误信息 |
2. JSON 解析示例
cpp
#include <QCoreApplication>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
void parseJSON(const QString &fileName) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "无法打开文件:" << fileName;
return;
}
// 读取 JSON 数据
QByteArray jsonData = file.readAll();
file.close();
// 解析 JSON
QJsonParseError parseError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "JSON 解析错误:" << parseError.errorString();
return;
}
// 检查是否为 JSON 对象
if (jsonDoc.isObject()) {
QJsonObject jsonObj = jsonDoc.object();
// 获取基本类型值
if (jsonObj.contains("name") && jsonObj["name"].isString()) {
QString name = jsonObj["name"].toString();
qDebug() << "Name:" << name;
}
// 获取数组
if (jsonObj.contains("books") && jsonObj["books"].isArray()) {
QJsonArray booksArray = jsonObj["books"].toArray();
qDebug() << "Books:";
for (int i = 0; i < booksArray.size(); ++i) {
if (booksArray[i].isObject()) {
QJsonObject bookObj = booksArray[i].toObject();
QString title = bookObj["title"].toString();
QString author = bookObj["author"].toString();
qDebug() << " Title:" << title;
qDebug() << " Author:" << author;
}
}
}
}
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
parseJSON("data.json");
return a.exec();
}
3. JSON 生成示例
cpp
#include <QCoreApplication>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
void createJSON(const QString &fileName) {
// 创建 JSON 对象
QJsonObject rootObj;
rootObj["name"] = "My Library";
rootObj["location"] = "Beijing";
rootObj["established"] = 2020;
// 创建书籍数组
QJsonArray booksArray;
// 添加第一本书
QJsonObject book1;
book1["title"] = "C++ Primer";
book1["author"] = "Stanley Lippman";
book1["year"] = 2012;
book1["available"] = true;
booksArray.append(book1);
// 添加第二本书
QJsonObject book2;
book2["title"] = "Qt 5 C++ GUI Programming Cookbook";
book2["author"] = "Mark Summerfield";
book2["year"] = 2018;
book2["available"] = false;
booksArray.append(book2);
// 将书籍数组添加到根对象
rootObj["books"] = booksArray;
// 创建 JSON 文档
QJsonDocument jsonDoc(rootObj);
// 写入文件
QFile file(fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
file.write(jsonDoc.toJson(QJsonDocument::Indented));
file.close();
}
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
createJSON("library.json");
return a.exec();
}
三、XML 与 JSON 的对比与选择
1. 适用场景
特性 | XML | JSON |
---|---|---|
数据结构 | 层次结构(元素嵌套) | 键值对和数组 |
语法复杂度 | 较高(需要标签闭合、命名空间等) | 较低(简洁的键值对语法) |
可读性 | 较好(标签提供明确语义) | 好(简洁直观) |
解析性能 | 较低(DOM 方式需加载整个文档) | 较高(轻量级,解析速度快) |
数据大小 | 较大(标签增加冗余) | 较小(紧凑格式) |
适用场景 | 配置文件、文档交换(如 RSS、SOAP) | 网络 API(如 RESTful)、配置文件 |
2. 转换工具
- XML → JSON:可通过解析 XML 并手动构建 JSON 对象实现转换。
- JSON → XML:需创建 XML 结构,将 JSON 键值对映射为 XML 元素或属性。
以下是一个简单的 XML 到 JSON 转换示例:
cpp
QJsonValue xmlToJson(const QDomNode &node) {
if (node.isElement()) {
QDomElement element = node.toElement();
QJsonObject obj;
// 添加元素属性
QDomNamedNodeMap attributes = element.attributes();
for (int i = 0; i < attributes.size(); ++i) {
QDomNode attribute = attributes.item(i);
obj["@" + attribute.nodeName()] = attribute.nodeValue();
}
// 处理子节点
QDomNodeList children = element.childNodes();
if (children.size() == 1 && children.at(0).isText()) {
// 如果只有文本内容,直接返回文本
return QJsonValue(children.at(0).toText().data());
} else {
// 处理子元素
QHash<QString, QJsonArray> childArrays;
for (int i = 0; i < children.size(); ++i) {
QDomNode child = children.at(i);
if (child.isElement()) {
QString name = child.nodeName();
QJsonValue value = xmlToJson(child);
if (childArrays.contains(name)) {
childArrays[name].append(value);
} else {
QJsonArray array;
array.append(value);
childArrays[name] = array;
}
}
}
// 将子元素添加到对象
QHashIterator<QString, QJsonArray> it(childArrays);
while (it.hasNext()) {
it.next();
if (it.value().size() == 1) {
obj[it.key()] = it.value().at(0);
} else {
obj[it.key()] = it.value();
}
}
}
return QJsonValue(obj);
}
return QJsonValue();
}
四、最佳实践与注意事项
1. XML 处理建议
- 大型文件 :使用
QXmlStreamReader
逐行解析,避免内存溢出。 - 复杂操作 :若需频繁修改或随机访问,使用
QDomDocument
。 - 命名空间 :处理含命名空间的 XML 时,使用
QXmlStreamReader::namespaceUri()
。 - 错误处理 :始终检查解析错误(如
QXmlStreamReader::hasError()
)。
2. JSON 处理建议
- 网络数据:优先使用 JSON,因其轻量且易于解析。
- 严格格式:JSON 格式严格(如键需用双引号),解析前需验证。
- 空值处理 :使用
QJsonValue::isNull()
和QJsonValue::isUndefined()
区分空值和未定义值。 - 嵌套结构:处理深层嵌套的 JSON 时,建议先定义数据模型类进行映射。
3. 性能考虑
- XML:DOM 方式加载整个文档到内存,适合小型文件;流解析适合大型文件。
- JSON:解析速度通常快于 XML,尤其适合移动端和网络传输。
五、总结
Qt 提供了全面的 XML 和 JSON 处理工具,开发者可根据需求选择合适的方式:
- XML:适合需要严格结构、丰富元数据和文档交换的场景,提供 DOM 和流两种处理方式。
- JSON:适合轻量级数据交换、网络 API 和配置文件,语法简洁且解析高效。
掌握这些技术后,可轻松实现数据的存储、传输和交换,为应用开发提供强大的数据处理能力。