JSON和cJSON

cJson使用

目录

  • 一、什么是JSON
    • 1、JSON
    • 2、cJSON
  • 二、例子
    • 1、最简单的cJSON字符串
    • 2、使用cJSON解析数组
  • 三、完整代码

一、什么是JSON

1、JSON

JSON(JavaScript Object Notation)是一种轻量级的文本数据交换格式,易于让人阅读。同时也易于机器解析和生成。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON解析器和JSON库支持许多不同的编程语言。

几乎所有与网页开发相关的语言都有JSON库。JSON比XML更小、更快

JSON用于描述数据结构,有以下形式存在:

(1)、对象(object):一个对象以”{“开始,并以”}”结束。一个对象包含一系列非排序的名称/值对,每个名称/值对之间使用”,”分隔。

(2)、名称/值(collection):名称和值之间使用”:”隔开。一个名称是一个字符串;一个值 (value)可以是双引号括起来的字符串(string)、数值(number)、true、false、null、对象(object)或者数组(array)。这些结构可以嵌套。

JSON语法规则:(1)、数据在键值对中;(2)、数据由逗号分隔;(3)、花括号保存对象;(4)、方括号保存数组。

JSON的值可以是:

(1) 数值:一系列0–9的数字组合,可以为负数或者小数。还可以用”e”或者”E”表示为指数形式。数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。

(2) 字符串:以""括起来的一串字符。字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。字符串(string)与C或者Java的字符串非常相似。

(3) 布尔值:表示为true或者false。

(4) 数组(Array):数组是值(value)的有序集合。一个数组以”[“(左中括号)开始,”]”(右中括号)结束。值之间使用”,”(逗号)分隔。数组索引从0开始。

(5) 对象(object):对象是一个无序的”名称/值”对集合。一个对象以”{“开始,并以”}”结束。每个”名称”后跟一个”:”(冒号)。”名称/值”对之间使用”,”(逗号)分隔。

(6) null:空白可以加入到任何符号之间。

各式各样开源的JSON库非常多,这里介绍下GitHub上DaveGamble的cJSON库的使用,地址: https://github.com/DaveGamble/cJSON ,它用起来非常方便。

关于json11的使用可以参考:https://blog.csdn.net/fengbingchun/article/details/51396932

);

2、cJSON

cJSON是一个仅有一个.h文件,一个.c文件组成的JSON解析器,它是由纯C(ANSI C89)实现的,跨平台性较好。cJSON中有一个cJSON结构体。cJSON是采用链表存储的.

cJSON对象的实现采用了树形结构,每个对象是树的一个节点,每个节点由cJSON这个结构体组成,对象中的元素也由cJSON这个结构体组成。同一层的对象和元素是双向链表结构,由next和prev指针链接。不同层的对象或元素由child指针链接起来。type表示对象或元素类型,string表示对象或节点的名称。元素的值存储在valuestring, valueint和valuedouble中。cJSON.h中有详细的注释

为什么选择cJSON来解析JSON字符串?因为简洁又简单,而且效率又快,cJSON工程文件也非常简单,仅一个.c文件和一个.h文件!

1
2
3
4
5
6
7
8
9
10
typedef struct cJSON
{<!-- -->     //cJSON结构体
       struct cJSON *next,*prev;               /* 遍历数组或对象链的前向或后向链表指针*/
       struct cJSON *child;                   /* 数组或对象的孩子节点*/
       int type;                              /* key的类型*/
       char *valuestring;                     /* 字符串值*/
       int valueint;                          /* 整数值*/
       double valuedouble;                    /* 浮点数值*/
       char *string;                          /* key的名字*/
} cJSON;

常用的cJSON函数:

1
2
3
cJSON *cJSON_Parse(const char *value);
    作用:将一个JSON数据包,按照cJSON结构体的结构序列化整个数据包,并在堆中开辟一块内存存储cJSON结构体
返回值:成功返回一个指向内存块中的cJSON的指针,失败返回NULL
1
2
3
4
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
 
作用:获取JSON字符串字段值
返回值:成功返回一个指向cJSON类型的结构体指针,失败返回NULL
1
2
3
4
char  *cJSON_Print(cJSON *item);
 
作用:将cJSON数据解析成JSON字符串,并在堆中开辟一块char*的内存空间存储JSON字符串
返回值:成功返回一个char*指针该指针指向位于堆中JSON字符串,失败返回NULL
1
2
3
4
void  cJSON_Delete(cJSON *c);
 
作用:释放位于堆中cJSON结构体内存
返回值:无

二、例子

1、最简单的cJSON字符串

假如说有这样的一个JSON字符串

{
“test_1”:“0”
“test_2”:“1”
“test_3”:“2”
} //json_string

这是最简单的JSON字符串

我们首先要先将这个字符串打包成cJSON数据格式

1
cJSON* cjson = cJSON_Parse(json_string);

打包后使用if语句或三目表达式判断一下是否将JSON字符串打包成cJSON数据格式

1
2
3
4
5
6
7
8
if(cjson == NULL)
{<!-- -->
    printf("json pack into cjson error...");
}
else
{<!-- -->//打包成功调用cJSON_Print打印输出
    printf("%s\r\n",cJSON_Print(cjson));
}

然后依次获取json字符串中的每个字段的值并打印输出

1
2
3
4
5
6
7
8
9
//cJSON_GetObjectltem返回的是一个cJSON结构体所以我们可以通过函数返回结构体的方式选择返回类型!
char* test_1_string = cJSON_GetObjectltem(cjson,"test_1")->valuestring;
char* test_2_string = cJSON_GetObjectltem(cjson,"test_2")->valuestring;
char* test_3_string = cJSON_GetObjectltem(cjson,"test_3")->valuestring;

//打印输出
printf("%s",*test_1_string);
printf("%s",*test_2_string);
printf("%s",*test_3_string);

最后别忘记释放内存

1
2
//delete cjson
cJSON_Delete(cjson);

2、使用cJSON解析数组

如下:

{
“test_arr”:[{
{
“test_1”:“arr_1”,
“test_2”:“arr_2”,
“test_3”:“arr_3”
},
{
“test_1”:“1”,
“test_2”:“2”,
“test_3”:“3”
}
}]
}

在开始前介绍一个函数

1
2
3
4
int cJSON_GetArraySize(cJSON *array);
 
作用:获取数组成员对象个数
返回值:数组成员对象个数

首先第一步打包

1
cJSON* cjson = cJSON_Parse(json_arr_string);

第二步判断打包是否成功

1
2
3
4
5
6
7
8
if(cjson == NULL)
{<!-- -->
    printf("cjson error...");
}
else
{<!-- -->//打包成功调用cJSON_Print打印输出
    printf("%s\r\n",cJSON_Print(cjson));
}

第三步获取数组对象

1
cJSON* test_arr = cJSON_GetObjectltem(cjson,"test_arr");

第四步获取数组对象个数便于循环

1
int arr_size = cJSON_GetArraySize(test_arr);//return arr_size 2

第五步获取test_arr数组对象孩子节点

1
cJSON* arr_item = test_arr->child;//子对象

第六步循环获取数组下每个字段的值并使用cJSON_Print打印

1
2
3
4
5
6
7
8
for(int i = 0;i <=(arr_size-1)/*0*/;++i)
{<!-- -->
    printf("%s\r\n",cJSON_Print(cJSON_GetObjectItem(arr_item,"test_1")));
    printf("%s\r\n",cJSON_Print(cJSON_GetObjectItem(arr_item,"test_2")));
    printf("%s\r\n",cJSON_Print(cJSON_GetObjectItem(arr_item,"test_3")));
    arr_item = arr_item->next;//下一个子对象
 
}

最后别忘记释放

1
cJSON_Delete(cjson);

三、完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include "cJSON.h"
 
int main()
{<!-- -->
 
 
char json_arr_string[]="{"test_arr":[{"test_1":"arr_1","test_2":"arr_2","test_3":"arr_3"},{"test_1":"1","test_2":"2","test_3":"3"}]}"; 
 
 
    cJSON* cjson = cJSON_Parse(json_arr_string);
    if(cjson == NULL)
    {<!-- -->
        printf("cjson error...\r\n");
    }
    else
    {<!-- -->//打包成功调用cJSON_Print打印输出
        printf("%s\r\n",cJSON_Print(cjson));
    }
    cJSON* test_arr = cJSON_GetObjectItem(cjson,"test_arr");
    int arr_size = cJSON_GetArraySize(test_arr);//return arr_size 2
    cJSON* arr_item = test_arr->child;//子对象
 
    for(int i = 0;i <=(arr_size-1)/*0*/;++i)
    {<!-- -->
        printf("%s\r\n",cJSON_Print(cJSON_GetObjectItem(arr_item,"test_1")));
        printf("%s\r\n",cJSON_Print(cJSON_GetObjectItem(arr_item,"test_2")));
        printf("%s\r\n",cJSON_Print(cJSON_GetObjectItem(arr_item,"test_3")));
        arr_item = arr_item->next;//下一个子对象
    }
    cJSON_Delete(cjson);

}