JSON介绍

JSON全称为JavaScript Object Notation, JavaScript对象表示法, 是一种轻量级的数据交换语言, 不但易于让人阅读理解, 也易于让计算机理解。JSON格式虽然属于JavaScript的子集, 但他与语言无关, 是一种独立于语言的文本格式。 许多编程语言都支持JSON格式数据的生成和解析。关于json格式的更详细的资料可以参考https://www.json.org/

JSON格式简要说明

JSON的基本数据类型包括:数值(整型浮点型均可),字符串(用双引号括起来),布尔型(true or false), 数组([value, value, value···]),对象(无序的键值对,以花括号括起来,键与值之间以冒号分割,键值对之间以逗号分隔。)

JSON格式举例

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"type": 41,
"payload": {
"dates": ["20190926", "20190927", "20190928"],
"times": [{
"begin": "1568476800",
"end": "1568480399"
}, {
"begin": "1568480400",
"end": "1568483999"
}]
}
}

以上是一个标准的json对象。json对象由一对花括号括起来,成员都是以键值对的形式存在,即key-value pair,这种格式在web开发、NoSQL中应用十分广泛,也应用于在网络中传输各种数据量不大的数据。,值可以是数字,字符串数组,json对象数组。

cJSON介绍

这个是一个用标准的C来写的json对象的解析生成的库,可以跨平台使用。轻巧,源码结构简洁,消耗资源少,使得他在嵌入式设备中非常有优势。cJSON项目的代码仓库 https://github.com/DaveGamble/cJSON。只需要将其中的两个c文件和两个h文件添加到我们的工程中即可方便的使用。此外还能根据需要灵活修改一些源码。

应用cJSON

生成JSON文本

大体步骤

  1. cJSON_CreateObject()创建json root对象分配空间;
  2. 向root对象中添加 item, item也可以是object或array:
    (1)item:用cJSON_CreateString() cJSON_CreateNumber()创建的item;
    (2)object:cJSON_CreateObject()出来一个新的json对象,往当前对象可以再添加item,也就是说json对象可以嵌套;
    (3)array:用cJSON_CreateArray()先创建array, 然后可以向当前的array添加item;
  3. 利用cJSON_Print(root)或者cJSON_PrintUnformatted(root)生成json root对象的json字符串;
  4. cJSON_Delete(root)释放json root占用的内存空间;
    以上面给出的JSON示例进行举例,他的生成代码是:
    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
    cJSON* root = cJSON_CreateObject(); //先生成一个空的JSON对象root
    cJSON* type = cJSON_CreateNumber(41); //创建一个数值型的元素type
    cJSON_AddItemToObject(root, "type", type); //将type添加进root对象中
    cJSON* payload = cJSON_CreateObject(); //生成一个空的json对象元素payload
    cJSON_AddItemToObject(root, "payload", payload); //将payload添加到root中
    cJSON* dates = cJSON_CreateArray(); //创建一个json数组元素dates
    cJSON_AddItemToObject(payload, "dates", dates);
    cJSON* day1 = cJSON_CreateString("20190926");
    cJSON* day2 = cJSON_CreateString("20190927");
    cJSON* day3 = cJSON_CreateString("20190928");
    cJSON_AddItemToArray(dates, day1); //将3个字符串元素添加进数组dates中
    cJSON_AddItemToArray(dates, day2);
    cJSON_AddItemToArray(dates, day3);
    cJSON* times = cJSON_CreateArray();
    cJSON_AddItemToObject(payload, "times", times);
    cJSON* node1 = cJSON_CreateObject();
    cJSON* begin1 = cJSON_CreateString("1568476800");
    cJSON* end1 = cJSON_CreateString("1568480399");
    cJSON_AddItemToObject(node1, "begin", begin1);
    cJSON_AddItemToObject(node1, "end", end1);
    cJSON* node2 = cJSON_CreateObject();
    cJSON* begin2 = cJSON_CreateString("1568480400");
    cJSON* end2 = cJSON_CreateString("1568483999");
    cJSON_AddItemToObject(node2, "begin", begin2);
    cJSON_AddItemToObject(node2, "end", end2);
    cJSON_AddItemToArray(times, node1); //将一个json对象作为元素添加进数组times中
    cJSON_AddItemToArray(times, node2);

    printf("%s\r\n",cJSON_Print(root)); //将JSON对象root转换成字符串并打印出来,我们也可以将转换结果保存到文件或者在网络上传输。
    cJSON_Delete(root); //记住用完cjson对象后一定要调用这个方法对内存进行回收,不然会内存泄漏

解析JSON文本

大体步骤

  1. 通过cJSON_Parse()方法从json字符串中创建json对象root;
  2. 通过cJSON_GetObjectItem(parseRoot, “type”)从root对象中获取item,item可能是字符串,数值,json对象或者array:
    (1)item: 如果是字符串,可以直接通过cJSON_GetStringValue()获取到字符串,如果是数值型元素,可以通过item->valueInt或者item->valueFloat获得浮点数;
    (2)object:如果从root对象中获得的item为object,那么接着用cJSON_GetObjectItem()从当前object中获得item;
    (3)array:从跟对象中获得的item为array,那么需要用cJSON_GetArraySize()得到数组长度,再用cJSON_GetArrayItem()从数组中获得相应的对象继续处理;
  3. 一样最后要记得释放json对象占用的内存空间;

用以下的代码对上述例子中的JSON对象进行解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char* content = (char*)malloc(512);
strcpy(content, cJSON_Print(root));
cJSON* parseRoot = cJSON_Parse(content);
cJSON* parseType = cJSON_GetObjectItem(parseRoot, "type");
printf("type:%d\r\n",cJSON_GetIntegerValue(parseType));
cJSON* parsePayload = cJSON_GetObjectItem(parseRoot, "payload");
cJSON* parseDates = cJSON_GetObjectItem(parsePayload, "dates");
cJSON* parseTimes = cJSON_GetObjectItem(parsePayload, "times");
for(int i = 0; i < cJSON_GetArraySize(parseDates); i++){
printf("dates[%d]:%s\r\n", i, cJSON_GetStringValue(cJSON_GetArrayItem(parseDates, i)));
}
for(int i = 0; i < cJSON_GetArraySize(parseTimes); i++){
cJSON* node = cJSON_GetArrayItem(parseTimes, i);
cJSON* begin = cJSON_GetObjectItem(node, "begin");
cJSON* end = cJSON_GetObjectItem(node, "end");
printf("node:%d\r\n\tbegin:%s;end:%s\r\n", i, cJSON_GetStringValue(begin), cJSON_GetStringValue(end));
}
free(content);
cJSON_Delete(parseRoot);

其中的cJSON_GetIntegerValue()是自己添加的,因为cJSON库里没有这个方法,实现代码很简单:

1
2
3
4
5
6
CJSON_PUBLIC(int) cJSON_GetIntegerValue(cJSON *item) {
if(!cJSON_IsNumber(item)) {
return NULL;
}
return item->valueint;
}

利用上述代码解析json对象得到的结果是:

1
2
3
4
5
6
7
8
type:41
dates[0]:20190926
dates[1]:20190927
dates[2]:20190928
node:0
begin:1568476800;end:1568480399
node:1
begin:1568480400;end:1568483999

小结

cJSON库简洁,使用方法易于理解,应用于嵌入式设备中进行简单数据存储,数据传输非常适合。