cJSON 的使用方法 JSON 格式简述
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。(来自“开源中国”资料)。
cJSON从名字可知,整个项目都是以极标准的C来写的,意思说,可以跨各种平台使用了。cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。
cJSON 开源项目位置:DaveGamble/cJSON 更加详细的解释和示例请查看主页 。
cJSON,目前来说,就只有两个文件,一个cJSON.c 一个cJSON.h文件。使用的时候,自己创建好一个main.c文件后,将头文件include进去。 如果是在linux pc上,请使用以下命令进行编译:
记得编译时末尾链接libm库。
JSON 结构体 熟悉使用cJSON库函数可从cJSON结构体入手,cJSON结构体如下所示:
1 2 3 4 5 6 7 8 9 typedef struct cJSON { struct cJSON *next ,*prev ; struct cJSON *child ; int type; char *valuestring; int valueint; double valuedouble; char *string ; } cJSON;
几点说明
cJOSN结构体为一个双向列表,并可通过child指针访问下一层。
type变量决定数据项类型(键的类型),数据项可以是字符串可以是整形,也可以是浮点型。如果是整形值的话可从valueint,如果是浮点型的话可从valuedouble取出,以此类推。
string可理解为节点的名称,综合此处的第2点可理解为“键”的名称。
cJSON作为Json格式的解析库,其主要功能无非就是构建和解析Json格式了,用途就是一端将要发送的数据已cjson形式封装,然后发送,另一端收到此数据后,还是按cjson形式解析,就得到想要的数据了。
封装 接下来直接通过几个例子代码,一一解析。
第一,创建json数据串。这数据串,可能是对象,也可能是数组,也可能是它们的各种组合,其中再加上一些键值对。有一点要先说明:它们的组合,符合父子继承格式--这也是json数据串的特点。
<1> 创建一个对象,并向这个对象里添加字符串和整型键值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> #include <stdlib.h> #include <string.h> #include "cJSON.h" int main () { cJSON * usr; cJSON *arry; usr=cJSON_CreateObject(); cJSON_AddStringToObject(usr,"name" ,"fengxin" ); cJSON_AddStringToObject(usr,"passwd" ,"123" ); cJSON_AddNumberToObject(usr,"num" ,1 ); char *out = cJSON_Print(usr); printf ("%s\n" ,out); cJSON_Delete(usr); free (out); }
运行结果:
1 2 3 4 5 { "name": "fengxin", "passwd": "123", "num": 1 }
若干说明
cJSON_CreateObject函数可创建一个根数据项,之后便可向该根数据项中添加string或int等内容,返回的是一个 cJSON的指针,注意,在这个指针用完了以后,需要手工调用 cJSON_Delete(root); 进行内存回收。
cJSON_AddNumberToObject向节点中添加子节点,例如此处添加name节点,节点值为字符串”fengxin”
需要注意的是 json 格式的数据,虽然也是一个字符串的样子,但这个时候还是无法当成普通的字符串进行使用,需要调用 cJSON_PrintUnformatted(root) 或者 cJSON_Print(root);来将json对象转换成普通的字符串,并且都是以该json对象的根为基点。两个API的区别即是:一个是没有格式的:也就是转换出的字符串中间不会有”\n” “\t”之类的东西存在,而cJSON_Print(root);打印出来是人看起来很舒服的格式。
因为函数内部封装有malloc函数,所以使用free函数释放被out占用的内存空间
<2> 创建一个数组,并向数组添加一个字符串和一个数字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int create_js (void ) { cJSON *root, *js_body; root = cJSON_CreateArray(); cJSON_AddItemToArray(root, cJSON_CreateString("Hello world" )); cJSON_AddItemToArray(root, cJSON_CreateNumber(10 )); { char *s = cJSON_PrintUnformatted(root); if (s){ printf (" %s \n" ,s); free (s); } } if (root) cJSON_Delete(root); return 0 ; } int main (int argc, char **argv) { create_js(); return 0 ; }
运行结果:
<3> 对象里面包括一个数组,数组里面包括对象,对象里面再添加一个字符串和一个数字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int create_js (void ) { cJSON *root, *js_body, *js_list; root = cJSON_CreateObject(); cJSON_AddItemToObject(root,"body" , js_body = cJSON_CreateArray()); cJSON_AddItemToArray(js_body, js_list = cJSON_CreateObject()); cJSON_AddStringToObject(js_list,"name" ,"fengxin" ); cJSON_AddNumberToObject(js_list,"status" ,100 ); { char *s = cJSON_PrintUnformatted(root); if (s){ printf (" %s \n" ,s); free (s); } } if (root) cJSON_Delete(root); return 0 ; } int main (int argc, char **argv) { create_js(); return 0 ; }
运行结果:
1 {"body":[{"name":"fengxin","status":100}]}
<4> 其他组合就依次类推,只要搞清楚父子关系即可。随便嵌套随便玩。不再贴了。
解析 解析数据包的过程和组装数据包的过程相反
处理流程:
<1> 先将普通的json串处理成json对象,也就是所谓的创建json root的过程,只有一行代码即可:
1 2 cJSON *root; root = cJSON_Parse(js_string);
<2> 开始拿关键字,但如果关键字还有父层或者祖层,那就需要先从父层开拿,所谓剥洋葱是也!先说没有父层的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 out={\"name\":\"fengxin\",\"passwd\":\"123\",\"num\":1} #include<stdio.h> #include<stdlib.h> #include<string.h> #include" cJSON.h" int main() { cJSON *json,*json_name,*json_passwd,*json_num; char* out=" {\"name\":\"fengxin\",\"passwd\":\"123\",\"num\":1}" ; json = cJSON_Parse(out); json_name = cJSON_GetObjectItem( json , "name" ); json_passwd = cJSON_GetObjectItem( json , "passwd" ); json_num = cJSON_GetObjectItem( json , "num" ); printf ("name:%s,passwd:%s,num:%d\n" ,json_name->valuestring,json_passwd->valuestring,json_num->valueint); cJSON_Delete(json); free (out); }
显示结果:
1 name:fengxin,passwd:123,num:1
需要注意的是: 上面的type 已经在cJSON.h里面定义好了,有自己的意义。如果是在严格的场所,应该先判定该 item的type,然后再考虑去拿值。而如果有父层的话,无非就是接着向下拿就是了。
<3> 处理这串数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 out={\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}} char *s = " {\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}" ;cJSON *root = cJSON_Parse(s); if (!root) { printf ("get root faild !\n" ); return -1 ; } cJSON *js_list = cJSON_GetObjectItem(root, "list" ); if (!js_list) { printf ("no list!\n" ); return -1 ; } printf ("list type is %d\n" ,js_list->type);cJSON *name = cJSON_GetObjectItem(js_list, "name" ); if (!name) { printf ("No name !\n" ); return -1 ; } printf ("name type is %d\n" ,name->type);printf ("name is %s\n" ,name->valuestring);cJSON *age = cJSON_GetObjectItem(js_list, "age" ); if (!age) { printf ("no age!\n" ); return -1 ; } printf ("age type is %d\n" , age->type);printf ("age is %d\n" ,age->valueint);cJSON *js_other = cJSON_GetObjectItem(root, "other" ); if (!js_other) { printf ("no list!\n" ); return -1 ; } printf ("list type is %d\n" ,js_other->type);cJSON *js_name = cJSON_GetObjectItem(js_other, "name" ); if (!js_name) { printf ("No name !\n" ); return -1 ; } printf ("name type is %d\n" ,js_name->type);printf ("name is %s\n" ,js_name->valuestring);if (root) { cJSON_Delete(root); return 0 ; }
打印结果:
1 2 3 4 5 6 7 8 list type is 6 name type is 4 name is xiao hong age type is 3 age is 10 list type is 6 name type is 4 name is hua hua
所谓子子孙孙无穷尽也,按照上面那个方法推下去即可。
<4> json里数组怎么取?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 {\"list\":[\"name1\",\"name2\"]} int main(int argc, char **argv) { char *s = " {\"list\":[\"name1\",\"name2\"]}" ;cJSON *root = cJSON_Parse(s); if (!root) { printf ("get root faild !\n" ); return -1 ; } cJSON *js_list = cJSON_GetObjectItem(root, "list" ); if (!js_list){ printf ("no list!\n" ); return -1 ; } int array_size = cJSON_GetArraySize(js_list);printf ("array size is %d\n" ,array_size);int i = 0 ;cJSON *item; for (i=0 ; i< array_size; i++) { item = cJSON_GetArrayItem(js_list, i); printf ("item type is %d\n" ,item->type); printf ("%s\n" ,item->valuestring); } if (root) cJSON_Delete(root); return 0 ; }
<5> 如果json数组里面又搞了对象怎么办?
不怕搞对象,就怕这样搞对象? 无他,就是稍微复杂了一点,全是体力活儿:
既然是数组里面,那肯定要先测量数组的大小,然后根据大小循环拿;
拿到一个数组项,然后把这个项先转化成普通的json字符串,也就是 char *s 能接受的。
再次将这个json字符串,转化成一个json对象。
按照拿普通对象中的东西那样开干就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 {\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]} list 是一个数组,数组里面有两个对象,那么代码如下 int main(int argc, char **argv) { char *s = " {\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}" ;cJSON *root = cJSON_Parse(s); if (!root) { printf ("get root faild !\n" ); return -1 ; } cJSON *js_list = cJSON_GetObjectItem(root, "list" ); if (!js_list){ printf ("no list!\n" ); return -1 ; } int array_size = cJSON_GetArraySize(js_list);printf ("array size is %d\n" ,array_size);int i = 0 ;cJSON *item,*it, *js_name, *js_age; char *p = NULL ;for (i=0 ; i< array_size; i++) { item = cJSON_GetArrayItem(js_list, i); if (!item) { } p = cJSON_PrintUnformatted(item); it = cJSON_Parse(p); if (!it) continue ; js_name = cJSON_GetObjectItem(it, "name" ); printf ("name is %s\n" ,js_name->valuestring); js_age = cJSON_GetObjectItem(it, "age" ); printf ("age is %d\n" ,js_age->valueint); } if (root) cJSON_Delete(root); return 0 ; }