XML序列化数据对象(三)---实现
一.实现界面
1.1大致界面
图1
1.2类类型
图2
1.3变量输入
图3
二.使用步骤
2.1添加一些类
图4
2.2添加一些变量
图5
2.3可以保存类型和变量为xml文件
添加了类型和变量后,这些数据可以保存为xml文件(例如aa.xml),也可以重新加载这个XML文件,方便以后修改使用.
假设CTest类的结构变化了,那么序列化/反序列化的代码也就需要改变了,你可以重新加载aa.xml对CTest的结构修改,然后再次生成序列化/反序列化代码即可.
aa.xml文件:
<structure_def> <class name = "CTest"> <include file = "a" sys = "0"> </include> <include file = "b" sys = "1"> </include> </class> <basetype name = "int"> </basetype> <basetype name = "double"> </basetype> <basetype name = "long"> </basetype> <stltype name = "std::vector" typenamecount = "1"> </stltype> <stltemplate beptr = "0" beptr1 = "0" name = "IntVector" type = "std::vector" typename1 = "int"> </stltemplate> <ClassObject> <m_nA class = "int"> </m_nA> <m_dB class = "double"> </m_dB> <m_intVector class = "IntVector"> </m_intVector> </ClassObject> </structure_def>
2.4生成序列化/反序列化的代码
#pragma once // 这里include你自己的头文件 // 序列化 class CHYSerialization { public: CHYSerialization(); ~CHYSerialization(); bool SerializationOpen(const std::string& strFileName); bool SerializationClose(); // 基本类型的序列化 bool SerializationClassType_int(CHYMLItem* pCHYMLItemParent,const std::string& strObjectName,const int& nValue); bool SerializationClassType_long(CHYMLItem* pCHYMLItemParent,const long& lValue); bool SerializationClassType_double(CHYMLItem* pCHYMLItemParent,const double& dValue); bool SerializationClassType_float(CHYMLItem* pCHYMLItemParent,const float& fValue); bool SerializationClassType_char(CHYMLItem* pCHYMLItemParent,const char& chValue); bool SerializationClassType_string(CHYMLItem* pCHYMLItemParent,const std::string& strValue); // 用户定义的类/结构体等类型的序列化 bool SerializationClassType_CTest(CHYMLItem* pCHYMLItemParent,const CTest& refValue); bool SerializationClassType_IntVector(CHYMLItem* pCHYMLItemParent,const IntVector& refValue); // 变量的序列化函数 bool SerializationObject_m_nA(const int& refValue); bool SerializationObject_m_dB(const double& refValue); bool SerializationObject_m_intVector(const IntVector& refValue); private: CHYML m_hyML; // 你使用的XML解析库相关变量 CHYMLParser m_hyMLParser; CHYMLItem* m_pCHYMLItemParent; std::string m_strFileName; }; // 反序列化 class CHYReSerialization ... // Cpp文件代码很长 ...
2.5序列化/反序列化的代码的使用
变量m_nA,m_dB,m_intVector本身就是你的工程里面需要才添加到代码生成器的.
序列化:
// 你工程里的变量是这样的 int m_nA = 5; double m_dB = 5.9; IntVector m_intVector; m_intVector.push_back(1); m_intVector.push_back(3); m_intVector.push_back(4); m_intVector.push_back(7); .... // 序列化 CHYSerialization hySerialization; hySerialization.SerializationOpen("C:\ss.xml"); // 变量的序列化信息保存在ss.xml文件中 // 序列化这3个变量 hySerialization.SerializationObject_m_nA(m_nA); hySerialization.SerializationObject_m_dB(m_dB); hySerialization.SerializationObject_m_intVector(m_intVector); hySerialization.SerializationClose();
<ObjectSerialization> <m_nA class = "int"> 5 </m_nA> <m_dB class = "double"> 5.900000 </m_dB> <m_intVector class = "IntVector"> <vectorItem0 class = "int"> 1 </vectorItem0> <vectorItem1 class = "int"> 3 </vectorItem1> <vectorItem2 class = "int"> 4 </vectorItem2> <vectorItem3 class = "int"> 7 </vectorItem3> </m_intVector> </ObjectSerialization>
反序列化:
CHYReSerialization hyReSerialization; hyReSerialization.ReSerializationOpen("C:\ss.xml"); hyReSerialization.ReSerializationObject_m_nA(m_nA); hyReSerialization.ReSerializationObject_m_dB(m_dB); hyReSerialization.ReSerializationObject_m_intVector(m_intVector); hyReSerialization.ReSerializationClose();
初步使用了一下,效果还可以.
三.总结
3.1这样自动生成序列化/反序列化的代码使用起来的确比较方便,但是也有繁琐的地方,例如生成代码后,还要把h文件和cpp文件拷贝到自己的工程,还要在h文件中添加相关的头文件(你的类头文件).对比boost库,只需要些相关的模板代码代码就可以了.反正就是没有boost库方便.
3.2添加类类型的处理非常非常的繁琐和乱,因为类型很多(basetype,stltype,struct,class,stltemplate,typedef),还有很多判断条件,这些判断我是通过界面交互来处理的,可能还有很多没有考虑到的地方.可惜自己不懂C++的语法分析,通过语法分析,就很容易分析出这些类型,而且更强大.
3.3设计成类似boost库那样序列化的操作方式是不是更好?
3.4用代码写代码需要在更高一层上想问题.平时写代码,你直接把代码写入对应的cpp/h文件,然后编译,看是否有语法错误,编译通过了,就运行看有没有运行上/逻辑上的错误;用代码写代码还要加多一层,就是你先确保生成代码的程序(代码生成器)编译运行没错,然后编译生成器生成的代码,假设这代码有语法错误,你需要返回到生成器工程对应的字符地方修改这些字符,如果生成的代码语法没有但运行有错,那还要分析你所设计的生成代码是否有问题.这种过程是不断的在生成器代码和被生成代码之间切换,编译,生成,拷贝,编译.....(有时候会很乱!)
3.5通过序列化/反序列化代码生成器,体会到用代码写代码跟C++的模板编程(泛化编程)有与曲同工之妙!必须在更高一层处想问题.当然泛化编程更规范,更标准.(看这文章).
3.6C++代码生成器生成代码,生成的代码要编译后才能用,这是因为C++的语言特性决定的.假设我有一个代码生成器,生成的代码不需要编译,能直接使用,那多好啊.脚本语言可以(看这文章).