-- 作者:BetonArmEE
-- 发布时间:7/15/2009 11:44:00 PM
-- XML映射c语言结构源代码自动化工具
XML映射c语言结构源代码自动化工具 使用文档 calvin.xml2c@gmail.com 2009.7 谨以此文献给我亲爱的莫莫,她和她哥哥对网店的投入意外给了我写本文的时间。 版本修订 版本号 修订人 修订日期 修订内容 0.1.0 calvin 2009-07-13 创建 目录索引 版本修订 3 目录索引 4 1.概述 5 1.1.XML和映射c语言结构 5 1.2.xml2c是什么 6 1.3.感受一下XML新开发风格 6 2.使用教程 10 2.1.编写xmd定义文件 10 2.2.用xml2c处理后生成的源代码文件 11 2.3.嵌入你的应用代码 13 3.附录 14 I.关于作者和本文 14 II.xmd中已实现的数据类型描述 14 1.概述 1.1.XML和映射c语言结构 XML(Extensible Markup Language)即可扩展标记语言由于其跨平台性、自描述性、多层次化等优点目前被广泛使用。 XML处理过程代码风格比较成熟,各个函数库使用大同小异,甚至函数名也一样。主流操作无非就是读入外部XML文件或缓冲区,创建XML树,遍历处理树,导出树为外部XML文件或缓冲区。其中遍历处理树普遍采用硬编码方式,增加了应用代码复杂性风险性和编码负担。 XML和c语言结构都具备多层次化数据表达,不妨把两者建立映射关系,XML标记和c结构成员变量做元数据映射,类似于下例: XML数据: <userinfo> <username>calvin.xml2c@gmail.com</username> <password>123456</password> <regdate>2009-01-01</regdate> <logindate>2009-07-13</logindate> <extinfo> <age>30</age> <income>160000.00</income> <marriage>FALSE</marriage> </ extinfo> </userinfo> 对应c语言结构: struct userinfo { char username[ 64 + 1 ] ; char password[ 8 + 1 ] ; char regdate[ 10 + 1 ] ; char logindate[ 10 + 1 ] ; struct _extinfo { int age ; double income ; BOOL marriage ; } extinfo ; } 以上映射关系可以用XML定义格式(xmd)来描述: <userinfo> <username>char64</username> <password>char8</password> <regdate>date</regdate> <logindate>date</logindate> <extinfo> <age>int</age> <income>money</income> <marriage>BOOL</marriage> </extinfo > </userinfo > 1.2.xml2c是什么 xml2c是基于libxml2函数库的预处理XML定义描述文件生成c语言源代码的自动化工具。开发人员针对要处理的XML,改造成xmd,用工具xml2c处理后自动生成对应的c语言结构、XML格式-c结构格式相互转换函数以及周边源代码资源。 xml2c是跨平台的,这意味着你所能接触的几乎所有主流操作系统上都能使用它。 xml2c最新版本是v0.9.1(试验版)。 1.3.感受一下XML新开发风格 以1.2.为例,实现userinfo的文件读写处理。 稍作修改的XML定义描述文件(XML_test.xmd):(为什么要稍作修改呢?因为xml2c目前还不十分完善) <userinfo> <username>char64</username> <password>char8</password> <regdate>date</regdate> <logindate>date</logindate> <extinfo> <age>int</age> <income>double</income> <marriage>char5</marriage> </extinfo > </userinfo > 执行命令 “xml2c XML_test.xmd”,用工具xml2c处理XML_test.xmd后,你会找到一堆自动生成的c源代码文件: XML_test.XMLSTRUCT.h 对应c语言结构定义 XML_test.XMLDUMP.c c语言结构导出为外部XML文件或缓冲区格式转换函数 XML_test.XMLPARSE.c 外部XML文件或缓冲区映射为c语言结构格式转换函数 XML_test.XMLFREE.c 对变长元数据和变size数组的free操作函数 XML_test.XMLTRIM.c 裁剪各字符串变量右边白字符函数 (然后开发人员卷着袖子上场了)test.c: #include "libxml2c.h" #include "XML_test.XMLSTRUCT.h" int write_xmlfile() { struct XML_userinfo userinfo ; memset( & userinfo , 0x00 , sizeof(struct XML_userinfo) ); strcpy( userinfo.username , "calvin.xml2c@gmail.com" ); strcpy( userinfo.password , "123456" ); strcpy( userinfo.regdate , "2009-01-01" ); strcpy( userinfo.logindate , "2009-07-13" ); userinfo.extinfo.age = 30 ; userinfo.extinfo.income = 160000.00 ; strcpy( userinfo.extinfo.marriage , "FALSE" ); XMLDUMPFILE_userinfo( & userinfo , "test.xml" ); return 0; } int main() { return write_xmlfile(); } 编译链接执行,生成外部XML文件: <?xml version="1.0" encoding="GBK"?> <userinfo> <username>calvin.xml2c@gmail.com</username> <password>123456</password> <regdate>2009-01-01</regdate> <logindate>2009-07-13</logindate> <extinfo> <age>30</age> <income>160000.000000</income> <marriage>FALSE</marriage> </extinfo> </userinfo> okay,导出完成,再试试读入 int read_xmlfile() { struct XML_userinfo userinfo ; memset( & userinfo , 0x00 , sizeof(struct XML_userinfo) ); XMLPARSEFILE_userinfo( "test.xml" , & userinfo ); printf( "userinfo.username[%s]\n" , userinfo.username ); printf( "userinfo.password[%s]\n" , userinfo.password ); printf( "userinfo.regdate[%s]\n" , userinfo.regdate ); printf( "userinfo.logindate[%s]\n" , userinfo.logindate ); printf( "userinfo.extinfo.age[%d]\n" , userinfo.extinfo.age ); printf( "userinfo.extinfo.income[%lf]\n" , userinfo.extinfo.income ); printf( "userinfo.extinfo.marriage[%s]\n" , userinfo.extinfo.marriage ); return 0; } 编译链接执行,显示: userinfo.username[calvin.xml2c@gmail.com] userinfo.password[123456] userinfo.regdate[2009-01-01] userinfo.logindate[2009-07-13] userinfo.extinfo.age[30] userinfo.extinfo.income[160000.000000] userinfo.extinfo.marriage[FALSE] Well done , that’s all ~ 总结一下流程:首先编写或者改造现有的XML文件为定义文件,用工具xml2c处理生成c结构定义和格式转换函数,在你的应用代码中声明结构变量,调用自动生成的函数们做结构变量和XML文件或缓冲区格式相互转化。 对于变长字符串类型映射成c语言字符指针,重复相同层次结构的XML子树映射成c结构数组。 您老感觉如何?如果吓着您了,就当浪费您时间不用往下看了,如果您眼光变绿口水直淌——欢迎进入第二章^_^ 2.使用教程 2.1.编写xmd定义文件 xmd文件就是一个普通的XML文件,原有层次结构保持不变,只不过数据部分用类型描述替代,比如把“<age>30</age>” 替代成“<age>int</age>”,把“<username>calvin.xml2c@gmail.com</username>”替代成“<username>char64</username>”,完整的类型描述参见附录II。 目前版本xml2c支持变长字符串类型和重复XML相同层次结构,前者映射成c语言字符指针,由XML读函数内部在堆中alloc内存空间,后者映射成定长或变长结构数组,声明_count变量和_size变量跟踪该结构数组的大小。一个典型的案例如下: <?xml version="1.0" encoding="GBK"?> <tree> <branch11>char64</branch11> <branch12>char*</branch12> <branch21> <leaf211>short</leaf211> <leaf212>int</leaf212> <branch213> <leaf2131>long</leaf2131> </branch213> </branch21> <branch22 iterative="2"> <leaf221>double</leaf221> </branch22> <branch23 iterative="*"> <leaf231>datetime</leaf231> </branch23> </tree> 这里要注意的是如果你的xmd有XML头(“<?xml version="1.0" encoding="GBK"?>”),工具xml2c会提取出编码代码影响后面生成的所有源代码。 xmd定义文件最原始的来源渠道就是手工写,有些人喜欢用XML编辑器,比如XMLSpy(目前本人还没下载到完美破解的版本),有些人习惯干净,喜欢用记事本或者UltraEdit书写,更多的懒人则喜欢直接把XML文件拿来,把数据部分改成类型描述即可。 2.2.用xml2c处理后生成的源代码文件 定义好了xmd文件后,把xml2c拿出来处理一下它,如果你是一个严谨仔细的人,那么在标准输出最后一行出现的应该是“ok!\n”,如果没有出现,一定是哪里出现了错误,返回修改你的xmd直到pass为止。(推荐xmd文件命名规则为“XML_xxxxxx.xmd”,其中xxxxxx你可以自由命名) 你所在的目录里出现了很多c语言源代码文件,假如用的是1.3.的xmd文件,应该生成如下源代码文件: --- XML_test.XMLSTRUCT.h --------- #ifndef _H_XML_test_XMLSTRUCT_ #define _H_XML_test_XMLSTRUCT_ #include "libxml2c.h" struct XML_userinfo { char username[ 64 + 1 ] ; char password[ 8 + 1 ] ; char regdate[ 10 + 1 ] ; char logindate[ 10 + 1 ] ; struct _extinfo { int age ; double income ; char marriage[ 5 + 1 ] ; } extinfo ; } ; int XMLDUMPBUFFER_userinfo( struct XML_userinfo *pst , char *pbuffer , int *pbuflen ); int XMLDUMPFILE_userinfo( struct XML_userinfo *pst , char *xmlfilename ); int XMLPARSEBUFFER_userinfo( char *pbuffer , int *pbuflen , struct XML_userinfo *pst ); int XMLPARSEFILE_userinfo( char *xmlfilename , struct XML_userinfo *pst ); int XMLTRIM_userinfo( struct XML_userinfo *pst ); int XMLFREE_userinfo( struct XML_userinfo *pst ); #endif 头文件里包含对应c结构定义,以及其它几个.c文件里实现的函数原型。 函数XMLDUMPBUFFER_userinfo和XMLDUMPFILE_userinfo用于导出c结构变量数据到你申请好的缓冲区或外部XML文件,函数实现自动生成放在XML_test.XMLDUMP.c。 --- XML_test.XMLDUMP.c --------- #include "libxml2c.h" #include "XML_test.XMLSTRUCT.h" int XMLDUMP_userinfo( struct XML_userinfo *pst , xmlDoc *pXmlDoc , xmlNode **ppXmlNode ) {...} int XMLDUMPBUFFER_userinfo( struct XML_userinfo *pst , char *pbuffer , int *pbuflen ) {...} int XMLDUMPFILE_userinfo( struct XML_userinfo *pst , char *xmlfilename ) {...} 函数XMLPARSEBUFFER_userinfo和XMLPARSEFILE_userinfo用于读入缓冲区或外部XML文件映射成c结构数据,函数实现自动生成放在XML_test.XMLPARSE.c。 --- XML_test.XMLPARSE.c --------- #include "libxml2c.h" #include "XML_test.XMLSTRUCT.h" int XMLPARSE_userinfo( xmlDoc *pXmlDoc , xmlNode **ppXmlNode , struct XML_userinfo *pst ) {...} int XMLPARSEBUFFER_userinfo( char *pbuffer , int *pbuflen , struct XML_userinfo *pst ) {...} int XMLPARSEFILE_userinfo( char *xmlfilename , struct XML_userinfo *pst ) {...} 函数XMLTRIM_userinfo用于裁剪元数据类型为字符串的右边白字符,函数实现自动生成放在XML_test.XMLTRIM.c。 --- XML_test.XMLTRIM.c --------- #include "libxml2c.h" #include "XML_test.XMLSTRUCT.h" int XMLTRIM_userinfo( struct XML_userinfo *pst ) {...} 函数XMLFREE_userinfo用于释放变长字符串和变长结构数组在堆上申请的内存空间,函数实现自动生成放在XML_test.XMLFREE.c。 --- XML_test.XMLFREE.c --------- #include "libxml2c.h" #include "XML_test.XMLSTRUCT.h" int XMLFREE_userinfo( struct XML_userinfo *pst ) {...} 2.3.嵌入你的应用代码 有了所有素材,你的应用代码编码变得简单。 用前面生成的头文件里的结构体定义声明结构变量,也就是XML层次数据对应的结构,并用memset把它洗干净了。 如果从缓冲区里读进来,用前面自动生成的函数,原型为: int XMLPARSEBUFFER_userinfo( char *pbuffer , int *pbuflen , struct XML_userinfo *pst ); char *pbuffer和int *pbuflen为缓冲区首地址和有效长度,struct XML_userinfo *pst为数据映射到的c结构变量。 如果从XML文件里读进来,用前面自动生成的函数,原型为: int XMLPARSEFILE_userinfo( char *xmlfilename , struct XML_userinfo *pst ); char *xmlfilename为外部XML文件名,struct XML_userinfo *pst为数据映射到的c结构变量。 如果写到缓冲区里去,用前面自动生成的函数,原型为: int XMLDUMPBUFFER_userinfo( struct XML_userinfo *pst , char *pbuffer , int *pbuflen ); struct XML_userinfo *pst为数据源c结构变量,char *pbuffer和int *pbuflen为目标存放缓冲区首地址和缓冲区size。 如果写到XML文件里,用前面自动生成的函数,原型为: int XMLDUMPFILE_userinfo( struct XML_userinfo *pst , char *xmlfilename ); struct XML_userinfo *pst为数据源c结构变量,char *xmlfilename为要保存的外部XML文件名。 编译链接你的应用代码,看看最终效果,并爱上她。 3.附录 I.关于作者和本文 作者目前供职于某城市商业银行,崇尚创意,工作之余搞点儿研究自得其乐,在银行系统架构、基于FastCGI的现代CGI平台、源代码自动化理论、跨平台函数库等都有较深的研究和实现,并著有三部散文诗集供退休后赏玩。此外还是狂热级休闲wow玩家,国际惯例:二区(月神殿)Maua,一区(铜龙军团)暗影战刃。 你可以通过电子邮箱calvin.xml2c@gmail.com联系我,欢迎和我交流探讨共同提高^_^ (本工具目前为试验版本,因本工具造成的一切后果由使用者自负) 以上这句话有点儿吓人,呵呵呵^_^ II.xmd中已实现的数据类型描述 XML元数据类型(xmd内表达) c语言结构成员变量类型 类型描述 short short 短整型 int int 整型 long long 长整型 float float 浮点型 double double 双浮点型 char?? char[ ?? + 1 ] 定长字符串型 char* char* 变长字符串型① date char[ 10 + 1 ] 日期 time char[ 9 + 1 ] 时间 datetime char[ 19 + 1 ] 日期时间 money double 金额② BOOL BOOL 布尔值② YESNO YESNO 是非值② ONOFF ONOFF 开关值② 定个数XML子树结构 struct { } XXXXXX[ ?? ] ; 结构数组① 不定个数XML子树结构 struct { } *XXXXXX ; long XXXXXX_count ; long XXXXXX_size ; 结构数组指针① ①: PARSE系列函数自动调用alloc在堆上创建空间,DUMP列表函数则需要用户自己负责分配好空间并赋值_count和_size变量;应用处理完需要用户显式调用FREE系列函数释放空间。 ②:待实现数据类型。 ------------------------------------------------------ 下载包地址 : http://bbs3.chinaunix.net/thread-1506492-1-2.html
|