Qt读xml文件
QXmlStreamReader
QXmlStreamReader类通过简单的流式API为我们提供了一种快速的读取xml文件的方式。他比Qt自己使用的SAX解析方式还要快。
所谓的流式读取即将一个xml文档读取成一系列标记的流,类似于SAX。而QXmlStreamReader类和SAX的主要区别就是解析这些标记的方式。使用SAX解析时,应用程序必须提供一些处理器(回调函数)来处理来自解析器的一系列的所谓的xml事件,不同的xml标记会触发不同的事件,从而进行相应的处理。而使用QXmlStreamReader,应用程序自己可以驱动整个循环,从解析器中一个接一个的拉取出xml标记。这个动作可以通过readNext()来完成,该函数会读取出下一个完整的标记,然后其tokenType()。然后,我们就可以使用一系列方便的函数,如isStartElement(),text()等来确定或得到具体所读取的内容。这种拉模式(pull)的解析方法的好处就在于,我们可以将对一个xml文档的解析分开到多个函数中来完成,对不同的标记使用一个单独的函数来处理。
QXmlStreamReader类的典型使用方法如下:
QXmlStreamReader xml;...while (!xml.atEnd()) {xml.readNext();... // do processing}if (xml.hasError()) {... // do error handling}如果在解析的过程中出现了错误,atEnd()和hasError()会返回true,error()会返回所出现的具体错误类型。errorString(),lineNumber(),columnNumber()和characterOffset()函数可以用来得到错误的具体信息,一般我们使用这几个函数来构建一个错误字符串来提示用户具体的错误信息。同时,为了简化应用程序代码,QXmlStreamReader还提供了一个raiseError()的机制,可以让我们在必要时触发一个自定义的错误信息。
QXmlStreamReader是一个增量式的解析器。它可以处理文档不能被一下处理完的情况,比如该xml文件来自于多个文件或来自于网络。当QXmlStreamReader解析完所有的数据但该xml文档是不完整的,这时它会返回一个PrematureEndOfDocumentError类型的错误。然后,当有更多的数据到来时,它会从这个错误中恢复,然后继续调用readNext()来解析新的数据。
QXmlStreamReader是不太消耗内存的,因为它不会在内存中存储整个xml文档树,仅仅存储当前它所解析的标记。此外,QXmlStreamReader使用QStringRef来解析所有的字符串数据而不是真实的QString对象,这可以避免不必要的小字符串内存分配代价。QStringRef是对QString或其子串的一个简单包装,并提供了一些类似于QString类的API,但它不会进行内存的分配,并在底层使用了引用计数来共享数据。我们可以在需要时,调用QStringRef的toString()来得到一个真实的QString对象。
读xml文件
example.xml
<?xml version="1.0" encoding="UTF-8"?>
<labels map="demo1" ver="1.0"> <label id="1802232"> <x>1568</x> <y>666</y> </label> <label id="1802230"> <x>1111</x> <y>622</y> </label>
</labels>#ifndef XMLREAGER_H
#define XMLREAGER_H
#include <QXmlStreamReader>class xmlreader
{
public:xmlreader();bool readFile(const QString &fileName);private:void readlabelsElement(); //读取label标签void readlabelElement(); //读取label标签void readxElement(); //读取x标签void readyElement(); //读取y标签void skipUnknownElement(); //跳过未知标签QXmlStreamReader reader;
};#endif // XMLREAGER_H#include "xmlreader.h"
#include <iostream>
#include <QDebug>
#include <QFile>xmlreader::xmlreader()
{}bool xmlreader::readFile(const QString &fileName)
{//以只读和文本方式打开文件,如果打开失败输出错误日志,并且返回false QFile file(fileName);if (!file.open(QFile::ReadOnly | QFile::Text)) {std::cerr << "Error: Cannot read file " << qPrintable(fileName)<< ": " << qPrintable(file.errorString())<< std::endl;return false;}//将文件设置成xml阅读器的输入设备reader.setDevice(&file);reader.readNext(); //直接读取下一个节点,因为首先读到的标签是XML文件的头部(第一行)while (!reader.atEnd()) //外部循环,未到文件结尾就一直循环读取{if (reader.isStartElement()) //外部分支,如果不是起始标签,则直接读取下一个节点{if (reader.name() == "labels") //内部分支,如果根节点不是 == labels,//说明读取的文件是错误的{qDebug() << reader.name();//通过qDebug()输出当前节点的名字,这里输出labelsreadlabelsElement(); //读取labels节点的内容} else { //raiseError()函数用来自定义输出错误日志的内容,这里输出Not a labels filereader.raiseError(QObject::tr("Not a labels file"));}} else {reader.readNext();}}//关闭文件,如果读取发生错误(hasError())或者文件有错误,输出错误信息,返回false,file.close();if (reader.hasError()) {std::cerr << "Error: Failed to parse file "<< qPrintable(fileName) << ": "<< qPrintable(reader.errorString()) << std::endl;return false;} else if (file.error() != QFile::NoError) {std::cerr << "Error: Cannot read file " << qPrintable(fileName)<< ": " << qPrintable(file.errorString())<< std::endl;return false;}return true;
}void xmlreader::readlabelsElement()
{reader.readNext();//读取了根节点labels后,继续读取下一个节点while (!reader.atEnd()) {if (reader.isEndElement()){reader.readNext();break; //如果是结束节点,则结束循环//循环执行下去,读到的第一个结束节点是</labels>,而不是</label>;//这是执行readlabelElement()函数中得到的结果,当读到</label>时,//该函数跳出循环并读取下一个节点,而下一个节点是<label>或者</labels>}if (reader.isStartElement()) {if (reader.name() == "label") { //获得label的attributes()值,也就是id,转换成字符串输出qDebug() << reader.attributes().value("id").toString();qDebug() << reader.name();readlabelElement();} else {skipUnknownElement();//未知节点直接跳过}}else{reader.readNext();}}
}void xmlreader::readlabelElement()
{reader.readNext();while (!reader.atEnd()) {if (reader.isEndElement()) {reader.readNext();break;}if (reader.isStartElement()) {if (reader.name() == "x") {readxElement();} else if (reader.name() == "y") {readyElement();} else {skipUnknownElement();}} else {reader.readNext();}}
}void xmlreader::readxElement()
{QString x = reader.readElementText();qDebug() <<"x:" << x;if (reader.isEndElement())reader.readNext();}
void xmlreager::readyElement()
{QString y = reader.readElementText();//执行这个函数以后,y获得了坐标值,并且当前节点//自动变成结束节点</y>qDebug() << "y:" << y;if (reader.isEndElement())reader.readNext(); //在这里,读取下一个节点,就是</label>}
//是一个递归函数
void xmlreader::skipUnknownElement()
{reader.readNext();while (!reader.atEnd()) {if (reader.isEndElement()) {reader.readNext();break;}if (reader.isStartElement()) {skipUnknownElement();//函数的递归调用} else {reader.readNext();}}
}#include <QtCore/QCoreApplication>
#include "xmlreader.h"
#include <iostream>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);xmlreader reader;reader.readFile("labels.xml");return a.exec();
}读取结果如下图所示:

teachers.xml:
其中,学校(school)三楼(floor3)的老师信息,还有一个学生的信息。
6个老师,1个学生
<?xml version="1.0" ?>
<school><floor3 id="3" time="2019/10/11"><teacher><entry name="Job"><age>30</age><sport>soccer</sport></entry><entry name="Tom"><age>32</age><sport>swimming</sport></entry></teacher><teacher><entry name="Job2"><age>30</age><sport>soccer</sport></entry><entry name="Tom"><age>32</age><sport>swimming</sport></entry></teacher><teacher><entry name="Job3"><age>30</age><sport>soccer</sport></entry><entry name="Tom"><age>32</age><sport>swimming</sport></entry></teacher><teacher><entry name="Job4"><age>30</age><sport>soccer</sport></entry><entry name="Tom"><age>32</age><sport>swimming</sport></entry></teacher><teacher><entry name="Job5"><age>30</age><sport>soccer</sport></entry><entry name="Tom"><age>32</age><sport>swimming</sport></entry></teacher><student><entry name="Lily"><age>20</age><sport>dancing</sport></entry><entry name="Keith"><age>21</age><sport>running</sport></entry></student><teacher><entry name="Job6"><age>30</age><sport>soccer</sport></entry><entry name="Tom"><age>32</age><sport>swimming</sport></entry></teacher></floor3>
</school>注意:
重点在函数中的代码,移植出来可以使用。
记得将“用来计数”的变量,进行整理。
还有文件所在地址,也要更换。
将XML的文件内容,首先读取到一个变量中,再分析这个变量的内容。
受XML文件的编码格式影响很大,如果有中文乱码的现象出现,要慎重使用这种方法,可能无法读取。
#include <QtCore/QCoreApplication>
#include <QXmlStreamReader>
#include <QFile>
#include <iostream>void ReadXml()
{//用来计数int teacherCount = 0;int ageCount = 0;int sanlouCount = 0;int schoolCount = 0;//读取文件QString fileName = "D:/JBXML/teachers.xml";QFile file(fileName);if (!file.open(QFile::ReadOnly | QFile::Text)){return ;}//QXmlStreamReader操作任何QIODevice.QXmlStreamReader xml(&file);//解析XML,直到结束while (!xml.atEnd() && !xml.hasError()){//读取下一个element.QXmlStreamReader::TokenType token = xml.readNext();/*以下内容用于分析读取的内容,可以将每一个读取到的标签名字打印出来*//*if (token == QXmlStreamReader::Invalid){//如果有读取错误,将被打印出来std::cout << xml.errorString().toStdString();}std::cout << xml.tokenString().toStdString() << "\t";std::cout << xml.name().toString().toStdString() << std::endl;*//*显示这个分析过程,你会看到很清晰的读取过程*///如果获取的仅为StartDocument,则进行下一个if (token == QXmlStreamReader::StartDocument){continue;}//如果获取了StartElement,则尝试读取if (token == QXmlStreamReader::StartElement){//如果为person,则对其进行解析if (xml.name() == "teacher"){teacherCount++;}if (xml.name() == "age"){ageCount++;}if (xml.name() == "floor3"){sanlouCount++;}if (xml.name() == "school"){schoolCount++;}}}if (xml.hasError()){//QMessageBox::information(NULL, QString("parseXML"), xml.errorString());}file.close();std::cout << teacherCount << " teacher" << std::endl;std::cout << ageCount << " ages" << std::endl;std::cout << sanlouCount << " 3rdFloors" << std::endl;std::cout << schoolCount << " schools" << std::endl;
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);ReadXml();return a.exec();
}可以得到XML文件中,各个标签tag, 即尖括号内的信息,然后进行判断。
如果是“teacher”,会计数,然后可以看到,总共有6个老师。
运行结果如下图所示:

如果把中间注释的代码打开,可以看到每一个读取到的标签,并将读取过程打印出来。运行结果如下图所示:

相关文章:
Qt读xml文件
QXmlStreamReaderQXmlStreamReader类通过简单的流式API为我们提供了一种快速的读取xml文件的方式。他比Qt自己使用的SAX解析方式还要快。所谓的流式读取即将一个xml文档读取成一系列标记的流,类似于SAX。而QXmlStreamReader类和SAX的主要区别就是解析这些标记的方式…...
Qt样式表
1>样式表介绍 样式表可通过 QApplication::setStyleSheet()函数将其设置到整个应用程序上,也可以使用 QWidget::setStyleSheet()将其设置到指定的部件或子部件上,不同级别均可设置样式表,称为样式表的层叠。样式表也可通过设计模式编辑样…...
Docker与微服务实战2022
基础篇(零基小白)1.Docker简介1.1 是什么问题:为什么会有docker出现?您要如何确保应用能够在这些环境中运行和通过质量检测?并且在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复? 答案就…...
Linux(传输层二)
文章目录0. 前言1. TCP协议1-1 TCP协议段格式1. TCP如何解包?2. TCP协议如何交付(应用层- - 客户)?3. 如何理解报文本身?4. 如何理解报文字段?1-2 确认应答(ACK)机制1-3 超时重传机制1-4 连接管理机制1. TC…...
4.Spring Cloud (Hoxton.SR8) 学习笔记—Nacos微服务治理、Nacos配置管理
本文目录如下:一、Nacos微服务治理Nacos 下载 与 启动Spring Cloud 集成 NacosIDEA 同一个 Application 启动多次Nacos - 配置集群Nacos - 设置负载均衡Nacos - 设置服务实例的权重二、Nacos 配置管理Nacos - 合理的把配置信息迁移到 Nacos 中Nacos - 配置命名规范N…...
卷王都在偷偷准备金三银四了...
年终奖没发; 简历石沉大海; 发消息只读不回 打开某招聘,看了看岗位,这个厂还不错,可是要求好高,我啥都不会。 “哎,算了,我简历还没更新呢,我躺到6月份拿到年终奖再跑…...
【C++的OpenCV】第十二课-OpenCV图像常用操作(九):找到图像的边界(轮廓)findContours()和drawContours()
🎉🎉🎉欢迎各位来到小白piao的学习空间!\color{red}{欢迎各位来到小白piao的学习空间!}欢迎各位来到小白piao的学习空间!🎉🎉🎉 💖💖💖…...
传奇开服流程—传奇单机架设教程
现在传奇私服还是那么的火爆,上次有报道发布站一年盈利几个亿,还是有很大的机会,很多玩家因为GM开服关服给折腾,刚充的钱服务器就关了,很是恼火,于是都想自己整个服开开,但又不知道从何下手&…...
【GoF 23】篇3:抽象工厂
1. 什么是抽象工厂? 提供一个创建一系列相关或互相依赖的对象接口,而无需指定它们的具体类。 抽象工厂是一个超级工厂,是其他工厂的工厂,或将简单工厂进一步抽象。 这样来理解: 我们将科技公司可以做的事情简要枚举…...
软考高级信息系统项目管理师系列之三十七:流程管理
软考高级信息系统项目管理师系列之三十七:流程管理 一、流程管理内容二、流程管理基础概念知识1.企业业务流程的整体目标2.业务流程的核心3.流程六要素4.良好的业务流程管理步骤5.企业流程管理的层次三、流程管理过程1.业务流程分析2.业务流程分析的主要方法3.业务流程分析工具…...
【WPS文字-Word】WPS文字设置段落居中对齐后公式左边右边的文字仍然无法跟公式对齐,公式和文字对不齐
一、问题背景 原来的公式左边文字是底端,右边文字是居中,我想着让左右文字全跟公式居中对齐,就全部设置了段落居中对齐。 结果发现,公式左右边的文字依然无法居中对齐。左边的文字是居中,但是右边的文字变成了顶端对…...
英文术语对照
underlying asset 标的资产 leverage 杠杆 forward 远期 futures 期货 options 期权 delivery 交割 broker 证券机构/经理人 CBOT 芝加哥交易所 long futures position 多头 short futures position 空头 spot price 现货价格 future price 期货价格 over-the-coun…...
CSS 扫盲
✏️作者:银河罐头 📋系列专栏:JavaEE 🌲“种一棵树最好的时间是十年前,其次是现在” 目录引入方式内部样式内联样式外部样式CSS 选择器CSS 常用属性值字体属性设置字体大小粗细文字样式文本属性文本颜色文本对齐文本装…...
【Redis黑马点评】基于session实现登录【短信验证码登录、登录验证功能、拦截器】过程详解
文章目录一. 黑马点评Redis项目实践1.1开发环境搭建1.1.1 数据库1.1.2 Springboot项目1.1.3 前端配置1.2 基于session实现登录1.2.1 发送短信验证码1.2.2 短信验证码登录1.2.3 登录验证功能1.2.3.1 编写拦截器一. 黑马点评Redis项目实践 1.1开发环境搭建 1.课程介绍ÿ…...
【C++】通过priority_queue、reverse_iterator加深对于适配器和仿函数的理解
苦尽甘来 文章目录一、仿函数(仿函数就是一个封装()运算符重载的类)1.C语言的函数指针2.C的仿函数对象二、priority_queue中的仿函数1.模拟实现优先级队列1.1 优先级队列的本质(底层容器为vector的适配器)1.2 向下调整算法建堆1.3…...
网络安全 -- 常见的攻击方式和防守
网络安全 – 常见的攻击方式和防守 一 . 网页中出现黑链 特点: 隐藏,不易发现,字体大小是0,表面上看不出来,代码层面可以查出来,也可能极限偏移,颜色一致 表现: 多表现为非法植入链接,一般点击会跳转至其他网页 例如: 1.澳门新葡京等赌博网站,获取流量,有人甚至会充钱参与赌…...
Android中实现滑动的7种方法
Android中实现滑动的7种方法前置知识Android坐标系视图坐标系触控事件---MotionEvent获取坐标的方法实现滑动的7种方法layout方法offsetLeftAndRight()和offsetTopAndBottom()LayoutParamsscrollTo和scrollByScroller属性动画ViewDragHelper参考前置知识 Android坐标系 Andro…...
【hadoop】介绍
目录 介绍 版本 优势 大数据技术生态体系 介绍 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 解决 存储和分析计算Google在大数据方面的三篇论文GFS --->HDFS Map-Reduce --->MR BigTable --->HBaseHadoop创始人Doug Cutting版本 Hadoop 三大发行版本&a…...
【C语言】有关的经典题型内含数组及递归函数题型讲解(入门适用)
C语音经典题型1. 在屏幕上输出9*9乘法口诀表2. 求10 个整数中最大值3. 计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值,打印出结果4. 编写程序数一下 1到 100 的所有整数中出现多少个数字95. 能把函数处理结果的二个数据返回给主调函数6. 实现一个函数,…...
MyBatis操作数据库
目录 MyBatis 功能架构 学习MyBatis 第一个MyBatis查询 1、创建数据库和表 2、搭建MyBatis开发环境 2.1、在项目中添加MyBatis框架 2.2、配置数据库连接信息 2.3、配置MyBatis中xml的保存路径(规则) 3、添加业务代码 3.1、创建实体类 3.2、构…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...
