当前位置: 首页 > article >正文

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

一、对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.kler.cn/a/507153.html

相关文章:

  • LabVIEW与WPS文件格式的兼容性
  • OpenCV相机标定与3D重建(55)通用解决 PnP 问题函数solvePnPGeneric()的使用
  • 大文件上传的解决办法~文件切片、秒传、限制文件并发请求。。。
  • 计算机组成原理(计算机系统3)--实验二:MIPS64乘法实现实验
  • ubuntu20.04安装MySQL5.7
  • 工作中redis常用的5种场景
  • apidoc thinkphp likeadmin 遇到解析报错
  • element 日期时间组件默认显示当前时间
  • 2023 Google开发者大会:你了解机器学习的新动向吗?
  • Docker--Docker Container(容器) 之容器实战
  • RocketMQ 学习笔记01
  • 从Arrays源码学习定义工具类
  • sqlalchemy The transaction is active - has not been committed or rolled back.
  • leetcode hot100(2)
  • 【CSS】:nth-child和:nth-of-type
  • 【Elasticsearch】全文搜索与相关性排序
  • SCSSA-BiLSTM基于改进麻雀搜索算法优化双向长短期记忆网络多特征分类预测Matlab实现
  • UI自动化测试框架之PO模式+数据驱动
  • 如何选择合适的服务器?服务器租赁市场趋势分析
  • 【遥感目标检测】【数据集】DOTA:用于航空图像中目标检测的大规模数据集
  • 【深度学习】Pytorch:CUDA 模型训练
  • .net core 中使用AsyncLocal传递变量
  • 【实践功能记录9】使用pnpm打补丁
  • VD:生成a2l文件
  • Lora理解QLoRA
  • iOS - Objective-C 底层中的内存屏障