sax-json是一个sax2风格的JSON解析器。它读取JSON文档并根据在文档中遇到的特定符号生成事件,它不会在内存中为文档创建树结构,相反,它按顺序处理文档的内容并在读取文档时生成事件。 比如针对下面的JSON实例:
{
"meeting_info":
{
"meeting_id": 123,
"meeting_title": "meeting"
}
}
在解析时,sax-json会依次触发以下事件:
和xml sax解析器一样,开发者需要实现处理这些事件的处理函数来完成解析后处理功能。
sax-json采用标准c语言编写,支持windows、linux、mac。要使用sax-json,只需要将源码下载并添加到项目中即可。
在使用sax-json时,有两种方式可供选择:
JSON解析功能是在json/JsonParser代码中完成的,如果开发者只想使用JSON解析功能,可以只添加json/JsonParser及其依赖文件到项目中。事实上json/JsonParser来自我的另一个项目CBase。
直接使用JSON解析功能,是需要开发者自己实现解析器抛出的onStartElement及onEndElement事件的,相比较使用封装好的json/JsonLoader会麻烦一点。
comm/ErrorCode.h
comm/BaseFuncDef.h
json/JsonParser.h
json/JsonParser.c
onStartElement: json中子字段开始事件处理函数
onEndElement: json中子字段结束事件处理函数
onParseError: json解析出错事件处理函数
parse_json_string: 解析JSON字符串
parse_json_file: 解析JSON文件
使用json/JsonLoader可以将JSON字符串或JSON文件解析成c结构对象。在解析过程中,JsonLoader需要c结构对象与JSON对象之间的对应关系,这个对应关系可以使用pp描述文件(类似Protocol Buffer)来定义,之后使用tools/CMessage-Creator/generator.py工具,将pp描述文件转成c语言文件。转换后的c文件也需要添加到项目中一起编译使用。
具体步骤如下:
<结构体名>_from_json: 解析JSON字符串,填充c结构体
<结构体名>_from_file: 解析JSON文件,填充c结构体
<结构体名>_to_json: c结构体对象转成json字符串
可以参考example目录下的例子:
pp描述文件可以定义c结构体与JSON对象之间的对应关系。在pp文件中可以定义常量(c 宏定义)、枚举(c enum)、结构体(c struct)、联合体(c union)。
使用struct关键字定义结构体,其语法格式和c语言定义结构体的语法格式类似,见下面的例子:
// 会议信息
struct MeetingInfo {
string MeetingID[MAX_MEETING_ID_LEN]; `json:"meeting_id"` // 会议ID
uint8 MeetingType; `json:"meeting_type"` // 会议类型
uint8 MeetingState; `json:"meeting_state"`// 会议状态
int64 BeginTM; `json:"begin_tm"` // 会议开始时间
uint8 ChatterNumber; `json:"chatter_number"`// 语音会议中聊天人数量
uint64 Chatters[MAX_CHATTER_NUMBER] => ChatterNumber; `json:"chatters"` // 语音会议中聊天者UID
};
它定义了一个名为MeetingInfo的结构体,包含6个字段:
此外:
json:"JSON名"
来指定,比如本例中,字段MeetingID的JSON名称是meeting_id。若不指定json名,则字段本名将作为字段的JSON名。类型 | 类型说明 |
---|---|
uint8 | 无符号整数,C语言中占1个字节,JSON中对应Number |
int8 | 有符号整数,C语言中占1个字节,JSON中对应Number |
uint16 | 无符号整数,C语言中占2个字节,JSON中对应Number |
int16 | 有符号整数,C语言中占2个字节,JSON中对应Number |
uint32 | 无符号整数,C语言中占4个字节,JSON中对应Number |
int32 | 有符号整数,C语言中占4个字节,JSON中对应Number |
uint64 | 无符号整数,C语言中占8个字节,JSON中会自动转换成string |
int64 | 有符号整数,C语言中占8个字节,JSON中会自动转换成string |
string | 字符串类型,定义字符串字段时需要指定最大长度 |
使用tools/CMesage-Creator/generator.py工具,将pp定义的结构体MeetingInfo转换的c代码如下:
/**
* 会议信息
*/
struct MeetingInfo
{
char szMeetingID[MAX_MEETING_ID_LEN]; /* 会议ID */
uint8_t chMeetingType; /* 会议类型 */
uint8_t chMeetingState; /* 会议状态 */
int64_t llBeginTM; /* 会议开始时间 */
uint8_t chChatterNumber; /* 语音会议中聊天人数量 */
uint64_t astChatters[MAX_CHATTER_NUMBER]; /* 语音会议中聊天者UID */
};
定义结构体时,使用其他结构体定义子字段,可以实现结构体嵌套定义,如下例使用结构体MeetingInfo定义了一个结构体数组字段:
// 会议列表
struct MeetingList {
uint32 MeetingNumber; `json:"meeting_number"` // 列表中会议数量
MeetingInfo MeetingInfos[MAX_MEETING_NUMBER] => MeetingNumber `json:"meeting_infos"` // 列表中会议信息
};
联合体在c语言中可以节省内存,虽然JSON没有联合体,但是在c语言中可以使用联合体。
在pp中,使用union关键字定义联合,其语法格式和c语言定义联合的语法格式类似,见下面的例子:
// 会议信息
union MeetingData {
MeetingList MeetingList; `json:"meeting_list" tag:"MEETING_DATA_TYPE_LIST"` // 会议列表
MeetingInfo MeetingInfo; `json:"meeting_info" tag:"MEETING_DATA_TYPE_INFO"` // 会议信息
};
注意,定义联合时,联合的子字段,必须使用tag标签指定联合的选择的值,上例中:
联合体MeetingData转换成c代码如下:
/**
* 会议信息
*/
struct MeetingData
{
uint16_t nSelector;
union
{
MEETINGLIST stMeetingList; /* 会议列表 */
MEETINGINFO stMeetingInfo; /* 会议信息 */
};
};
可见,转换后,MeetingData被自动加上了nSelector字段,它是联合的选择器,当nSelector=MEETING_DATA_TYPE_LIST时,字段stMeetingList有效;当nSelector=MEETING_DATA_TYPE_INFO时,字段stMeetingInfo有效
使用关键字const定义常量:
// 宏定义
const MAX_MEETING_ID_LEN = 128; // 最大会议ID长度
const MAX_MEETING_NUMBER = 128; // 会议列表中最大会议数量
const MAX_CHATTER_NUMBER = 8; // 语音会议中最大聊天人数量
使用关键字enum定义枚举:
// 会议类型
enum MeetingType {
MEETING_TYPE_NORMAL = 0, // 普通会员
MEETING_TYPE_AUDIO = 1, // 语音会议
MEETING_TYPE_VIDEO = 2, // 视频会议
};
在pp文件中,可以使用module关键字定义模块,将pp中定义的常量、枚举、结构体、联合都归类于这个模块中。参考meeting.pp中module的定义:
module meeting {
// 宏定义
const MAX_MEETING_ID_LEN = 128; // 最大会议ID长度
// 其他 ...
};
由于c语言不支持namespace概念,所以这里module的定义是可选的。
代码生成器位于tools/CMessage-Creator目录,它是python编写的工具,不需要编译可以跨平台使用。它需要python2.4以上的环境
代码生成器的主程序是generator.py,执行python generator.py --help可以查看帮助。
Description: message generator.
Version: 1.0.0.0
Usage: python generator.py [-?] [-h] [-s DIRECTORY] [-d DIRECTORY] [-m FILE_NAME]
optional arguments:
-?, -h, --help Show this help information
-s DIRECTORY, --srcpath DIRECTORY
Set pp define file search directory
-d DIRECTORY, --directory DIRECTORY
Set generate project directory for project
-f FILE_NAME
Set generate file name
Example:
python generator.py --help
python generator.py -s . -d ../test
可选输入参数说明如下:
可选参数:
-?, -h, --help 显示本程序的帮助信息
-s DIRECTORY, --srcpath DIRECTORY
指定pp描述文件所在路径,注意路径中可以包含多个pp描述文件
-d DIRECTORY, --directory DIRECTORY
设置代码生成路径,该路径用来存放转换后的c语言文件
-f FILE_NAME
设置代码生成的c语言文件名称,若不指定,则使用pp描述文件中的module名
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。