QT开发技术 【基于TinyXml2的对类进行序列化和反序列化】一

news2025/2/26 6:09:42

一、对TinyXml2 进行封装 使用宏 实现序列化和反序列化

思路:
利用宏增加一个类函数,使用序列化器调用函数进行序列化

封装宏示例

#define XML_SERIALIZER_BEGIN(ClassName) \
public: \
    virtual void ToXml(XMLElement* parentElem, bool bSerialize = true) { \
        if (bSerialize) { \
             parentElem->SetName(#ClassName); \
        }\
            
#define XML_SERIALIZER_VAR(Name, Value) \
        if (bSerialize) { \
            CXmlImplement::WriteElement(parentElem, Name, Value); \
        } \
        else { \
            CXmlImplement::ReadElement(parentElem, Name, Value); \
        } \

#define XML_SERIALIZER_STL_VAR(Name, Value) \
        if (bSerialize) { \
            CXmlImplement::WriteSTLElement(parentElem, Name, Value); \
        } \
        else { \
            CXmlImplement::ReadSTLElement(parentElem, Name, Value); \
        } \

#define XML_SERIALIZER_ARRAY(Name, Object) \
        if (bSerialize) { \
            CXmlImplement::WriteElementObject(parentElem, Name, Object); \
        } \
        else { \
            CXmlImplement::ReadElementObject(parentElem, Name, Object); \
        } \

#define XML_SERIALIZER_END() \
    } \

目前只封装了简单使用的,需要其他自己可以增加

二、类使用宏

新建一个student 类 增加宏

class CStudent
{
public:
    CStudent()
    {
        std::cout << "Constructor CStudent" << std::endl;
    }
    ~CStudent()
    {
        std::cout << "Destructor CStudent" << std::endl;
    }

    XML_SERIALIZER_BEGIN(CStudent)
    XML_SERIALIZER_VAR("学号", m_nStudentID)
    XML_SERIALIZER_VAR("姓名", m_strName)
    XML_SERIALIZER_VAR("年龄", m_nAge)
    XML_SERIALIZER_VAR("性别", m_nSex)
    XML_SERIALIZER_END()


    int m_nStudentID;
    std::string m_strName;
    int m_nAge;
    int m_nSex;
};  

这样一个类就增加了想要的序列化函数

三、实现序列化器

利用TinyXml2实现序列化器封装

3.1、TinyXml2介绍

TinyXML-2 是一个简单,小型,高效的 C ++ XML 解析器,可以轻松集成到其他程序中,直接引用源文件的话只需要包含两个文件(h 和 cpp,此外还有个测试文件里面带有 demo)。

TinyXML-2 解析 XML 文档,并以此为基础构建可读取,修改和保存的文档对象模型(DOM)。文档说,在解释 XML 时仅使用 UTF-8 ,假定所有 XML 为 UTF-8 (看了下使用 MSVC 编译器时生成的 XML 文件文本编码使用的本地编码)。该库还支持打印到文件或内存,使用 XMLPrinter 类。

GitHub 链接:[链接](https://github.com/leethomason/tinyxml2)

使用模板对TinyXml2 序列化进行封装

/*
**  File name:   XmlImplement.h
**  Author:      
**  Date:        2025-01-16
**  Brief:       xml序列化实现类
**  Copyright (C) 1392019713@qq.com All rights reserved.
*/

#pragma once
#include <string>
#include <vector>
#include <iostream>
#include "tinyxml2.h"
#include "XmlSerializerExportLib.h"

using namespace tinyxml2;

class  CXmlImplement {
public:
    template <typename T>
    static void WriteElement(XMLElement* parentElem, const std::string& elementName, const T& value) {
        XMLElement* elem = parentElem->GetDocument()->NewElement(elementName.c_str());
        elem->SetText(value);
        parentElem->InsertEndChild(elem);
    }

    static void WriteElement(XMLElement* parentElem, const std::string& elementName, const std::string& value) {
        XMLElement* elem = parentElem->GetDocument()->NewElement(elementName.c_str());
        elem->SetText(value.c_str());
        parentElem->InsertEndChild(elem);
    }

    template <typename T>
    static void WriteSTLElement(XMLElement* parentElem, const std::string& elementName, const std::vector<T>& values) {
        XMLElement* vectorElem = parentElem->GetDocument()->NewElement(elementName.c_str());
        if (!vectorElem)
        {
            return;
        }
        for (const auto& value : values) {
            WriteElement(vectorElem, elementName + "Item", value);
        }
        parentElem->InsertEndChild(vectorElem);
    }

    template <typename T>
    static void ReadElement(XMLElement* parentElem, const std::string& elementName, T& value) {
        XMLElement* elem = parentElem->FirstChildElement(elementName.c_str());
        if (elem) {
            value = std::stoi(elem->GetText());
        }
    }

    static void ReadElement(XMLElement* parentElem, const std::string& elementName, std::string& value) {
        XMLElement* elem = parentElem->FirstChildElement(elementName.c_str());
        if (elem) {
            value = elem->GetText();
        }
    }

    template <typename T>
    static void ReadSTLElement(XMLElement* parentElem, const std::string& elementName, std::vector<T>& values) {
        XMLElement* vectorElem = parentElem->FirstChildElement(elementName.c_str());
        if (!vectorElem)
        {
            return;
        }
        for (XMLElement* elem = vectorElem->FirstChildElement(); elem; elem = elem->NextSiblingElement())
        {
            T value;
            ReadElement(elem, elem->Name(), value);
            values.push_back(value);
        }
    }

    template <typename T>
    static void WriteElementObject(XMLElement* parentElem, const std::string& elementName,  T* pT) {
        XMLElement* elem = parentElem->GetDocument()->NewElement(elementName.c_str());
        pT->ToXml(elem);
        parentElem->InsertEndChild(elem);
    }

    template <typename T>
    static void WriteElementObject(XMLElement* parentElem, const std::string& elementName, const std::vector<T*>& objects) {
        XMLElement* vectorElem = parentElem->GetDocument()->NewElement(elementName.c_str());
        for (const auto& object : objects) {
            WriteElementObject(vectorElem, elementName + "Item", object);
        }
        parentElem->InsertEndChild(vectorElem);
    }

    template <typename T>
    static void ReadElementObject(XMLElement* parentElem, const std::string& elementName, T* pT, bool array = false) {
        XMLElement* elem;
        if (array)
        {
            elem = parentElem;
        }
        else
        {
            elem = parentElem->FirstChildElement(elementName.c_str());
        }
        if (elem) {
            pT->ToXml(elem, false);
        }
    }

    template <typename T>
    static void ReadElementObject(XMLElement* parentElem, const std::string& elementName, std::vector<T*>& vecObjs) {
        XMLElement* objectElem = parentElem->FirstChildElement(elementName.c_str());
        for (XMLElement* elem = objectElem->FirstChildElement(); elem; elem = elem->NextSiblingElement())
        {
            T* pT = new T();
            ReadElementObject(elem, elem->Name(), pT, true);
            vecObjs.push_back(pT);
        }
    }

    template <typename T>
    static bool Serialize(std::string& strXml, T* pT) {
        bool bRet = false;
        if (!pT)
        {
            return bRet;
        }
        XMLDocument doc;
        XMLDeclaration* declaration = doc.NewDeclaration();
        declaration->SetValue("xml version=\"1.0\" encoding=\"GB2312\"");
        doc.InsertFirstChild(declaration);
        XMLElement* rootElem = doc.NewElement("Root");
        if (!rootElem)
        {
            return bRet;
        }
        pT->ToXml(rootElem);
        doc.InsertEndChild(rootElem);

        XMLPrinter printer;
        doc.Accept(&printer);
        strXml = printer.CStr();
        return true;
    }

    template <typename T>
    static bool Deserialize(const std::string& xml, T* pT) {
        bool bRet = false;
        if (!pT)
        {
            return bRet;
        }

        XMLDocument doc;
        XMLError result = doc.Parse(xml.c_str());

        if (result != XML_SUCCESS) {
            std::cerr << "Failed to parse XML: " << XMLDocument::ErrorIDToName(result) << std::endl;
            return bRet;
        }

        XMLElement* rootElem = doc.RootElement();
        if (rootElem) {
            pT->ToXml(rootElem, false);
        }
        return true;
    }
};

四、使用测试

增加2个类测试

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include "../../XmlSerialize/Include/XmlSerializer.h"


class CStudent
{
public:
    CStudent()
    {
        std::cout << "Constructor CStudent" << std::endl;
    }
    ~CStudent()
    {
        std::cout << "Destructor CStudent" << std::endl;
    }

    XML_SERIALIZER_BEGIN(CStudent)
    XML_SERIALIZER_VAR("学号", m_nStudentID)
    XML_SERIALIZER_VAR("姓名", m_strName)
    XML_SERIALIZER_VAR("年龄", m_nAge)
    XML_SERIALIZER_VAR("性别", m_nSex)
    XML_SERIALIZER_END()


    int m_nStudentID;
    std::string m_strName;
    int m_nAge;
    int m_nSex;
};  


class CClass //: public CXmlSerializer
{
public:
    CClass()
    {
        
    }
    ~CClass()
    {
        for (auto itr = m_vecStudents.begin(); itr != m_vecStudents.end();)
        {
            CStudent* pStudent = *itr;
            if (pStudent)
            {
                std::cout << pStudent->m_nStudentID << " " << pStudent->m_strName << std::endl;
                delete pStudent;
                itr = m_vecStudents.erase(itr);
                
            }
            else
            {
                ++itr;
            }
        }
        m_vecStudents.clear();
    }

    XML_SERIALIZER_BEGIN(CClass)
    XML_SERIALIZER_VAR("班级名称", m_strName)
    XML_SERIALIZER_VAR("班级ID", m_nClassID)
    XML_SERIALIZER_ARRAY("学生列表", m_vecStudents)
    XML_SERIALIZER_END()
    std::string m_strName;
    int m_nClassID;
    std::vector<CStudent*> m_vecStudents;
};


void TestXml()
{
    {
        CStudent student;
        student.m_nStudentID = 1001;
        student.m_strName = "张三";
        student.m_nAge = 20;
        student.m_nSex = 1;

        std::string strXml;
        CXmlImplement::Serialize(strXml, &student);
        std::ofstream ofs("E:/Project/Inlib/Base/Examples/Bin/Debug/student.xml");
        ofs << strXml;


        CStudent student2;
        CXmlImplement::Deserialize(strXml, &student2);
        std::cout << student2.m_nStudentID << std::endl;
        std::cout << student2.m_strName << std::endl;
        student2.m_strName = "李四";
        student2.m_nStudentID = 1002;

        CClass class1;
        class1.m_strName = "1班";
        class1.m_nClassID = 101;
        class1.m_vecStudents.push_back(&student);
        class1.m_vecStudents.push_back(&student2);
        CXmlImplement::Serialize(strXml, &class1);
        std::ofstream ofs1("E:/Project/Inlib/Base/Examples/Bin/Debug/class.xml");
        ofs1 << strXml;
    }
    std::cout << "------class Begin--------------" << std::endl;


    std::ifstream ifs("E:/Project/Inlib/Base/Examples/Bin/Debug/class.xml");
    std::string strXml = std::string((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
    CClass class2;
    CXmlImplement::Deserialize(strXml, &class2);
    std::cout << class2.m_strName << std::endl;
}

int main()
{

    TestXml();
    
    return 0;
}

生成结果

在这里插入图片描述

如果文章帮到你,动动小手点赞 (-_-)

下一篇文章链接 QT开发技术 【基于TinyXml2的对类进行序列化和反序列化】 二

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录训练营第五十一天| 99.岛屿数量 深搜 岛屿数量 广搜 100.岛屿的最大面积

99.岛屿数量 深搜 题目链接&#xff1a;99. 岛屿数量 讲解链接&#xff1a;代码随想录 就是dfs模版题目 在dfs里可以先定义方向数组移动 再遍历分别向四个方向移动 同时记得更新当前nextx nexty 再判断是否越界 再执行判断条件 当前位置未走过 visited[i][j] false 一开始jav…

【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发之常见布局

目录 1 -> 自适应布局 1.1 -> 线性布局 1.1.1 -> 线性布局的排列 1.1.2 -> 自适应拉伸 1.1.3 -> 自适应缩放 1.1.4 -> 定位能力 1.1.5 -> 自适应延伸 1.2 -> 层叠布局 1.2.1 -> 对齐方式 1.2.2 -> Z序控制 1.3 -> 弹性布局 1.3.1…

docker 部署 MantisBT

1. docker 安装MantisBT docker pull vimagick/mantisbt:latest 2.先运行实例&#xff0c;复制配置文件 docker run -p 8084:80 --name mantisbt -d vimagick/mantisbt:latest 3. 复制所需要配置文件到本地路径 docker cp mantisbt:/var/www/html/config/config_inc.php.…

【Linux系统编程】—— 深度解析进程等待与终止:系统高效运行的关键

文章目录 进程创建再次认识fork()函数fork()函数返回值 写时拷贝fork常规⽤法以及调用失败的原因 进程终⽌进程终止对应的三种情况进程常⻅退出⽅法_exit函数exit函数return退出 进程等待进程等待的必要性进程等待的⽅法 进程创建 再次认识fork()函数 fork函数初识&#xff1…

学习MyBatis的调优方案

MyBatis是一款优秀的Java持久层框架&#xff0c;它简化了数据库操作&#xff0c;并提供了灵活的SQL查询机制。然而&#xff0c;在实际应用中&#xff0c;我们可能会遇到一些性能问题&#xff0c;这时需要对MyBatis进行合理的调优。本文将详细探讨MyBatis的调优方案&#xff0c;…

python_在钉钉群@人员发送消息

python_在钉钉群人员发送消息 1、第一种 企业内部机器人群聊实现人接入指南&#xff0c;适用于群机器人接收消息&#xff0c;处理完一系列的动作之后&#xff0c;将消息返回给发消息的人员&#xff0c;同时该人员。 需要在企微后台新建一个自建应用&#xff0c;在自建应用里…

【Linux】进程优先级与进程切换

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;Linux &#x1f339;往期回顾&#x1f339;&#xff1a;【Linux】进程状态 &#x1f516;流水不争&#xff0c;争的是滔滔不 一、进程优先级是什么二、查看系统进程三…

imbinarize函数用法详解与示例

一、函数概述 众所周知&#xff0c;im2bw函数可以将灰度图像转换为二值图像。但MATLAB中还有一个imbinarize函数可以将灰度图像转换为二值图像。imbinarize函数是MATLAB图像处理工具箱中用于将灰度图像或体数据二值化的工具。它可以通过全局或自适应阈值方法将灰度图像转换为二…

电商项目高级篇08-springCache

电商项目高级篇08-springCache 1、整合springCache2、Cacheable细节设置 1、整合springCache 1、引入依赖 <!--引入springCache--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifa…

macOS 安装JDK17

文章目录 前言介绍新特性下载安装1.下载完成后打开downloads 双击进行安装2.配置环境变量3.测试快速切换JDK 小结 前言 近期找开源软件&#xff0c;发现很多都已经使用JDK17springboot3 了&#xff0c;之前的JDK8已经被替换下场&#xff0c;所以今天就在本机安装了JDK17&#…

ASP.NET Core - 配置系统之配置提供程序

ASP.NET Core - 配置系统之配置提供程序 3. 配置提供程序3.1 文件配置提供程序3.1.1 JSON配置提供程序3.1.2 XML配置提供程序3.1.3 INI配置提供程序 3.2 环境变量配置提供程序3.3 命令行配置提供程序3.4 内存配置提供程序3.5 配置加载顺序 3.6 默认配置来源 3. 配置提供程序 前…

[手机Linux] ubuntu 错误解决

Ubuntu: 1,ttyname failed: Inappropriate ioctl for device 将 /root/.profile 文件中的 mesg n || true 改为如下内容。 vim /root/.profile tty -s && mesg n || true 2,Errors were encountered while processing: XXX XXXX sudo apt-get --purge remove xxx…

【2024年华为OD机试】 (B卷,100分)- 敏感字段加密(Java JS PythonC/C++)

一、问题描述 题目描述 给定一个由多个命令字组成的命令字符串&#xff1a; 字符串长度小于等于 127 字节&#xff0c;只包含大小写字母、数字、下划线和偶数个双引号&#xff1b;命令字之间以一个或多个下划线 _ 进行分割&#xff1b;可以通过两个双引号 "" 来标…

使用 ChatGPT 生成和改进你的论文

文章目录 零、前言一、操作引导二、 生成段落或文章片段三、重写段落四、扩展内容五、生成大纲内容六、提高清晰度和精准度七、解决特定的写作挑战八、感受 零、前言 我是虚竹哥&#xff0c;目标是带十万人玩转ChatGPT。 ChatGPT 是一个非常有用的工具&#xff0c;可以帮助你…

【C语言系列】深入理解指针(1)

前言 总所周知&#xff0c;C语言中指针部分是非常重要的&#xff0c;这一件我们会介绍指针相关的内容&#xff0c;当然后续我还会出大概4篇与指针相关的文章&#xff0c;来深入的讲解C语言指针部分&#xff0c;希望能够帮助到指针部分薄弱或者根本不会的程序员们&#xff0c;后…

深度学习 Pytorch 基本优化思想与最小二乘法

在正式开始进行神经网络建模之前&#xff0c;我们还需要掌握pytorch中最核心的基础数学工具——autograd(自动微分)模块。虽然对于任何一个通用的深度学习框架都会提供许多自动优化的算法和现成的loss function&#xff0c;但如果想更深入理解神经网络&#xff0c;对深度学习的…

如何在vue中渲染markdown内容?

文章目录 引言什么是 markdown-it&#xff1f;安装 markdown-it基本用法样式失效&#xff1f;解决方法 高级配置语法高亮 效果展示 引言 在现代 Web 开发中&#xff0c;Markdown 作为一种轻量级的标记语言&#xff0c;广泛用于文档编写、内容管理以及富文本编辑器中。markdown…

N个utils(sql)

sql&#xff0c;操作数据库的语言&#xff0c;也可以叫做数据库软件的指令集吧。名字而已&#xff0c;无所谓啦。 本质上&#xff0c;sql并不是java语言内的范畴。但却是企业级开发的范畴。并且我整个文章的一篇逻辑的本质&#xff0c;层的概念&#xff0c;其中一个大的层级就…

Linux虚拟机安装与FinalShell使用:探索Linux世界的便捷之旅

文章目录 软件准备安装 VMware 虚拟机下载CentOS 光盘镜像文件选择适合的 CentOS 版本选择合适的镜像文件 本教程工具版本 第一部分&#xff1a;安装 Linux 虚拟机1. 启动 VMware 并创建新虚拟机2. 默认硬件兼容性设置3. 安装操作系统的设置4. 选择操作系统类型与版本5. 为虚拟…

CSS 网络安全字体

适用于 HTML 和 CSS 的最佳 Web 安全字体 下面列出了适用于 HTM L和 CSS 的最佳 Web 安全字体&#xff1a; Arial (sans-serif)Verdana (sans-serif)Helvetica (sans-serif)Tahoma (sans-serif)Trebuchet MS (sans-serif)Times New Roman (serif)Georgia (serif)Garamond (se…