• cJSON 使用笔记


                                                                                                            缘      起                                                                                                     

          最近在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 !
    ");
     8         goto EXIT;
     9     }else DEBUG("get root success!
    ");
    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
    ",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的区别即是:一个是没有格式的:也就是转换出的字符串中间不会有" " " "之类的东西存在,而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 
    ",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 
    ",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 !
    ");
     5     return -1;
     6 }
     7 cJSON *name = cJSON_GetObjectItem(root, "name");
     8 if(!name) {
     9     printf("No name !
    ");
    10     return -1;
    11 }
    12 printf("name type is %d
    ",name->type);
    13 printf("name is %s
    ",name->valuestring);
    14 
    15 cJSON *age = cJSON_GetObjectItem(root, "age");
    16 if(!age) {
    17     printf("no age!
    ");
    18     return -1;
    19 }
    20 printf("age type is %d
    ", age->type);
    21 printf("age is %d
    ",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 !
    ");
     5     return -1;
     6 }
     7 
     8 cJSON *js_list = cJSON_GetObjectItem(root, "list");
     9 if(!js_list) {
    10     printf("no list!
    ");
    11     return -1;
    12 }
    13 printf("list type is %d
    ",js_list->type);
    14 
    15 cJSON *name = cJSON_GetObjectItem(js_list, "name");
    16 if(!name) {
    17     printf("No name !
    ");
    18     return -1;
    19 }
    20 printf("name type is %d
    ",name->type);
    21 printf("name is %s
    ",name->valuestring);
    22 
    23 cJSON *age = cJSON_GetObjectItem(js_list, "age");
    24 if(!age) {
    25     printf("no age!
    ");
    26     return -1;
    27 }
    28 printf("age type is %d
    ", age->type);
    29 printf("age is %d
    ",age->valueint);
    30 
    31 cJSON *js_other = cJSON_GetObjectItem(root, "other");
    32 if(!js_other) {
    33     printf("no list!
    ");
    34     return -1;
    35 }
    36 printf("list type is %d
    ",js_other->type);
    37 
    38 cJSON *js_name = cJSON_GetObjectItem(js_other, "name");
    39 if(!js_name) {
    40     printf("No name !
    ");
    41     return -1;
    42 }
    43 printf("name type is %d
    ",js_name->type);
    44 printf("name is %s
    ",js_name->valuestring);
    45 
    46 if(root)
    47     cJSON_Delete(root);
    48     return 0;

    打印结果:

    1 list type is 6
    2 name type is 4
    3 name is xiao hong
    4 age type is 3
    5 age is 10
    6 list type is 6
    7 name type is 4
    8 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 !
    ");
     7     return -1;
     8 }
     9 cJSON *js_list = cJSON_GetObjectItem(root, "list");
    10 if(!js_list){
    11     printf("no list!
    ");
    12     return -1;
    13 }
    14 int array_size = cJSON_GetArraySize(js_list);
    15 printf("array size is %d
    ",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
    ",item->type);
    21     printf("%s
    ",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 !
    ");
     7     return -1;
     8 }
     9 cJSON *js_list = cJSON_GetObjectItem(root, "list");
    10 if(!js_list){
    11     printf("no list!
    ");
    12     return -1;
    13 }
    14 int array_size = cJSON_GetArraySize(js_list);
    15 printf("array size is %d
    ",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
    ",js_name->valuestring);
    30     js_age = cJSON_GetObjectItem(it, "age");
    31     printf("age is %d
    ",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 !

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

  • 相关阅读:
    x5开源库后续知识点
    仿抖音上下滑动分页视频
    Sp效率分析和理解
    ARCGIS 数据格式
    arcEngine开发之activeView.PartialRefresh(译)
    arcEngine开发之查询的相关接口
    arcEngine开发之查看属性表
    arcEngine开发之根据点坐标创建Shp图层
    arcEngine开发之加载栅格数据
    arcEngine开发之IMap、ILayer、IFeatureLayer和IFeatureClass关系
  • 原文地址:https://www.cnblogs.com/chineseboy/p/3959852.html
Copyright © 2020-2023  润新知