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的对类进行序列化和反序列化】 二

相关推荐
正在走向自律28 分钟前
X2Doris是SelectDB可视化数据迁移工具,安装与部署&使用手册,轻松进行大数据迁移
数据库·数据迁移·selectdb·x2doris·数据库迁移工具
KarrySmile30 分钟前
Day17--二叉树--654. 最大二叉树,617. 合并二叉树,700. 二叉搜索树中的搜索,98. 验证二叉搜索树
数据结构·算法·二叉树·二叉搜索树·合并二叉树·最大二叉树·验证二叉搜索树
凤年徐31 分钟前
【数据结构与算法】21.合并两个有序链表(LeetCode)
c语言·数据结构·c++·笔记·算法·链表
tuokuac32 分钟前
SQL中的LEFT JOIN
数据库·sql
tuokuac36 分钟前
SQL中的GROUP BY用法
数据库·sql
程序员老冯头40 分钟前
第三十二节 MATLAB函数
数据结构·算法·matlab
爱吃小土豆豆豆豆41 分钟前
登录校验一
java·大数据·数据库
lifallen44 分钟前
hadoop.yarn 带时间的LRU 延迟删除
java·大数据·数据结构·hadoop·分布式·算法
黑塞1231 小时前
Qt deleteLater 延迟删除原理
qt
jingjing~1 小时前
【Qt】QTime::toString(“hh:mm:ss.zzz“) 显示乱码的原因与解决方案
java·开发语言·qt