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

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

思路:

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

封装宏示例

cpp 复制代码
#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 类 增加宏

cpp 复制代码
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 序列化进行封装

cpp 复制代码
/*
**  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个类测试

cpp 复制代码
#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的对类进行序列化和反序列化】 二

相关推荐
AIzealot无1 小时前
力扣hot100之螺旋矩阵
算法·leetcode·矩阵
兑生1 小时前
力扣面试150 长度最小的子数组 滑动窗口
算法·leetcode·面试
miilue1 小时前
[LeetCode] 链表I — 704#设计链表 | 203#移除链表元素 | 206#反转链表 | 递归法
java·开发语言·c++·算法·leetcode·链表
Tisfy1 小时前
LeetCode 2266.统计打字方案数:排列组合
数学·算法·leetcode·动态规划·题解·排列组合
Joyner20181 小时前
python-leetcode-汇总区间
算法·leetcode·职场和发展
win水1 小时前
数据结构(初阶)(二)----顺序表
c语言·数据结构·算法
万事可爱^2 小时前
算法入门(九)—— 无监督学习介绍与K-Means实战(内附Kaggle实战源码与数据集)
人工智能·学习·算法·机器学习·kmeans
_.Switch2 小时前
FastAPI 应用的容器化与 Docker 部署:提升性能与可扩展性
数据库·python·网络协议·docker·容器·eureka·fastapi
小菜鸟博士2 小时前
大模型学习笔记 - 第一期 - Milvus向量数据库
数据库·笔记·学习·算法·milvus
kcarly2 小时前
认识 Milvus 向量数据库
数据库·milvus·向量数据库