免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
1234下一页
最近访问板块 发新帖
查看: 18712 | 回复: 36
打印 上一主题 下一主题

[C] SPDataPickle: C语言的结构体和 xml/json/protobuf 的自动转化(移植到 win32 平台) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-01-22 23:06 |只看该作者 |倒序浏览
SPDataPickle 是一个用于在 C语言的结构体和 xml/json 之间做自动转化的库。

http://code.google.com/p/spdatapickle
http://spdatapickle.googlecode.c ... ckle-0.5.src.tar.gz

大家可能对 google 的 protocol buffers 都早有耳闻。SPDataPickle 和 protobuf 很相似。

仿照 google protobuf 的例子,也来一个 Person 的简单例子。

对应 a.proto ,要写一个 a.xml

  1. <metainfo prefix="XYZ" filename="account">
  2.     <struct name="Person">
  3.         <field name="id"    type="int32" />
  4.         <field name="name"  type="*char" />
  5.         <field name="email" type="*char" />
  6.     </struct>
  7. </metainfo>
复制代码


然后使用 spxml2struct 处理这个 a.xml,生成具体的 structure 定义和 metainfo 。

  1. enum {
  2.     eTypeXYZPerson = eTypeSPDPUserDefine + 1
  3. };

  4. typedef struct tagXYZPerson {
  5.     int mId;
  6.     char * mName;
  7.     char * mEmail;
  8. } XYZPerson_t;

  9. typedef struct tagSP_DPMetaInfo SP_DPMetaInfo_t;
  10. extern SP_DPMetaInfo_t * gXYZAccountMetaInfo;
复制代码


然后就可以对这个 XYZPerson_t 结构进行序列化和反序列化。

  1. int main( int argc, char * argv[] )
  2. {
  3.     XYZPerson_t person;

  4.     person.mId = 123;
  5.     person.mName = strdup( "Bob" );
  6.     person.mEmail = strdup( "bob@example.com" );

  7.     SP_XmlStringBuffer buffer;

  8.     SP_XmlPickle pickle( gXYZAccountMetaInfo );
  9.     pickle.pickle( &person, sizeof( person ), eTypeXYZPerson, &buffer );

  10.     printf( "xml: %s\n", buffer.getBuffer() );

  11.     XYZPerson_t other;
  12.     pickle.unpickle( buffer.getBuffer(), buffer.getSize(), eTypeXYZPerson, &other, sizeof( other ) );

  13.     printf( "id %d, name %s, email %s\n", other.mId, other.mName, other.mEmail );

  14.     SP_DPAlloc alloc( gXYZAccountMetaInfo );

  15.     alloc.free( &person, sizeof( person ), eTypeXYZPerson );
  16.     alloc.free( &other, sizeof( person ), eTypeXYZPerson );

  17.     return 0;
  18. }
复制代码


输出结果

  1. xml: <Person>
  2. <id>123</id>
  3. <name>Bob</name>
  4. <email>bob@example.com</email>
  5. </Person>

  6. id 123, name Bob, email [email]bob@example.com[/email]
复制代码

[ 本帖最后由 iunknown 于 2009-11-6 23:14 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-08-02 18:06 |只看该作者
发布 0.2 版本,新增特性
1.增加了对 json 的支持
2.xml pickle 和 json pickle 用一个统一的接口,方便使用
3.在 metainfo 中支持指定某个字段是可选的,在解包的时候,如果对应的字段不存在,直接跳过

http://spdatapickle.googlecode.c ... ckle-0.2.src.tar.gz


  1. <metainfo prefix="XYZ" filename="addrbook">
  2.     <struct name="Email">
  3.         <field name="Type"    type="char" arraysize="10" />
  4.         <field name="Address" type="*char" />
  5.         <field name="Nickname" type="*char" required="0" />
  6.     </struct>
  7. </metainfo>
复制代码


  1. void testEmail( SP_DataPickle * pickle )
  2. {
  3.     XYZEmail_t email;
  4.     memset( &email, 0, sizeof( email ) );

  5.     strncpy( email.mType, "work", sizeof( email.mType ) - 1 );
  6.     email.mAddress = strdup( "foo <[email]foo@bar.com[/email]>" );

  7.     SP_XmlStringBuffer buffer;

  8.     pickle->pickle( &email, sizeof( email ), eTypeXYZEmail, &buffer );

  9.     printf( "%s\n\n", buffer.getBuffer() );

  10.     SP_DPAlloc alloc( gXYZAddrbookMetaInfo );
  11.     alloc.free( &email, sizeof( email ), eTypeXYZEmail );
  12. }
复制代码


序列化的结果

  1. {
  2.         "Email" : {
  3.                 "Type" : "work",
  4.                 "Address" : "foo <[email]foo@bar.com[/email]>"
  5.         }
  6. }
复制代码

[ 本帖最后由 iunknown 于 2009-8-2 18:09 编辑 ]

论坛徽章:
1
寅虎
日期:2014-11-30 21:25:54
3 [报告]
发表于 2009-08-02 18:32 |只看该作者
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?

论坛徽章:
0
4 [报告]
发表于 2009-08-02 21:20 |只看该作者
原帖由 vbs100 于 2009-8-2 18:32 发表
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?


如果整个系统都是用 C/C++ 的话,那么直接用二进制协议就非常方便。

但事情有另外的一面。这个问题其实相当于是在问 xml和json 存在的理由。
关于这一点,可以看看 xmlrpc 列举的理由:

http://www.xmlrpc.com/spec

Strategies/Goals

Firewalls. The goal of this protocol is to lay a compatible foundation across different environments, no new power is provided beyond the capabilities of the CGI interface. Firewall software can watch for POSTs whose Content-Type is text/xml.

Discoverability. We wanted a clean, extensible format that's very simple. It should be possible for an HTML coder to be able to look at a file containing an XML-RPC procedure call, understand what it's doing, and be able to modify it and have it work on the first or second try.

Easy to implement. We also wanted it to be an easy to implement protocol that could quickly be adapted to run in other environments or on other operating systems.

论坛徽章:
1
寅虎
日期:2014-11-30 21:25:54
5 [报告]
发表于 2009-08-03 08:59 |只看该作者

回复 #4 iunknown 的帖子

存在即合理吧 学习了 可能以后工作上也会遇到

论坛徽章:
0
6 [报告]
发表于 2009-10-07 22:31 |只看该作者

发布 0.3 版本

发布 0.3 版本,新增特性
1.增加了对 ProtoBuf wire format 的支持

http://spdatapickle.googlecode.c ... ckle-0.3.src.tar.gz

这个功能没有使用 google 的代码,而是重新实现了 wire format 的编码解码器。
http://iunknown.javaeye.com/blog/482683

这个实现,比起 google 的更轻量。google 的 protobuf 代码量太大了。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
7 [报告]
发表于 2009-10-10 16:05 |只看该作者
原帖由 vbs100 于 2009-8-2 18:32 发表
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?

在网络上,各种不同系统,二进制不方便。
实际上是用模板映射结构,要很仔细保持模板和结构的关系。
使用xml格式做模板效率较低,在C语言里我更喜欢用结构做模板,其他语言可以用xml。

我也搞了一个JSON的,可以支持SQL和JSON之间的映射。
那里起先叫DTO,后来改称DAU(DATA Access Unit)

数据模板从数据库生成,结构根据模板分配。

DAU_init(DAU,SQL_Connect,tablename,0,0);//后边两个参数=0,要求数据库以表名生成模板和结构,否则,一个是结构,一个是模板。
DAU里包含了数据库连接句柄,表名,结构,模板,还有其他资源。

sprintf(where,"WHERE .....",,,,);
DAU_select(DAU,where,0);//以where里的条件从数据库读。语句是内部生成的(也使用模板)。
DAU_next(DAU);//从结果集中提取1行倒结构;
json=json_object_new_object(); //生成一个空JSON

DAU_toJSON(DAU,json,0);//结构内容进入JSON对象
char *p=json_object_to_json_string(json);//JSON变字符串;这个字符串可以输出了;
。。。。。

下贴1楼是过程,2楼是结果,以后是关于功能和性能的讨论:
http://www.itpub.net/thread-1088197-1-1.html

还没有做XML的,感觉包太大,处理效率较低,在OLTP里不合适。

DAU系统完成 结构-关系映射(有点像JAVA的ORM),结构的序列化是其中一部分内容。所以它的模板比较复杂,完成的功能超过了序列化要求。
看来你的工作与我有类似之处,特来探讨一下。
你也可以考虑模板自动生成的问题,可以依赖数据库进行。

我没有采取XML或JSON定义模板,主要是感觉在一个大型事务系统里,要附带一大堆XML文件挺累赘的,何况这些文件在运行时环境里,万一被改动,程序就死掉不明不白。
我的模板是在编译环境里,运行时看不见。所以安全一些。

上边帖子很长,后边有模板的样式。

[ 本帖最后由 yulihua49 于 2009-10-10 16:49 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2009-10-10 16:14 |只看该作者
序列化是个说大就大,说小就小的问题,和兼容性,异构度有关,好像json比较受吹捧

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
9 [报告]
发表于 2009-10-10 16:50 |只看该作者
原帖由 sbc19861004 于 2009-10-10 16:14 发表
序列化是个说大就大,说小就小的问题,和兼容性,异构度有关,好像json比较受吹捧

json比较轻便,效率也好。我们现在通信协议就用JSON。
比JSON在精简就是传统字符串和分隔符了,双方用同样用模板也可以解析复杂的字符串结构。
字符串还有保密作用,没有模板你很难看懂数据的含义。

[ 本帖最后由 yulihua49 于 2009-10-10 16:54 编辑 ]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
10 [报告]
发表于 2009-10-10 16:58 |只看该作者
原帖由 vbs100 于 2009-8-2 18:32 发表
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?

二进制不方便调试。
流行的 internet 协议几乎全是文本的,
HTTP FTP SMTP POP
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP