CJSON编程使用,组装和解析json格式数据

来源:互联网 发布:linux c 开发环境 编辑:程序博客网 时间:2024/04/29 10:32

cJSON 开源项目位置: http://sourceforge.net/projects/cjson/

   cJSON,目前来说,就只有两个文件,一个cJSON.c 一个cJSON.h文件。使用的时候,自己创建好一个main.c文件后,如果是在linux pc上,请使用以下命令进行编译:

1 gcc -g -Wall *.c -l m
就会默认生成一个 a.out文件,执行即可。在linux下编译的时候,注意链接 libm 库。

   整个项目都是以极标准的C来写的,意思说,可以跨各种平台使用了。不过,还是有两三处需要微调一下<针对stm32f103  + rt_thread >。其中修改一下malloc & free & size_t 这三个东西:
static void *(*cJSON_malloc)(size_t sz) = malloc;static void (*cJSON_free)(void *ptr) = free;----------------------------------------static void *(*cJSON_malloc)(size_t sz) = rt_malloc;static void (*cJSON_free)(void *ptr) = rt_free; void cJSON_InitHooks(cJSON_Hooks* hooks) {     if (!hooks) { /* Reset hooks */         cJSON_malloc = malloc;         cJSON_free = free;         return;   }     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;     cJSON_free   = (hooks->free_fn)?hooks->free_fn:free; }---------------------------------------------------- void cJSON_InitHooks(cJSON_Hooks* hooks) {    if (!hooks) { /* Reset hooks */         cJSON_malloc = rt_malloc;        cJSON_free = rt_free;         return;     }      cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:rt_malloc;    cJSON_free   = (hooks->free_fn)?hooks->free_fn:rt_free;  }

复制代码
free & malloc就这么两个地方要修改一下吧,其中size_t 这个应该是在 .h 文件修改,主要是rtt的 rt_malloc 和这里的malloc使用的不同,所以修改了下---不一定非要修改。

所以,这东西说实话,也不存在什么移植不移植的问题了。很轻松的就可以在各个平台使用了。

                                                                                               例       程                                                                                                            不对json的格式进行说明了,下面直接记下使用方法了。  第一,创建json数据串。这数据串,可能是对象,也可能是数组,也可能是它们的各种组合,其中再加上一些键值对。有一点要先说明:它们的组合,符合父子继承格式--这也是json数据串的特点。 <1>  创建一个对象,并在这个对象里面添加一个字符串键值和一个数字键值:
 int create_js(void)  {      cJSON *root;      /*create json string root*/     root = cJSON_CreateObject();     if(!root) {         DEBUG("get root faild !\n");         goto EXIT;     }else DEBUG("get root success!\n");     {         cJSON * js_body ;         const char *const body = "body";         cJSON_AddItemToObject(root, body, js_body=cJSON_CreateObject());        cJSON_AddStringToObject(js_body,"name","xiaohui");        cJSON_AddNumberToObject(js_body,"value",600);        {         char *s = cJSON_PrintUnformatted(root);        if(s){            DEBUG("create js string is %s\n",s);             free(s);         }         }         cJSON_Delete(root);     }     return 0; EXIT:    return -1; } int main(int argc, char **argv) {     create_js();     return 0; }

运行结果:

1 create js string is {“body”:{“name”:”xiaohui”,”value”:600}}
说明: 创建根对象,使用 cJSON_CreateObject(); 这个API,返回的是一个 cJSON的指针,注意,在这个指针用完了以后,需要手工调用 cJSON_Delete(root); 进行内存回收。

创建body对象的时候,是在根对象的基础上进行创建,而插入name 和value的时候,是以body为父节点。需要注意的是 json 格式的数据,虽然也是一个字符串的样子,但这个时候还是无法当成普通的字符串进行使用,需要调用 cJSON_PrintUnformatted(root) 或者 cJSON_Print(root);来将json对象转换成普通的字符串,并且都是以该json对象的根为基点。两个API的区别即是:一个是没有格式的:也就是转换出的字符串中间不会有”\n” “\t”之类的东西存在,而cJSON_Print(root);打印出来是人看起来很舒服的格式。仅此而已。

<2> 创建一个数组,并向数组添加一个字符串和一个数字:

 1 int create_js(void) 2 { 3     cJSON *root, *js_body; 4     root = cJSON_CreateArray(); 5     cJSON_AddItemToArray(root, cJSON_CreateString("Hello world")); 6     cJSON_AddItemToArray(root, cJSON_CreateNumber(10));  7     { 8 //        char *s = cJSON_Print(root); 9         char *s = cJSON_PrintUnformatted(root);10         if(s){11             DEBUG(" %s \n",s);12             free(s);13         }14     }15     if(root)16     cJSON_Delete(root);17 18     return 0;19 EXIT:20     return -1;21 }22 23 int main(int argc, char **argv)24 {25     create_js();26     return 0;27 }

运行结果:

1 ["Hello world",10]

<3> 对象里面包括一个数组,数组里面包括对象,对象里面再添加一个字符串和一个数字:

 1 int create_js(void) 2 { 3     cJSON *root, *js_body, *js_list; 4     root = cJSON_CreateObject(); 5     cJSON_AddItemToObject(root,"body", js_body = cJSON_CreateArray()); 6     cJSON_AddItemToArray(js_body, js_list = cJSON_CreateObject()); 7     cJSON_AddStringToObject(js_list,"name","xiaohui"); 8     cJSON_AddNumberToObject(js_list,"status",100); 9 10     {11         //        char *s = cJSON_Print(root);12         char *s = cJSON_PrintUnformatted(root);13         if(s){14             DEBUG(" %s \n",s);15             free(s);16         }17     }18     if(root)19         cJSON_Delete(root);20 21     return 0;22 EXIT:23     return -1;24 }25 26 int main(int argc, char **argv)27 {28     create_js();29     return 0;30 }

运行结果:

1 {"body":[{"name":"xiaohui","status":100}]}

<4>其他组合就依次类推,只要搞清楚父子关系即可。随便嵌套随便玩。不再贴了。

<第二, 解析json数据串>

步骤: 1 先将普通的json 字符串 处理成 json对象格式。 2 根据关键字进行解析,解析的时候,需要根据关键字值的类型进行判断,而这些类型,已经在cJSON.h里面写明白了,包括:对象、数组、普通字符串、普通变量等等。

<偷个懒吧,将自己学习的时候用的资料现贴过来,后面休息一下再详细补充自己在工程中的解析方法>

http://blog.csdn.net/xukai871105/article/details/17094113http://blog.sina.com.cn/s/blog_a6fb6cc90101ffme.html

<当然,他写的比较简洁,还有些可以补充的---其实我已经在上面使用文字进行补充过了。当然,不同的工程,可能解析的方法和侧重点并不相同>

或许,是时候把解析的部分补充上来了:

处理流程:

1, 先将普通的json串处理成json对象,也就是所谓的创建json root的过程,只有一行代码即可:

cJSON *root;root = cJSON_Parse(js_string);

ps:需要注意的是,这个root在解析完成后,需要释放掉,代码如下:

if (root)  cJSON_Delete(root);

2,开始拿关键字,但如果关键字还有父层或者祖层,那就需要先从父层开拿,所谓剥洋葱是也!

先说没有父层的:

{“name”:”xiaohong”,”age”:10}
这个字符串这样拿即可:

 1 char *s = "{\"name\":\"xiao hong\",\"age\":10}"; 2 cJSON *root = cJSON_Parse(s); 3 if(!root) { 4     printf("get root faild !\n"); 5     return -1; 6 } 7 cJSON *name = cJSON_GetObjectItem(root, "name"); 8 if(!name) { 9     printf("No name !\n");10     return -1;11 }12 printf("name type is %d\n",name->type);13 printf("name is %s\n",name->valuestring);14 15 cJSON *age = cJSON_GetObjectItem(root, "age");16 if(!age) {17     printf("no age!\n");18     return -1;19 }20 printf("age type is %d\n", age->type);21 printf("age is %d\n",age->valueint);

显示结果:

1 name type is 4
2 name is xiao hong
3 age type is 3
4 age is 10

需要注意的是: 上面的type 已经在cJSON.h里面定义好了,有自己的意义。如果是在严格的场所,应该先判定该 item的type,然后再考虑去拿值。

而如果有父层的话,无非就是接着向下拿就是了,稍微修改下前面的demo吧:

处理这串数据吧:

{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}
 1 char *s = "{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}"; 2 cJSON *root = cJSON_Parse(s); 3 if(!root) { 4     printf("get root faild !\n"); 5     return -1; 6 } 7  8 cJSON *js_list = cJSON_GetObjectItem(root, "list"); 9 if(!js_list) {10     printf("no list!\n");11     return -1;12 }13 printf("list type is %d\n",js_list->type);14 15 cJSON *name = cJSON_GetObjectItem(js_list, "name");16 if(!name) {17     printf("No name !\n");18     return -1;19 }20 printf("name type is %d\n",name->type);21 printf("name is %s\n",name->valuestring);22 23 cJSON *age = cJSON_GetObjectItem(js_list, "age");24 if(!age) {25     printf("no age!\n");26     return -1;27 }28 printf("age type is %d\n", age->type);29 printf("age is %d\n",age->valueint);30 31 cJSON *js_other = cJSON_GetObjectItem(root, "other");32 if(!js_other) {33     printf("no list!\n");34     return -1;35 }36 printf("list type is %d\n",js_other->type);37 38 cJSON *js_name = cJSON_GetObjectItem(js_other, "name");39 if(!js_name) {40     printf("No name !\n");41     return -1;42 }43 printf("name type is %d\n",js_name->type);44 printf("name is %s\n",js_name->valuestring);45 46 if(root)47     cJSON_Delete(root);48     return 0;

打印结果:

1 list type is 62 name type is 43 name is xiao hong4 age type is 35 age is 106 list type is 67 name type is 48 name is hua hua

所谓子子孙孙无穷尽也,按照上面那个方法推下去即可。

3,json 里数组怎么取?

1 {\"list\":[\"name1\",\"name2\"]}代码如下:复制代码 1 int main(int argc, char **argv) 2 { 3 char *s = "{\"list\":[\"name1\",\"name2\"]}"; 4 cJSON *root = cJSON_Parse(s); 5 if(!root) { 6     printf("get root faild !\n"); 7     return -1; 8 } 9 cJSON *js_list = cJSON_GetObjectItem(root, "list");10 if(!js_list){11     printf("no list!\n");12     return -1;13 }14 int array_size = cJSON_GetArraySize(js_list);15 printf("array size is %d\n",array_size);16 int i = 0;17 cJSON *item;18 for(i=0; i< array_size; i++) {19     item = cJSON_GetArrayItem(js_list, i);20     printf("item type is %d\n",item->type);21     printf("%s\n",item->valuestring);22 }23 24 if(root)25     cJSON_Delete(root);26     return 0;27 }

对头,好简单的样子<在别人的库上使用>

4 如果json数组里面又搞了对象怎么办?

不怕搞对象,就怕这样搞对象? 无他,就是稍微复杂了一点,全是体力活儿:

<1> 既然是数组里面,那肯定要先测量数组的大小,然后根据大小循环拿;

<2> 拿到一个数组项,然后把这个项先转化成普通的json字符串,也就是 char *s 能接受的。

<3>再次将这个json字符串,转化成一个json对象

<4> 按照拿普通对象中的东西那样开干就行了。

ps:曾经试过直接在数组项中拿内容,失败了,不知为何,于是就按照这个4步开干了。

比如:

1 {\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}

是的.list 是一个数组,数组里面有两个对象,那么代码如下:

 1 int main(int argc, char **argv) 2 { 3 char *s = "{\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}"; 4 cJSON *root = cJSON_Parse(s); 5 if(!root) { 6     printf("get root faild !\n"); 7     return -1; 8 } 9 cJSON *js_list = cJSON_GetObjectItem(root, "list");10 if(!js_list){11     printf("no list!\n");12     return -1;13 }14 int array_size = cJSON_GetArraySize(js_list);15 printf("array size is %d\n",array_size);16 int i = 0;17 cJSON *item,*it, *js_name, *js_age;18 char *p  = NULL;19 for(i=0; i< array_size; i++) {20     item = cJSON_GetArrayItem(js_list, i);21     if(!item) {22         //TODO...23     }24     p = cJSON_PrintUnformatted(item);25     it = cJSON_Parse(p);26     if(!it)27         continue ;28     js_name = cJSON_GetObjectItem(it, "name");29     printf("name is %s\n",js_name->valuestring);30     js_age = cJSON_GetObjectItem(it, "age");31     printf("age is %d\n",js_age->valueint);32 33 }34 35 if(root)36     cJSON_Delete(root);37     return 0;38 }

按理说,应该释放下 it 变量才对,但似乎事实不是这样,仅仅可以释放根root。

好了,json 解析,无非就是上面的组合了,还能有什么呢?

解析和封装都有了,此文结束了。

看这里:

https://github.com/boyisgood86/learning/tree/master/cjson

good luck !

0 0
原创粉丝点击