您的位置:首页 > 编程语言

代码自动生成工具(三)-Xml读表代码自动生成工具

2018-01-18 10:48 471 查看
之前提到了一个工具类XmlReader

这里我们实现一个可以对Xml文件,自动生成其对应的读表代码。

本工具需要boost库支持,本人用的是1.55.0。

首先人为约定两个xml结点属性名称的保留关键字:pk=“”,rk=“”。

pk的值是本结点的某一个字段的名字,用来表示本结点在其父结点中,采用map来管理,键值就是该字段的值。

rk的值是本结点中某两个同类型的字段的名字,这两个字段用来表示一个闭区间,使得本结点在其父结点中,采用rangmap来管理,区间的起始值和终止值,就是这两个字段所填的值。

没有配置键的情况下,子节点在父结点中采用vector管理。

pk或rk 在相同结构路径下,只需要配置一次就可以,不需要每个节点都配置。

对于字段的数据类型,采用正则表达式判断识别,如果同一个字段,即出现整数,又出现浮点数,则按浮点数处理;即出现数字,又出现字符串,按字符串处理;如果同一个字段,出现不能兼容的两种类型,比如同时有数字和时间,按字符串处理。

这里首先定义Xml中支持的几种列类型:XmlMemberType:包括整数,小数,浮点数,字符串,时间戳,子结构等等

enum XmlMemberType
{
XMT_init = 0,	// 未初始化的
XMT_uint32,		// 无符号整数
XMT_int32,		// 整数
XMT_float,		// 浮点数
XMT_datetime,	// 年-月-日 时:分:秒表示的时间
XMT_time,		// 时:分:秒表示的时间
XMT_rang,		// int-int这样的两个数字表示的区间值
XMT_string,		// 字符串
XMT_child,		// 子结构
XMT_unknow,		// 非法的类型(同一个字段出现了两种不能互相兼容的类型)
XMT_count,
};


列主键的类型

enum XmlMemberKey
{
XMK_pk = 0,		// 主键
XMK_rang,		// 范围主键
XMK_normal,		// 普通成员
};


xml结构成员的定义,包括名字,类型,是否是主键

class XmlMember
{
public:
XmlMember();
XmlMember(const XmlMember &other);
XmlMember& operator = (const XmlMember &other);
void Init();
std::string m_Name;		// xml结构字段名称
XmlMemberType m_Type;	// xml结构字段类型
XmlMemberKey m_Key;		// xml结构字段是否作为主键使用
};


xml结构的定义,包含结构名称,结构成员列表

class XmlStruct
{
public:
XmlStruct();
XmlStruct(const XmlStruct &other);
XmlStruct& operator = (const XmlStruct &other);
void Init();
const XmlMember* GetPrimaryKey() const;
std::vector<const XmlMember*> GetRangKey() const;
std::string m_Name;							// 结构名称
std::map<std::string, XmlMember> m_Members;	// 结构字段列表
};


整个xml文件:包括文件名,包名,结构列表

class XmlFile
{
public:
XmlFile();
XmlFile(const XmlFile &other);
XmlFile& operator = (const XmlFile &other);
void Init();
std::string m_FileName;						// xml文件名(不带扩展名)
std::string m_Package;						// xml包名xxx.xxx.xxx
std::map<std::string, XmlStruct> m_Structs;	// xml结构列表
};


xml文件解析类,读取文件文本内容,使用EBNF范式,分析文件内容,按相应配置(命名空间,文件路径等),解析生成相应的XmlFile对象,

class XmlParse
{
public:
XmlParse();
~XmlParse();
bool ParseFile(const char* fullPathName);
private:
bool ParseXml(const char* expr);
void ParseXmlStruct(const char* start, const char* end);
void ParseXmlStructEnd(const char* start, const char* end);
void ParseXmlStructEnd1(const char* start, const char* end);
void ParseXmlStructEnd2(const char* start, const char* end);
void ParseXmlMemberName(const char* start, const char* end);
void ParseXmlMemberValue(const char* start, const char* end);
public:
// 解析完毕的xml文件信息列表
std::map<std::string, XmlFile> m_Files;
private:
// 解析时,临时xml文件内容对象
common::tool::FileData m_FileData;
// 解析时,临时xml文件对象
XmlFile m_TempFile;
// 解析时,临时xml结构对象
XmlStruct m_TempStruct;
// 解析时,临时xml结构成员对象
XmlMember m_TempMember;
// 用于判断结构父子关系的栈
std::stack<std::string> m_ChildName;
// xml文件解析工具输入参数
public:
std::string m_NameSpace; // 自定义命名空间
bool m_ThreadSpecific;	// 是否需要线程本地表格数据
std::vector<std::string> m_XmlFileName; // 待处理的xml文件列表
std::string m_LoaderPath; // loader输出cpp代码路径
std::string m_HelperPath; // helper输出cpp代码路径
};


具体的代码生成包含两部分功能:

void ParseXml2LoaderH(const XmlParse& xmlParse)

void ParseXml2LoaderCpp(const XmlParse& xmlParse)

void ParseXml2HelperH(const XmlParse& xmlParse)

void ParseXml2HelperCpp(const XmlParse& xmlParse)

传入一个解析好的XmlParse对象,生成具体代码

Loader生成对应的读取代码,使用boost::ptree读取xml文件,转成相应的数据结构。

Helper生成一个空的辅助类,用于需要对数据重新组织的情况,比如配置中是按某个id列作为主键,存成一个map,提供查找,但是实际逻辑中还需要按某个名称列作为索引,再提供一个map,用于提供按名称查找(或者模糊查找),这时候就需要手动再提供一个新的查找函数,就可以写在helper中

main函数涉及两个小功能:

一个是遍历输入参数,解析名命名空间,待处理的xml文件,代码生成路径

一个是迭代每一个待处理的xml文件名,传入XmlParse解析,然后对解析完的结果,逐个生成相应代码

完整的代码,比较长,这里就不贴了

给一个生成后的代码的示例吧:

xml文件:

<Tests>
<Node id="10000" pk="id">
<Time begin="2018-1-18 00:00:00" end="2018-1-18 23:59:59" rk="begin;end" num="1"/>
<Time begin="2018-1-19 00:00:00" end="2018-1-19 23:59:59" num="1"/>
<Time begin="2018-1-20 00:00:00" end="2018-1-20 23:59:59" num="1"/>
</Node>
<Node id="10001">
<Time begin="2018-1-18 00:00:00" end="2018-1-18 23:59:59" num="1"/>
<Time begin="2018-1-19 00:00:00" end="2018-1-19 23:59:59" num="1"/>
<Time begin="2018-1-20 00:00:00" end="2018-1-20 23:59:59" num="1"/>
</Node>
</Tasks>

生成的代码:

#ifndef __TestsXmlLoader_h__
#define __TestsXmlLoader_h__

#include <string>
#include <vector>
#include <map>

#include "rangmap.h"

namespace common {
namespace xml {

class Tests
{
public:
class Node
{
public:
class Time
{
public:
Time();
Time(const Time& other);
Time& operator=(const Time& other);
~Time();

time_t m_begin;
time_t m_end;
unsigned int m_num;
};

public:
Node();
Node(const Node& other);
Node& operator=(const Node& other);
~Node();

void AddTime(time_t begin, time_t end, const Time& val);
const Time* GetTime(time_t key) const;

common::tool::rangmap<time_t, Time> m_Time;
unsigned int m_id;
};

public:
Tests();
Tests(const Tests& other);
Tests& operator=(const Tests& other);
~Tests();

void AddNode(unsigned int key, const Node& val);
const Node* GetNode(unsigned int key) const;

std::map<unsigned int, Node> m_Node;
};

class TestsXmlLoader
{
public:
TestsXmlLoader()
{
}
~TestsXmlLoader()
{
}

bool LoadFile(const char* szPath);
bool ReloadFile(const char* szPath);

const Tests& GetTests() const;

private:
Tests m_Tests;
};

}
}
#endif


放上完整工程的下载链接
工程中的boost库的路径为作者本机的路径,VS编译时请选择Release,重新配置boost库的include路径和lib路径
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息