使用cJSON解析JSON字符串

在学了在学了! 2020-08-20 11:08:00 3906

JSON学习-使用cJSON解析

使用cJSON解析JSON字符串

一、为何选择cJSON

我们在使用JSON格式时,如果只是处理简单的协议,可以依据JSON格式,通过对字符串的操作来进行解析与创建。然而随着协议逐渐复杂起来,经常会遇到一些未考虑周全的地方,需要进一步的完善解析方法,此时,使用比较完善的JSON解析库的需求就提出来了。

基于方便引用的考虑,我们希望这个JSON解析库是用C语言实现的。同时,为了避免太过复杂的C源码包含关系,希望最好是一个C文件来实现。通过在网络上的查找,发现cJSON是比较符合要求的。cJSON只有一个C文件,一个头文件,包含到项目源码中非常方便,而且其实现效率也是非常高的。

二、cJSON的核心结构体

cJSON的核心结构体就是一个cJSON,理解了这个结构体,基本上对cJSON的使用就有了个基本概念了。该结构体具体定义如下:

  typedef struct cJSON {
   struct cJSON*next,*prev;           /* 遍历数组或对象链的前向或后向链表指针*/
   struct cJSON *child;                   /*数组或对象的孩子节点*/
   int type;                                     /* key的类型*/
   char *valuestring;                       /*字符串值*/
   int valueint;                                /* 整数值*/
   double valuedouble;                    /* 浮点数值*/
   char *string;                               /* key的名字*/
  } cJSON;

说明:

1、cJSON是使用链表来存储数据的,其访问方式很像一颗树。每一个节点可以有兄弟节点,通过next/prev指针来查找,它类似双向链表;每个节点也可以有孩子节点,通过child指针来访问,进入下一层。只有节点是对象或数组时才可以有孩子节点。

2、type是键(key)的类型,一共有7种取值,分别是:False,Ture,NULL,Number,String,Array,Object。
若是Number类型,则valueint或valuedouble中存储着值。若期望的是int,则访问valueint,若期望的是double,则访问valuedouble,可以得到值。

若是String类型的,则valuestring中存储着值,可以访问valuestring得到值。

3、string中存放的是这个节点的名字,可理解为key的名称。

三、解析JSON格式;

还是在Linux下,使用C语言编程,先实现读文件的功能,然后开始JSON字符串的解析。我们还是一步步来,先从简单的开始,万丈高楼起于平地嘛。

1,下载源码;

可以从如下网站来下载:https://sourceforge.net/projects/cjson/

2,包含cJSON的源码;

下载下来,解压后,从里面找到两个文件(cJSON.c、cJSON.h),复制到我们的工程里面。只需在函数中包含头文件(#include “cJSON.h”),然后和cJSON.c一起编译即可使用。

3,解析一个键值对;

首先是一个简单的键值对字符串,要解析的目标如下:

{"firstName":"Brett"}

要进行解析,也就是要分别获取到键与值的内容。我们很容易就能看出键为firstName,值为Brett,可是,使用cJSON怎么解析呢?

对于这个简单的例子,只需要调用cJSON的三个接口函数就可以实现解析了,这三个函数的原型如下:

cJSONcJSON_Parse(const char value);

cJSONcJSON_GetObjectItem(cJSON object,const char *string);

voidcJSON_Delete(cJSON *c);

下面按解析过程来描述一次:

(1) 首先调用cJSON_Parse()函数,解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。使用该函数会通过malloc()函数在内存中开辟一个空间,使用完成需要手动释放。

cJSON*root=cJSON_Parse(json_string);

(2)调用cJSON_GetObjectItem()函数,可从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。

cJSON*item=cJSON_GetObjectItem(root,"firstName");

(3)如果需要使用cJSON结构体中的内容,可通过cJSON结构体中的valueint和valuestring取出有价值的内容(即键的值)
本例子中,我们直接访问 item->valuestring 就获取到 "Brett" 的内容了。

(4) 通过cJSON_Delete(),释放cJSON_Parse()分配出来的内存空间。

cJSON_Delete(root);

这样就完成了一次cJSON接口调用,实现了解析工作。使用起来其实也很简单的啊,呵呵。

4,解析一个结构体;

接下来,我们来个复杂一点的,解析一个结构体,要解析的目标如下:

{
         "person":
         {
                   "firstName":"z",
                   "lastName":"jadena",
                   "email":"jadena@126.com",
                   "age":8,
                   "height":1.17
         }        
}

看起来比一个键值对复杂多了,我们又需要学习新的接口函数了吗?

答案是不需要!

还是那三个函数就可以了。当然,解析的步骤要复杂一些了,下面我按解析过程来描述一次:

(1)根据JSON串中的对象,我们定义一个相应的结构体如下:

typedefstruct
{
         char firstName[32];
         char lastName[32];
         char email[64];
         int age;
         float height;
} PERSON;

具体的对应关系,一目了然,我就不罗嗦了。让我们直奔主题,解析!

(2)还是调用cJSON_Parse()函数,解析JSON数据包。
cJSON*root=cJSON_Parse(json_string);

(3)调用一次cJSON_GetObjectItem()函数,获取到对象person。
cJSON *object=cJSON_GetObjectItem(root,"person");

(4)对我们刚取出来的对象person,多次调用cJSON_GetObjectItem()函数,来获取对象的成员。此时要注意,不同的成员,访问的方法不一样:


cJSON*item;
PERSONperson;
item=cJSON_GetObjectItem(object,"firstName");
memcpy(person.firstName,item->valuestring,strlen(item->valuestring));
item=cJSON_GetObjectItem(object,"lastName");
memcpy(person.lastName,item->valuestring,strlen(item->valuestring));
item=cJSON_GetObjectItem(object,"email");
memcpy(person.email,item->valuestring,strlen(item->valuestring));
item=cJSON_GetObjectItem(object,"age");
person.age=item->valueint;
item=cJSON_GetObjectItem(object,"height");
person.height=item->valuedouble;

这样,就获取到了对象的全部内容了。

(5) 通过cJSON_Delete(),释放cJSON_Parse()分配出来的内存空间。
cJSON_Delete(root);

至此,我们就使用cJSON接口完成了基于结构体的解析工作。

5,解析结构体数组的JSON串;

最后,我们来个更复杂一些的,来解析一个数组,并且数组的成员是结构体!要解析的JSON串如下:

```      

{
"people":[
{"firstName":"z","lastName":"Jason","email":"bbbb@126.com","height":1.67},
{"lastName":"jadena","email":"jadena@126.com","age":8,"height":1.17},
{"email":"cccc@126.com","firstName":"z","lastName":"Juliet","age":36,"height":1.55}
]
}


此时,我们真的又需要学习新的接口了,一个是获取数组长度,一个是取数组成员,函数原型如下:

int cJSON_GetArraySize(cJSON *array);

cJSONcJSON_GetArrayItem(cJSON array,int item);



  由于前面已经实现了结构体的解析,这里我们只需要关注下数组的相关调用即可。 

(1)调用cJSON_Parse()函数,解析JSON数据包。

(2)调用一次cJSON_GetObjectItem()函数,获取到数组people。

(3)对我们刚取出来的数组people,调用cJSON_GetArraySize()函数,来获取数组中对象的个数。然后,多次调用cJSON_GetArrayItem()函数,逐个读取数组中对象的内容。

(4)通过cJSON_Delete(),释放cJSON_Parse()分配出来的内存空间。

 这样,我们就使用cJSON接口完成了结构体数组的解析工作。

详细代码见后文附带例程。    

说明:

本文所附带例程,实现了结构体数组的解析,只是一个学习之作,对于初学JSON使用cJSON接口的同学,可以有些借鉴参考的作用。 

例程:

    #include <stdio.h>

    #include <string.h>

    #include <sys/types.h>

    #include <stdlib.h>

    #include <unistd.h>

    #include "cJSON.h"

    typedef struct

    {

        int id;

        char firstName[32];

        char lastName[32];

        char email[64];

        int age;

        float height;

    }people;

    void dofile(char *filename);/* Read a file, parse, render back, etc. */

    int main(int argc, char **argv)

    {

    //  dofile("json_str1.txt");

    //  dofile("json_str2.txt");

        dofile("json_str3.txt");

        return 0;

    }

    //parse a key-value pair

    int cJSON_to_str(char *json_string, char *str_val)

    {

        cJSON *root=cJSON_Parse(json_string);

        if (!root)

        {

            printf("Error before: [%s]\n",cJSON_GetErrorPtr());

            return -1;

        }

        else

        {

            cJSON *item=cJSON_GetObjectItem(root,"firstName");

            if(item!=NULL)

            {

                printf("cJSON_GetObjectItem: type=%d, key is %s, value is %s\n",item->type,item->string,item->valuestring);

                memcpy(str_val,item->valuestring,strlen(item->valuestring));

            }

            cJSON_Delete(root);

        }

        return 0;

    }

    //parse a object to struct

    int cJSON_to_struct(char *json_string, people *person)

    {

        cJSON *item;

        cJSON *root=cJSON_Parse(json_string);

        if (!root)

        {

            printf("Error before: [%s]\n",cJSON_GetErrorPtr());

            return -1;

        }

        else

        {

            cJSON *object=cJSON_GetObjectItem(root,"person");

            if(object==NULL)

            {

                printf("Error before: [%s]\n",cJSON_GetErrorPtr());

                cJSON_Delete(root);

                return -1;

            }

            printf("cJSON_GetObjectItem: type=%d, key is %s, value is %s\n",object->type,object->string,object->valuestring);

            if(object!=NULL)

            {

                item=cJSON_GetObjectItem(object,"firstName");

                if(item!=NULL)

                {

                    printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);

                    memcpy(person->firstName,item->valuestring,strlen(item->valuestring));

                }

                item=cJSON_GetObjectItem(object,"lastName");

                if(item!=NULL)

                {

                    printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);

                    memcpy(person->lastName,item->valuestring,strlen(item->valuestring));

                }

                item=cJSON_GetObjectItem(object,"email");

                if(item!=NULL)

                {

                    printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);

                    memcpy(person->email,item->valuestring,strlen(item->valuestring));

                }

                item=cJSON_GetObjectItem(object,"age");

                if(item!=NULL)

                {

                    printf("cJSON_GetObjectItem: type=%d, string is %s, valueint=%d\n",item->type,item->string,item->valueint);

                    person->age=item->valueint;

                }

                else

                {

                    printf("cJSON_GetObjectItem: get age failed\n");

                }

                item=cJSON_GetObjectItem(object,"height");

                if(item!=NULL)

                {

                    printf("cJSON_GetObjectItem: type=%d, string is %s, valuedouble=%f\n",item->type,item->string,item->valuedouble);

                    person->height=item->valuedouble;

                }

            }

            cJSON_Delete(root);

        }

        return 0;

    }

    //parse a struct array

    int cJSON_to_struct_array(char *text, people worker[])

    {

        cJSON *json,*arrayItem,*item,*object;

        int i;

        json=cJSON_Parse(text);

        if (!json)

        {

            printf("Error before: [%s]\n",cJSON_GetErrorPtr());

        }

        else

        {

            arrayItem=cJSON_GetObjectItem(json,"people");

            if(arrayItem!=NULL)

            {

                int size=cJSON_GetArraySize(arrayItem);

                printf("cJSON_GetArraySize: size=%d\n",size);

                for(i=0;i<size;i++)

                {

                    printf("i=%d\n",i);

                    object=cJSON_GetArrayItem(arrayItem,i);

                    item=cJSON_GetObjectItem(object,"firstName");

                    if(item!=NULL)

                    {

                        printf("cJSON_GetObjectItem: type=%d, string is %s\n",item->type,item->string);

                        memcpy(worker[i].firstName,item->valuestring,strlen(item->valuestring));

                    }

                    item=cJSON_GetObjectItem(object,"lastName");

                    if(item!=NULL)

                    {

                        printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);

                        memcpy(worker[i].lastName,item->valuestring,strlen(item->valuestring));

                    }

                    item=cJSON_GetObjectItem(object,"email");

                    if(item!=NULL)

                    {

                        printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);

                        memcpy(worker[i].email,item->valuestring,strlen(item->valuestring));

                    }

                    item=cJSON_GetObjectItem(object,"age");

                    if(item!=NULL)

                    {

                        printf("cJSON_GetObjectItem: type=%d, string is %s, valueint=%d\n",item->type,item->string,item->valueint);

                        worker[i].age=item->valueint;

                    }

                    else

                    {

                        printf("cJSON_GetObjectItem: get age failed\n");

                    }

                    item=cJSON_GetObjectItem(object,"height");

                    if(item!=NULL)

                    {

                        printf("cJSON_GetObjectItem: type=%d, string is %s, value=%f\n",item->type,item->string,item->valuedouble);

                        worker[i].height=item->valuedouble;

                    }

                }

            }

            for(i=0;i<3;i++)

            {

                printf("i=%d, firstName=%s,lastName=%s,email=%s,age=%d,height=%f\n",

                        i,

                        worker[i].firstName,

                        worker[i].lastName,

                        worker[i].email,

                        worker[i].age,

                        worker[i].height);

            }

            cJSON_Delete(json);

        }

        return 0;

    }

    // Read a file, parse, render back, etc.

    void dofile(char *filename)

    {

        FILE *f;

        int len;

        char *data;

        f=fopen(filename,"rb");

        fseek(f,0,SEEK_END);

        len=ftell(f);

        fseek(f,0,SEEK_SET);

        data=(char*)malloc(len+1);

        fread(data,1,len,f);

        fclose(f);

        printf("read file %s complete, len=%d.\n",filename,len);

    //  char str_name[40];

    //  int ret = cJSON_to_str(data, str_name);

    //  people person;

    //  int ret = cJSON_to_struct(data, &person);

        people worker[3]={{0}};

        cJSON_to_struct_array(data, worker);

        free(data);

    }

原文连接:https://blog.csdn.net/lintax/article/details/50993958
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
在学了在学了!
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区