QT 使用XML保存操作记录

文章目录

  • 1 实现程序保存操作记录的思路
  • 2 XML文档基本结构
  • 3 QDomDocument实现XML读写
    • 3.1 QDomDocument实现生成XML文件
    • 3.2 QDomDocument实现读取XML文件
  • 4 QXmlStreamWriter实现读写
    • 4.1 QXmlStreamWriter实现生成XML
    • 4.2 QXmlStreamWriter实现读取XML

1 实现程序保存操作记录的思路

思路来源: 由于在一些绘图工具中,有些将操作的历史记录,缓存的操作配置保存在了json文件,也有的保存到了xml文件中,如下图所示。经过个人的对比发现xml的文件结构简单、文件的可读性强,节点和内容项之间关系层次清晰,能够实现简单、快速、清晰的内容缓存,非常适合做复杂数据类型的操作记录、工程操作文件记录、配置文件工具。

  • json 示例(来自一个友商的算法标注工具)
{"version": "4.5.6","flags": {},"shapes": [{"description": null,"mask": null,"label": "7","points": [[574.5679012345677,630.8641975308642],[701.7283950617282,0.0],[822.7160493827159,193.82716049382702],[1091.8518518518517,169.1358024691358]],"group_id": null,"shape_type": "polygon","flags": {}},{"description": null,"mask": null,"label": "7","points": [[970.5472636815921,377.96019900497504],[763.2246176524784,204.6395798783858],[689.9502487562188,457.0646766169153],[689.9502487562188,639.1542288557212],[882.4875621890546,636.1691542288554],[1222.7860696517412,583.9303482587063]],"group_id": null,"shape_type": "polygon","flags": {}},{"description": null,"mask": null,"label": "7","points": [[536.8694885361556,394.21340388007053],[596.1287477954147,430.01587301587324]],"group_id": null,"shape_type": "circle","flags": {}}],"imagePath": "微信图片_20231027144505.png","imageData": null,"imageHeight": 1080,"imageWidth": 1920
}
  • xml示例 (qdraw)
    在这里插入图片描述
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE qdraw>
<canvas width="800" height="600"><polyline rotate="0" x="469.004" y="326.484" z="0" width="394" height="289"><point x="-88.0041" y="20.5161"/><point x="76.9959" y="144.516"/><point x="196.996" y="65.5161"/><point x="150.996" y="-144.484"/><point x="-24.0041" y="-59.4839"/><point x="-163.004" y="-63.4839"/><point x="-197.004" y="53.5161"/><point x="-116.004" y="56.5161"/><point x="-150.004" y="11.5161"/></polyline><polyline rotate="0" x="164.945" y="321.008" z="0" width="218" height="134"><point x="-71.9446" y="26.9924"/><point x="27.0554" y="66.9924"/><point x="109.055" y="8.99239"/><point x="-44.9446" y="-67.0076"/><point x="-108.945" y="17.9924"/><point x="-70.9446" y="25.9924"/></polyline><ellipse startAngle="40" spanAngle="400" rotate="0" x="155" y="125.5" z="0" width="174" height="125"/><roundrect rx="0.1" ry="0.333333" rotate="0" x="357.5" y="461" z="0" width="141" height="108"/><rect rotate="0" x="104" y="488.5" z="0" width="152" height="163"/>
</canvas>

2 XML文档基本结构

在这里插入图片描述

3 QDomDocument实现XML读写

原理说明: 和json文件处理发方式相同。根据节点、子节点、内容项的关系生成、加载XML文件的内容。
方案缺点: 生成的xml文档中的内容项的顺序是随机的,如下图所示。需要添加随机方法处理,参见文章Qt中使用QDomDocument生成XML文件元素属性随机乱序解决办法 、解决QDomDocument的setattribute乱序,这样能保证每行顺序都是一样的,但是也和自己生成顺序不同。该方法逐渐被淘汰,请参见下文,方法2QXmlStreamWriter实现。

<!-->自己期望的结果<!-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE algoConfig>
<baseConfig><algolist><algo algId="101001" algName="未戴安全帽" serverType="图片服务" depModel1="1030" depLable1="NO_HELMET" depModel2="" depLable2="" depModel3="" depLable3=""/><algo algId="101002" algName="未穿长袖" serverType="图片服务" depModel1="1030" depLable1="PERSON" depModel2="" depLable2="" depModel3="" depLable3=""/>
</algolist><modelMap><model modelName="1303" reName="2303"/></modelMap>
</baseConfig>
<!-->生成的结果<!-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE algoConfig>
<baseConfig><algolist><algo serverType="图片服务" algName="未戴安全帽" algId="101001"  depModel1="1030" depLable1="NO_HELMET" depModel2="" depLable2="" depModel3="" depLable3=""/><algo serverType="图片服务" algName="未穿长袖" algId="101002"   depModel1="1030" depLable1="PERSON" depModel2="" depLable2="" depModel3="" depLable3=""/>
</algolist><modelMap><model modelName="1303" reName="2303"/></modelMap>
</baseConfig>

3.1 QDomDocument实现生成XML文件

方法说明: 采用QDomDocument实现,方案传统优缺点。

#include <QDomDocument>
#include <QFile>
#include <QTextStream>// Method to generate XML file
void generateXMLFile() {QDomDocument document;// Making the root elementQDomElement root = document.createElement("baseConfig");// Making elements of algolistQDomElement algolist = document.createElement("algolist");QDomElement algo1 = document.createElement("algo");algo1.setAttribute("algId", "101001");algo1.setAttribute("algName", "未戴安全帽");algo1.setAttribute("serverType", "图片服务");algo1.setAttribute("depModel1", "1030");algo1.setAttribute("depLable1", "NO_HELMET");algolist.appendChild(algo1);QDomElement algo2 = document.createElement("algo");algo2.setAttribute("algId", "101002");algo2.setAttribute("algName", "未穿长袖");algo2.setAttribute("serverType", "图片服务");algo2.setAttribute("depModel1", "1030");algo2.setAttribute("depLable1", "PERSON");algolist.appendChild(algo2);root.appendChild(algolist);// Making elements of modelMapQDomElement modelMap = document.createElement("modelMap");QDomElement model = document.createElement("model");model.setAttribute("modelName", "1303");model.setAttribute("reName", "2303");modelMap.appendChild(model);root.appendChild(modelMap);document.appendChild(root);// Writing to a fileQFile file("Config.xml");if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) {qDebug() << "Failed to open file for writing.";return;} else {QTextStream stream(&file);stream << document.toString();file.close();qDebug() << "File written.";}
}

3.2 QDomDocument实现读取XML文件

#include <QDomDocument>
void loadXMLFile() {QDomDocument document;QFile file("Config.xml");if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {qDebug() << "Failed to open file for reading.";return;} else {if(!document.setContent(&file)) {qDebug() << "Failed to load document.";return;}file.close();}QDomElement root = document.firstChildElement();QDomNodeList algos = root.firstChildElement("algolist").elementsByTagName("algo");for(int i = 0; i < algos.count(); i++) {QDomNode algoNode = algos.at(i);if(algoNode.isElement()) {QDomElement algo = algoNode.toElement();qDebug() << "Algo ID: " << algo.attribute("algId");qDebug() << "Algo Name: " << algo.attribute("algName");}}QDomNodeList models = root.firstChildElement("modelMap").elementsByTagName("model");for(int i = 0; i < models.count(); i++) {QDomNode modelNode = models.at(i);if(modelNode.isElement()) {QDomElement model = modelNode.toElement();qDebug() << "Model Name: " << model.attribute("modelName");qDebug() << "Renamed as: " << model.attribute("reName");}}
}

4 QXmlStreamWriter实现读写

  • 使用QXmlStreamWriter方法,读写超级简单,实现容易快速。

4.1 QXmlStreamWriter实现生成XML

#include <QXmlStreamReader>
void genConfForm::genXmlFile()
{QFile file("conf.xml");if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {qDebug() << "Failed to open file for writing.";return;}QXmlStreamWriter xmlWriter(&file);xmlWriter.setAutoFormatting(true);xmlWriter.writeStartDocument();xmlWriter.writeDTD("<!DOCTYPE algoConfig>");xmlWriter.writeStartElement("baseConfig");xmlWriter.writeStartElement("algolist");int rows = ui->tableView_gc->model()->rowCount();for(int r = 0; r < rows; r++){/*|0算法ID|1算法名称|2服务类型|3依赖模型1|4依赖label1|5依赖模型2|6依赖label2|7依赖模型3|8依赖label3|*/QString algId = ui->tableView_gc->model()->index(r,0).data().toString();QString algName = ui->tableView_gc->model()->index(r,1).data().toString();QString serverType = ui->tableView_gc->model()->index(r,2).data().toString();QString depModel1 = ui->tableView_gc->model()->index(r,3).data().toString();QString depLabel1 = ui->tableView_gc->model()->index(r,4).data().toString();QString depModel2 = ui->tableView_gc->model()->index(r,5).data().toString();QString depLabel2 = ui->tableView_gc->model()->index(r,6).data().toString();QString depModel3 = ui->tableView_gc->model()->index(r,7).data().toString();QString depLabel3 = ui->tableView_gc->model()->index(r,8).data().toString();xmlWriter.writeEmptyElement("algo");xmlWriter.writeAttribute("algId", algId);xmlWriter.writeAttribute("algName", algName);xmlWriter.writeAttribute("serverType", serverType);xmlWriter.writeAttribute("depModel1", depModel1);xmlWriter.writeAttribute("depLable1", depLabel1);xmlWriter.writeAttribute("depModel2", depModel2);xmlWriter.writeAttribute("depLable2", depLabel2);xmlWriter.writeAttribute("depModel3", depModel3);xmlWriter.writeAttribute("depLable3", depLabel3);}xmlWriter.writeEndElement();//algolistxmlWriter.writeStartElement("modelMap");for(auto& model:m_modelRename){//第一次修改后的值,第二次修改前的值auto& modName = model.first;auto& reName = model.second;xmlWriter.writeEmptyElement("model");xmlWriter.writeAttribute("modelName", modName);xmlWriter.writeAttribute("reName", reName);}xmlWriter.writeEndElement();//modelMapxmlWriter.writeEndElement(); // baseConfigxmlWriter.writeEndDocument();file.close();qDebug() << "XML file generated successfully.";
}

4.2 QXmlStreamWriter实现读取XML

#include <QXmlStreamReader>
struct DepAllModelInfo{QString m_model1;QString m_label1;QString m_model2;QString m_label2;QString m_model3;QString m_label3;
};
using depModel = std::vector<DepModelInfo>;
struct algInfo{QString m_alg_name;QString m_server_type;DepAllModelInfo m_dep_model;
};
using algFullCapacity = std::map<QString,algInfo>;
/*以上是读取config.xml文件结构在程序中的数据结构*/
void genConfForm::loadXmlFile()
{algFullCapacity afc;QFile file("config.xml");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {qDebug() << "Failed to open file for reading.";return;}QXmlStreamReader xmlReader(&file);while (!xmlReader.atEnd() && !xmlReader.hasError()) {// Read next elementQXmlStreamReader::TokenType token = xmlReader.readNext();// If token is just StartDocument, we'll go to nextif (token == QXmlStreamReader::StartDocument) {continue;}// If token is StartElement - read itif (token == QXmlStreamReader::StartElement){if (xmlReader.name() == "algo"){DepAllModelInfo dam;QXmlStreamAttributes attributes = xmlReader.attributes();QString algId = attributes.value("algId").toString();QString algName = attributes.value("algName").toString();QString serverType = attributes.value("serverType").toString();dam.m_model1 = attributes.value("depModel1").toString();dam.m_label1 = attributes.value("depLable1").toString();dam.m_model2 = attributes.value("depModel2").toString();dam.m_label2 = attributes.value("depLable2").toString();dam.m_model3 = attributes.value("depModel3").toString();dam.m_label3 = attributes.value("depLable3").toString();if(!algId.isEmpty() && !algName.isEmpty()){afc.insert(std::pair<QString,algInfo>(algId, {algName,serverType,dam}));}}if (xmlReader.name() == "model"){QXmlStreamAttributes attributes = xmlReader.attributes();QString dbModelName = attributes.value("modelName").toString();QString modifyName = attributes.value("reName").toString();m_modelRename.insert(std::pair<QString,QString>(dbModelName,modifyName));}}}if(!afc.empty())slotAlgInfo(afc);if (xmlReader.hasError()) {qDebug() << "XML error: " << xmlReader.errorString();}file.close();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/247842.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大数据】Flink 架构(三):事件时间处理

《Flink 架构》系列&#xff08;已完结&#xff09;&#xff0c;共包含以下 6 篇文章&#xff1a; Flink 架构&#xff08;一&#xff09;&#xff1a;系统架构Flink 架构&#xff08;二&#xff09;&#xff1a;数据传输Flink 架构&#xff08;三&#xff09;&#xff1a;事件…

04.对象树

一、引入 1.QT实现输出"hello world" 使用QT编写"hello world"程序&#xff0c;有两种实现方式&#xff1a; &#xff08;1&#xff09;直接在生成的ui文件中&#xff0c;拖入一个label控件&#xff0c;双击控件编辑内容即可实现 &#xff08;2&#xff0…

【CSS】flex布局用法解析,快速上手flex布局,flex:1是什么意思?肯定看的懂好吧?

一、flex布局 flex 是 flexible box 的缩写&#xff0c;意为"弹性布局"&#xff0c;用来为盒状模型提供最大的灵活性。 任何一个容器都可以指定为 flex 布局。 采用 flex 布局的元素&#xff0c;称为 flex 容器&#xff08;flex container&#xff09;&#xff0c;…

计算机视觉:高级图像处理,满足您的所有需求。

一、说明 特征提取是机器学习管道中的关键步骤&#xff0c;可增强模型在不同数据集上的泛化和良好表现能力。特征提取方法的选择取决于数据的特征和机器学习任务的具体要求。本文揭示图像处理的数学原理&#xff0c;实现增强的计算机视觉 二、关于计算机视觉的普遍问题 在计算机…

CSS基础细节学习

目录 一.CSS--网页的美容师 二.语法规范及选择器的介绍 一.CSS--网页的美容师 CSS是层叠样式表( Cascading Style Sheets )的简称&#xff0c;有时我们也会称之为CSS样式表或级联样式表。 CSS是也是一种标记语言&#xff0c;CSS主要用于设置HTML页面中的文本内容(字体、大小…

Linux:共享内存VS消息队列VS信号量

文章目录 共享内存的通信速度消息队列msggetmsgsndmsgrcvmsgctl 信号量semgetsemctl 内核看待ipc资源单独设计的模块ipc资源的维护 本篇主要是基于共享内存&#xff0c;延伸出对于消息队列和信号量&#xff0c;再从内核的角度去看这三个模块实现进程间通信 共享内存的通信速度…

2024 新年HTML5+Canvas制作3D烟花特效(附源码)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

RK3568 Android 13 系统裁剪

android 13 系统裁剪是个大工程&#xff0c;裁剪也是需要大量的测试&#xff0c;才能保证系统的稳定性&#xff0c;以下是RK官方给出的裁剪方案&#xff0c;有兴趣的可以去看一下&#xff0c;对裁剪不是要求过高的可以根据官方的建议&#xff0c;对系统进行裁剪: Rockchip And…

专科拿到季军:微茫星火,奋起直追!

Datawhale干货 作者&#xff1a;“不啻微茫”团队&#xff0c;季军方案 前 言 大家好&#xff0c;我们是 飞桨星河社区 X 智海Mo平台 AI 大模型创意应用大赛 获奖团队——"不啻微茫"&#xff0c;很荣幸能有机会与大家分享这次比赛经验&#xff0c;我们从零开始的过程…

【CanvasKeyFrames - HTML5 Canvas 图片序列帧播放工具】

前言 一、CanvasKeyFrames 是什么&#xff1f; 用来做canvas动画的工具。 二、使用步骤 效果如图&#xff1a;上下波动的线条 1.引入库 代码如下&#xff08;示例&#xff09;&#xff1a; 在html中引入&#xff1a; <script src"canvas-keyframes.js"><…

【linux】运维-磁盘空间不足-用到的命令(简洁)

【linux】运维-磁盘空间不足-用到的命令 常用&#xff1a; 注&#xff1a;du -s 和 -d 不能同时都用, -s | -d n 注&#xff1a;df -H 和 -h 区别 -H 1K1000 -h 1K1024 #-T 显示文件系统类型 -h 高可读性显示 df -Th #-c显示总和 ;sort -r 倒序显示 ;2>/dev/nul…

LiveGBS流媒体平台GB/T28181常见问题-如何快速查看推流上来的摄像头并停止摄像头推流?

LiveGBS流媒体平台GB/T28181常见问题-如何快速查看推流上来的摄像头并停止摄像头推流&#xff1f; 1、负载信息2、负载信息说明3、会话列表查看3.1、会话列表 4、停止会话5、搭建GB28181视频直播平台 1、负载信息 实时展示直播、回放、播放、录像、H265、级联等使用数目 2、负…

蓝桥杯AT24C02问题记录

问题1&#xff1a;从这个图片上可以看出这两个在IIC的.c文件里延时时间不一样&#xff0c;第一张图使用了15个_nop_(); 12M晶振机器周期是 1/12M*121uS&#xff1b;nop()要延时1个指令周期。延时时间不对会对时序产生影响&#xff0c;时序不对&#xff0c;则AT24C02有没被使用…

时序分解 | MATLAB实现CEEMDAN+SE自适应经验模态分解+样本熵计算

时序分解 | MATLAB实现CEEMDANSE自适应经验模态分解样本熵计算 目录 时序分解 | MATLAB实现CEEMDANSE自适应经验模态分解样本熵计算效果一览基本介绍程序设计参考资料 效果一览 基本介绍 MATLAB实现CEEMDANSE自适应经验模态分解样本熵计算 包括频谱图 附赠案例数据 可直接运行 …

秋招面试—浏览器原理篇

浏览器原理篇 1.什么是XSS、CSRF,怎么预防&#xff1f; &#xff08;1&#xff09;XSS(跨站脚本攻击)&#xff1a;攻击者将恶意代码植入到浏览器页面中&#xff0c;盗取存储在客户端的Cookie&#xff1b; ​ XSS分为&#xff1a;①存储型&#xff1a;论坛发帖、商品评论、用户…

cartographer离线建图报错:data_.trajectory_nodes.SizeOfTrajectoryOrZero

cartographer离线建图报错: data_.trajectory_nodes.SizeOfTrajectoryOrZero [FATAL] [1706177325.876019302, 1706015603.398505596]: F0125 18:08:45.000000 17607 pose_graph_2d.cc:1314] Check failed: data_.trajectory_nodes.SizeOfTrajectoryOrZero(trajectory_id) &…

C++类和对象(中)

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

【BUG】联想Y7000电池电量为0且无法充电解决方案汇总

因为最近火灾很多&#xff0c;所以昨天夜晚睡觉的时候把插线板电源关掉了&#xff0c;电脑也关机了。 各位一定要注意用电安全&#xff0c;网上的那些事情看着真的很难受qvq。 第二天早上起床的时候一看发现电脑直接没电了&#xff0c;插上电源后也是显示 你一定要冲进去啊(ू˃…

Android HIDL概述与绑定模式的实现

一、前言 Android O(8.0) 版本之后&#xff0c;底层实现有了比较大的变化&#xff0c;最显著的一个方面就是 HIDL 机制的全面实施。本文对于理解系统源码中 Gnss、Usb、Camera 等模块的工作原理有极大帮助。 二、HIDL 设计目的 在 Android O(8.0) 之前系统的升级牵扯多方协作…

c语言实战之贪吃蛇

文章目录 前言效果展示游戏用到的图片游戏思路一览游戏前准备一、贪吃蛇、食物、障碍物节点坐标的结构体二、枚举游戏状态、和贪吃蛇的方向三、维护运行的结构体 游戏开始前的初始化一、学习图形库相关知识二、设置背景三、欢迎界面四、初始化贪吃蛇五、生成障碍物六、生成食物…