美文网首页
cJSON用法,转载

cJSON用法,转载

作者: 嵌入式工作 | 来源:发表于2018-09-12 18:33 被阅读0次

    最近在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上,请使用以下命令进行编译:

    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;
    
    
     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;
    
    

    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;
    }
    
    
    

    运行结果:

     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> 创建一个数组,并向数组添加一个字符串和一个数字:

    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_Print(root);
            char *s = cJSON_PrintUnformatted(root);
            if(s){
                DEBUG(" %s \n",s);
                free(s);
            }
        }
        if(root)
        cJSON_Delete(root);
    
        return 0;
    EXIT:
        return -1;
    }
    
    int main(int argc, char **argv)
    {
        create_js();
        return 0;
    }
    
    

    运行结果:

    1 ["Hello world",10]
    
    

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

    
    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","xiaohui");
        cJSON_AddNumberToObject(js_list,"status",100);
    
        {
            //        char *s = cJSON_Print(root);
            char *s = cJSON_PrintUnformatted(root);
            if(s){
                DEBUG(" %s \n",s);
                free(s);
            }
        }
        if(root)
            cJSON_Delete(root);
    
        return 0;
    EXIT:
        return -1;
    }
    
    int main(int argc, char **argv)
    {
        create_js();
        return 0;
    }
    
    

    运行结果:

    
    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}
    
    
    

    这个字符串这样拿即可:

    
    char *s = "{\"name\":\"xiao hong\",\"age\":10}";
    cJSON *root = cJSON_Parse(s);
    if(!root) {
        printf("get root faild !\n");
        return -1;
    }
    cJSON *name = cJSON_GetObjectItem(root, "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(root, "age");
    if(!age) {
        printf("no age!\n");
        return -1;
    }
    printf("age type is %d\n", age->type);
    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\"}}
    
    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 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\"]}
    
    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;
    }
    

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

    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 是一个数组,数组里面有两个对象,那么代码如下:

    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) {
            //TODO...
        }
        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;
    }
    
    

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

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

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

    相关文章

      网友评论

          本文标题:cJSON用法,转载

          本文链接:https://www.haomeiwen.com/subject/msrbgftx.html