使⽤CJSON解析JSON结构体数组【典型】
1.CJSON数据结构定义
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5  //数组
#define cJSON_Object 6 //对象or单键名
typedef struct cJSON {
struct cJSON *next,*prev;    /*遍历数组或对象链的前向或后向链表指针*/
struct cJSON *child;        /*数组或对象的⼦节点*/
int type;                    /* key键的类型,上⾯宏定义的7中之⼀*/
char *valuestring;            /*字符串值, if type==cJSON_String */
int valueint;                /* 整型数值, if type==cJSON_Number */
double valuedouble;            /* 浮点数值, if type==cJSON_Number */
char *string;                /* key键的名字 */
} cJSON;
说明:
1、cJSON是使⽤链表来存储数据的,其访问⽅式很像⼀颗树。每⼀个节点可以有兄弟节点,通过next/prev指针来查,它类似双向链表;每个节点也可以有孩⼦节点,通过child指针来访问,进⼊下⼀层。只有节点是对象或数组时才可以有孩⼦节点。
2、type是键(key)的类型,⼀共有7种取值,分别是:False,Ture,NULL,Number,String,Arra
y(数组),Object(对象或单键名)。
若是Number类型,则valueint或valuedouble中存储着值。若期望的是int,则访问valueint,若期望的是double,则访问valuedouble,可以得到值。若是String类型的,则valuestring中存储着值,可以访问valuestring得到值。
3、string中存放的是这个节点的名字,可理解为key的名称。
2.常⽤的解析函数
/* 第⼀个
*函数功能:将⼀个JSON数据包序列化,并开辟堆内存存储获取的cJSON对象;
*返回值:成功返回⼀个指向cJSON对象的指针;失败则返回NULL
*/
extern cJSON *cJSON_Parse(const char *value);//从源数据中,获取未整理的JSON对象
/* 第⼆个
*函数功能:根据单键名(cjson对象)获取对应的值
*参数:
*objec:第⼀个函数中获取的句柄
* string:需要获取的对象
*返回值:
*/
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* 第三个
*函数功能:
*返回值:
*/
extern int  cJSON_GetArraySize(cJSON *array);//获取cjson对象数组成员的个数
/* 第四个
*函数功能:根据下标获取cjosn对象数组中对应元素的对象
*参数:
array 数组名
item 数组的下标元素
c++string类型*返回值:元素的键值;失败则返回NULL
*/
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* 第五个
*作⽤:与Parse成对出现,释放Parse操作时,产⽣的位于堆中cJSON结构体内存;
*返回值:⽆
*/
extern void  cJSON_Delete(cJSON *c);//删除cjson对象,释放链表占⽤的内存空间
3.解析:包含两个键值对的结构体(单层)
第⼀层结构体;第⼆层键值对
步骤:Parse格式化==》cJSON_GetObjectItem根据键名获取键值
char text[]="{\"name\":\"Tom\",\"age\":18}";
cJSON * root = cJSON_Parse(text);
if(!root) {
printf("no json\n");
return -1;
}
//name
cJSON *name = cJSON_GetObjectItem(root, "name");
if (!name) {
printf("no name!\n");
return -1;
} else{
printf("%s\n",name->valuestring);
}
//age
cJSON *age = cJSON_GetObjectItem(root, "age");
if (!age) {
printf("no age!\n");
return -1;
} else{
printf("%d\n",age->valueint);
}
cJSON_Delete(root);
4.解析:键值对嵌套
{
"semantic": {
"slots":    {
"name": "张三"
}
},
"rc":  0,
"operation":    "CALL",
"service":  "telephone",
"text": "打电话给张三"
}
5.解析:包含键值对结构体的数组
第⼀层数组;第⼆层结构体;第三层键值对;
步骤:Parse格式化==》IsArray判断是否数组==》GetArraySize获取数组元素个数==》cJSON_GetAr
rayItem按照下标检索数组元素==》cJSON_GetObjectItem根据元素中的单键名获取键值
int main(){
char text[]="[{\"name\":\"Tom1\",\"age\":18},{\"name\":\"Tom2\",\"age\":19},{\"name\":\"Tom3\",\"age\":20},{\"name\":\"Tom4\",\"age\":21}]";
cJSON * root = cJSON_Parse(text);
if(!root) {
printf("no json\n");
return -1;
}
if (!cJSON_IsArray(root)){
printf("no Array\n");
return -1;
}
//数组长度
int array_size = cJSON_GetArraySize(root);
cJSON *item;
cJSON *name;
cJSON *age;
for(int i=0; i< array_size; i++) {
item = cJSON_GetArrayItem(root, i);
name = cJSON_GetObjectItem(item, "name");
if (!name) {
printf("no name!\n");
return -1;
}
printf("%s\t",name->valuestring);
age = cJSON_GetObjectItem(item, "age");
if (!age) {
printf("no age!\n");
return -1;
}
printf("%d\n",age->valueint);
}
return 0;
}
cJSON_Delete(root);
6.解析结构体数组的JSON串
与5的区别在于,第⼀层是键值对(值:是结构体数组)
{
"people":[
{"firstName":"z","lastName":"Jason","email":"bbbb@126","height":1.67},
{"lastName":"jadena","email":"jadena@126","age":8,"height":1.17},
{"email":"cccc@126","firstName":"z","lastName":"Juliet","age":36,"height":1.55}
]
}
(1)调⽤cJSON_Parse()函数,解析JSON数据包。
(2)调⽤⼀次cJSON_GetObjectItem()函数,获取到数组people。【重点区别!!】
(3)对刚取出来的数组people,调⽤cJSON_GetArraySize()函数,来获取数组中对象的个数。然后,多次调⽤cJSON_GetArrayItem()函数,逐个读取数组中对象的内容。
(4)通过cJSON_Delete(),释放cJSON_Parse()分配出来的内存空间。
例程如下:例程较长,见⽂章末尾。
7.混合解析:键值对结构体+数组混合嵌套
{
"results":
[
{
"currentConfirmedCount":3247,
"currentConfirmedIncr":-37,
"confirmedCount":127336,
"confirmedIncr":39,
"suspectedCount":9919,
"suspectedIncr":23,
"curedCount":118392,
"curedIncr":76,
"deadCount":5697,
"deadIncr":0,
"seriousCount":500,
"seriousIncr":-10,
"globalStatistics":
{
"currentConfirmedCount":40083221,
"confirmedCount":255222728,
"curedCount":210013003,
"deadCount":5126504,
"currentConfirmedIncr":370347,
"confirmedIncr":485719,
"curedIncr":108221,
"deadIncr":7151,
"yesterdayConfirmedCountIncr":485714
},
"generalRemark":"",
"remark1":"易感⼈:⼈普遍易感。⽼年⼈及有基础疾病者感染后病情较重,⼉童及婴幼⼉也有发病",
"remark2":"潜伏期:⼀般为 3~7 天,最长不超过 14 天,潜伏期内可能存在传染性,其中⽆症状病例传染性⾮常罕见",                "remark3":"宿主:野⽣动物,可能为中华菊头蝠",
"remark4":"",
"remark5":"",
"note1":"病毒:SARS-CoV-2,其导致疾病命名 COVID-19",
"note2":"传染源:新冠肺炎的患者。⽆症状感染者也可能成为传染源。",
"note3":"传播途径:经呼吸道飞沫、接触传播是主要的传播途径。⽓溶胶传播和消化道等传播途径尚待明确。",
"updateTime":1637145079410
}
],
"success":true
}
⽽当待解析数据同时包含了“结构体数组”时:
第⼀步,先利⽤cJSON_GetArraySize获取数组元素个数;
第⼆步,使⽤cJSON_GetArrayItem(数组名,元素下标)⽅式来检索数组中对应的元素;
第三步,判断该元素是否包含了直接的对象,即该元素的类型是否是cJSON_Object;
第四步,使⽤cJSON_GetObjectItem(元素名,单键名)的⽅式获取单键名所对应的键值;
仅解析部分:
int parseData(uint8_t *str)
{
int ret = 0;
cJSON *root, *result_arr;
cJSON *result, *global;
time_t updateTime;
struct tm *time;
root = cJSON_Parse((const char *)str);  //创建JSON解析对象,返回JSON格式是否正确

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。