博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
cJSON 使用笔记
阅读量:6758 次
发布时间:2019-06-26

本文共 9730 字,大约阅读时间需要 32 分钟。

                                                                                                        缘      起                                                                                                     

      最近在stm32f103上做一个智能家居的项目,其中选择的实时操作系统是 rt_thread OS v1.2.2稳定版本,其中涉及到C和java(android)端数据的交换问题,经过讨论和研究,选择了json格式的数据进行交互。当然,如果自己去写一个json解析器,有点重造轮子的嫌疑。于是使用了开源的json解析器。考虑到是嵌入式平台,在一位朋友的推荐下,选择了轻量级别的cJSON。

                                                                                                        使      用                                                                                                     

       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 这三个东西:

46 static void *(*cJSON_malloc)(size_t sz) = malloc; 47 static void (*cJSON_free)(void *ptr) = free;---------------------------------------- 46 static void *(*cJSON_malloc)(size_t sz) = rt_malloc; 47 static void (*cJSON_free)(void *ptr) = rt_free;
60 void cJSON_InitHooks(cJSON_Hooks* hooks) 61 { 62     if (!hooks) { /* Reset hooks */ 63         cJSON_malloc = malloc; 64         cJSON_free = free; 65         return; 66     } 67  68     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 69     cJSON_free   = (hooks->free_fn)?hooks->free_fn:free; 70 }---------------------------------------------------- 60 void cJSON_InitHooks(cJSON_Hooks* hooks) 61 { 62     if (!hooks) { /* Reset hooks */ 63         cJSON_malloc = rt_malloc; 64         cJSON_free = rt_free; 65         return; 66     } 67  68     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:rt_malloc; 69     cJSON_free   = (hooks->free_fn)?hooks->free_fn:rt_free; 70 }

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

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

                                                                                                   例       程                                                                                                          

      不对json的格式进行说明了,下面直接记下使用方法了。

      第一,创建json数据串。这数据串,可能是对象,也可能是数组,也可能是它们的各种组合,其中再加上一些键值对。有一点要先说明:它们的组合,符合父子继承格式--这也是json数据串的特点。

     <1>  创建一个对象,并在这个对象里面添加一个字符串键值和一个数字键值:

1 int create_js(void) 2 { 3     cJSON *root; 4     /*create json string root*/ 5     root = cJSON_CreateObject(); 6     if(!root) { 7         DEBUG("get root faild !\n"); 8         goto EXIT; 9     }else DEBUG("get root success!\n");10 11     {12         cJSON * js_body ;13 14         const char *const body = "body";15         cJSON_AddItemToObject(root, body, js_body=cJSON_CreateObject());16         cJSON_AddStringToObject(js_body,"name","xiaohui");17         cJSON_AddNumberToObject(js_body,"value",600);18         {19         char *s = cJSON_PrintUnformatted(root);20         if(s){21             DEBUG("create js string is %s\n",s);22             free(s);23         }24         }25         cJSON_Delete(root);26     }27 28     return 0;29 EXIT:30     return -1;31 }32 33 int main(int argc, char **argv)34 {35     create_js();36     return 0;37 }

运行结果:

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/17094113

http://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 42 name is xiao hong3 age type is 34 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 解析,无非就是上面的组合了,还能有什么呢?

 

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

看这里:

 

good luck !

 

 

update:  上面第四部分会导致内存泄露,修改方法见贴图:

转载于:https://www.cnblogs.com/chineseboy/p/3959852.html

你可能感兴趣的文章
C语言中判断int,long型等变量是否赋值的方法
查看>>
leetcode -- Longest Valid Parentheses
查看>>
中位数与第K小元素
查看>>
详解JAVA输出Hello World
查看>>
概率问题随笔
查看>>
关于在堆中创建字符串对象的疑惑
查看>>
poj1077(康托展开+bfs+记忆路径)
查看>>
hibernate 树状映射
查看>>
值得 Web 开发人员收藏的20个 HTML5 实例教程
查看>>
经典网页设计:无缝过渡的响应式设计案例
查看>>
ASP.NET MVC 多语言方案
查看>>
移动设备、手机浏览器Javascript滑动事件代码
查看>>
linux,__attribute__用法
查看>>
LinqToXML~读XML文件续
查看>>
java.sql.SQLException: JZ00L
查看>>
struts的标签库出现Failed to load or instantiate TagExtraInfo class
查看>>
Java Web入门必知
查看>>
2014-3-5 星期三 [New Change && New Start]
查看>>
Eclipse安装SVN插件
查看>>
@Resource注解
查看>>