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 element
    QDomElement root = document.createElement("baseConfig");

    // Making elements of algolist
    QDomElement 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 modelMap
    QDomElement 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 file
    QFile 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();//algolist

    xmlWriter.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();//modelMap

    xmlWriter.writeEndElement(); // baseConfig
    xmlWriter.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 element
        QXmlStreamReader::TokenType token = xmlReader.readNext();
        // If token is just StartDocument, we'll go to next
        if (token == QXmlStreamReader::StartDocument) {
            continue;
        }
        // If token is StartElement - read it
        if (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();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker镜像详解

文章目录 一、什么是docker镜像 二、为什么需要镜像 三、镜像相关命令详解 3、1 命令清单 3、2 命令详解 四、镜像实战 4、1 镜像操作案例 4、2 离线迁移镜像 4、3 镜像存储的压缩与共享 &#x1f64b;‍♂️ 作者&#xff1a;Ggggggtm &#x1f64b;‍♂️ &#x1f440; 专栏…

西瓜书学习笔记——密度聚类(公式推导+举例应用)

文章目录 算法介绍实验分析 算法介绍 密度聚类是一种无监督学习的聚类方法&#xff0c;其目标是根据数据点的密度分布将它们分组成不同的簇。与传统的基于距离的聚类方法&#xff08;如K均值&#xff09;不同&#xff0c;密度聚类方法不需要预先指定簇的数量&#xff0c;而是通…

MGRE实验报告二

实验要求&#xff1a; 实验预览图&#xff1a; 实验分析&#xff1a; 1、对R1-R5配置IP地址&#xff0c;同时R1-R5每个路由器各有一个环回 2.1、对R1、R3、R4路由器开启虚拟接口1&#xff0c;分别配置隧道IP、接口封装协议&#xff0c;接口类型、定义封装源、开启伪广播功能&…

Mysql 删除数据

从数据表中删除数据使用DELETE语句&#xff0c;DELETE语句允许WHERE子句指定删除条件。DELETE语句基本语法格式如下&#xff1a; DELETE FROM table_name [WHERE <condition>]; table_name指定要执行删除操作的表&#xff1b;“[WHERE <condition>]”为可选参数&a…

Nginx 1.25配置QUIC和HTTP3

Nginx 1.25配置QUIC和HTTP/3 Nginx在编译时需要配置相应的SSL库&#xff0c;以确保能够支持HTTP3.0和HTTP2.0等基于HTTPS的协议。这些加密算法主要由OpenSSL提供。另外&#xff0c;BoringSSL是谷歌创建的OpenSSL分支&#xff0c;专门用于支持TLS 1.3的UDP协议的0-RTT数据传输加…

从C向C++6——运算符重载

本文的主要知识点是C中的运算符重载。 1.运算符重载 所谓重载&#xff0c;就是赋予新的含义。函数重载&#xff08;Function Overloading&#xff09;可以让一个函数名有多种功能&#xff0c;在不同情况下进行不同的操作。**运算符重载&#xff08;Operator Overloading&#…

【VS Code+Verilog+Vivado使用】(1)常用插件

文章目录 1 常用插件1.1 Chinese Language Pack1.2 Verilog-HDL/SV/BSV1.2.1 语法高亮1.2.2 代码片段1.2.3 代码检查1.2.4 Ctags1.2.4.1 自动补全设置1设置2 1.2.4.2 悬停显示1.2.4.3 转到定义1.2.4.4 查看定义1.2.4.5 模块例化设置1 1.3 vscode-icons1.4 Hex Editor1.5 Error …

Web开发8:前后端分离开发

在现代的 Web 开发中&#xff0c;前后端分离开发已经成为了一种常见的架构模式。它的优势在于前端和后端可以独立开发&#xff0c;互不干扰&#xff0c;同时也提供了更好的可扩展性和灵活性。本篇博客将介绍前后端分离开发的概念、优势以及如何实现。 什么是前后端分离开发&am…

国考省考行测:逻辑判断,分析推理,排除法,假设法

国考省考行测&#xff1a;逻辑判断&#xff0c;分析推理 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国考省考最重要的还是申论和行测&#xff0c;所以大家认真准备吧&#xff0c;我讲一起屡屡申论和…

【数据结构与算法】之哈希表系列-20240129

这里写目录标题 一、217. 存在重复元素二、219. 存在重复元素 II三、242. 有效的字母异位词四、268. 丢失的数字五、290. 单词规律六、349. 两个数组的交集七、350. 两个数组的交集 II 一、217. 存在重复元素 简单 给你一个整数数组 nums 。如果任一值在数组中出现至少两次 &a…

Java 面试题之 IO(二)

字符流 文章目录 字符流Reader&#xff08;字符输入流&#xff09;Writer&#xff08;字符输出流&#xff09; 文章来自Java Guide 用于学习如有侵权&#xff0c;立即删除 不管是文件读写还是网络发送接收&#xff0c;信息的最小存储单元都是字节。 那为什么 I/O 流操作要分为字…

【linux】-linux操作系统分支及包管理系统

一、Linux主要版本分支 免费的&#xff1a;ubuntu、centos&#xff0c;分属红帽、大便分支。 centos渐渐退出&#xff0c;CentOS 之父创造的 Rocky Linux&#xff08;再见 CentOS! Rocky Linux 要来了&#xff09; 二、Rocky Linux 官方地址&#xff1a;https://rockylinux.…

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

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

【Python笔记-设计模式】建造者模式

一、说明 又称生成器&#xff0c;是一种创建型设计模式&#xff0c;使其能够分步骤创建复杂对象。允许使用相同的创建代码生成不同类型和形式的对象。 (一) 解决问题 对象的创建问题&#xff1a;当一个对象的构建过程复杂&#xff0c;且部分构建过程相互独立时&#xff0c;可…

吉利汽车:S-SDLC融入开发体系,推动智能汽车安全发展

吉利汽车是中国汽车行业的知名品牌&#xff0c;是一家具有国际化视野的汽车企业&#xff0c;在中国汽车市场自主品牌中占据领军地位。吉利汽车集团数字化中心利用数字化技术优势赋能业务升级&#xff0c;推动研发效率提升和产品安全能力拓展&#xff0c;进行整体数字化转型。 在…

键盘上Ins键的作用

前几天编写文档时&#xff0c;发现一个问题&#xff1a;插入内容时&#xff0c;输入的字符将会覆盖光标位置后的字符。原来是按到了键盘上的 Ins键&#xff0c;解决方法是&#xff1a;再按一次 Ins键&#xff08;Ins键如果独立作为一键时&#xff0c;否则使用 “Fn Ins”组合键…

C++ —— 智能指针

C —— 智能指针 文章目录 C —— 智能指针一、为什么需要使用智能指针&#xff1f;二、内存泄漏什么是内存泄漏&#xff1f;内存泄漏的危害&#xff1f;内存泄漏分类 三、智能指针的使用及原理1. RAII2. 智能指针的原理 三、智能指针的缺陷及其发展3.1 std::auto_ptr3.2 std::…

华为笔记本matebook pro X如何扩容 C 盘空间

一、前提条件 磁盘扩展与合并必须是相邻分区空间&#xff0c;且两个磁盘类型需要相同。以磁盘分区为 C 盘和 D 盘为例&#xff0c;如果您希望增加 C 盘容量&#xff0c;可以先将 D 盘合并到 C 盘&#xff0c;然后重新创建磁盘分区&#xff0c;分配 C 盘和 D 盘的空间大小。 访…

Element ui 的组件弹窗 el-dialog点击的时候全屏变灰问题解决

最近在使用Element UI 的弹窗组件的时候发现这个组件各种的应用都没有问题&#xff0c;数据和元素的应用都是正确的但是在点击显示这个弹窗的时候全屏幕都会变灰。 这也不是因为增加了modal 遮挡幕的问题&#xff0c;在经过不断的排查代码的时候基本排除了代码的问题&#xf…

利用外卖系统源码构建高效的在线订餐平台

在当今数字化时代&#xff0c;外卖服务已成为人们日常生活中不可或缺的一部分。为了满足用户需求&#xff0c;许多创业者和企业都希望搭建自己的在线订餐平台。利用现有的外卖系统源码&#xff0c;可以快速构建一个高效、安全的在线订餐平台。本文将介绍如何利用外卖系统源码来…