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