本文主要是C语言基础——cJSON简介与使用的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
PC端开发环境 Windows Windows11 Ubuntu Ubuntu20.04.2的64位版本 VMware® Workstation 17 Pro 17.6.0 build-24238078 终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license)) Win32DiskImager Win32DiskImager v1.0 Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板 uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) linux内核 linux-4.15(NXP官方提供)
点击查看本文参考资料
点击查看相关文件下载
一、cJSON简介 1. cJSON是什么? cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。项目托管在Github上,仓库地址在这里:GitHub - DaveGamble/cJSON: Ultralightweight JSON parser in ANSI C
2. 源码说明 我们可以用以下命令拉取cJSON源码:
1 git clone https://github.com/DaveGamble/cJSON.git
从Github拉取cJSON源码后,文件非常多,但是其中cJSON的源码文件只有两个:cJSON.h
和cJSON.c
。使用的时候,只需要将这两个文件复制到工程目录,然后包含头文件cJSON.h
即可,如下:
Tips:
我拉取的时候,最新一次提交是这个:DaveGamble/cJSON at 12c4bf1986c288950a3d06da757109a6aa1ece38
3. 源码编译 下载完源码后,仓库是有提供demo的,我们可以直接编译的,说明文档在这里:GitHub - DaveGamble/cJSON: Ultralightweight JSON parser in ANSI C :
1 2 3 4 5 6 7 # 生成Makefile文件 mkdir build cd build cmake .. # 编译 make
但是其实可以直接在源码目录下执行make命令进行编译,编译完毕会得到一个名为 cJSON_test 的可执行文件,我们直接./
就可以运行。
二、cJSON源码说明 1. cJSON数据结构 cJSON使用cJSON结构体来表示一个JSON数据 ,定义在 cJSON.h 中,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 typedef struct cJSON { struct cJSON *next ; struct cJSON *prev ; struct cJSON *child ; int type; char *valuestring; int valueint; double valuedouble; char *string ; } cJSON;
首先,它不是将一整段JSON数据抽象出来,而是将其中的一条JSON数据抽象出来,也就是一个键值对,用上面的结构体 strcut cJSON
来表示,其中用来存放值的成员列表如下:
1 2 3 4 5 6 int type; char *valuestring; int valueint; double valuedouble; char *string ;
其次,一段完整的JSON数据中由很多键值对组成,并且涉及到键值对的查找、删除、添加,所以使用链表来存储整段JSON数据,如上面的代码所示:
1 2 struct cJSON *next ; struct cJSON *prev ;
最后,因为JSON数据支持嵌套,所以一个键值对的值会是一个新的JSON数据对象(一条新的链表),也有可能是一个数组,方便起见,在cJSON中,数组也表示为一个数组对象,用链表存储,所以:
2. JSON数据封装 封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。
1 root = cJSON_CreateObject();
1 2 3 4 5 6 7 8 9 10 11 12 CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string ); CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
3. 输出JSON数据 一段完整的JSON数据就是一条长长的链表,那么,如何打印出这段JSON数据呢?cJSON提供了一个API,可以将整条链表中存放的JSON信息输出到一个字符串中:cJSON/cJSON.c at master · DaveGamble/cJSON · GitHub
1 2 3 4 5 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { return (char *)print(item, true , &global_hooks); }
print函数定义在这里:cJSON/cJSON.c at master · DaveGamble/cJSON · GitHub 。这里就不详细去了解了,就是一个遍历链表的过程。
使用cJSON_Print()函数打印JSON数据的时候,只需要接收该函数返回的指针地址即可。
4. JSON数据解析 解析JSON数据的过程,其实就是剥离一个一个链表节点(键值对)的过程。
(2)解析整段JSON数据,并将链表头结点地址返回,赋值给头指针
1 2 root = cJSON_Parse(JSON_data);
(3)根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址
1 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string )
(4)如果JSON数据的值是数组,使用下面的两个API提取数据
1 2 CJSON_PUBLIC(int ) cJSON_GetArraySize(const cJSON *array ); CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array , int index);
三、使用实例 1. JSON数据封装实例 1.1 JSON数据 这里设计一个JSON的结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 { "name" : "sumu" , "age" : 28 , "weight" : 69.8 , "address" : { "country" : "China" , "city" : "shanghai" , "zip-code" : 999999 } , "skill" : [ "c" , "html" , "Python" ] , "student" : false }
1.2 代码编写 这里只写主函数吧,剩下的就是cJSON.c 和cJSON.h
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 34 35 36 37 38 39 40 41 42 43 44 45 #include <stdio.h> #include "cJSON.h" int main (int argc, const char * argv[]) { cJSON* root = NULL ; cJSON* cjson_address = NULL ; cJSON* cjson_skill = NULL ; char * str = NULL ; root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "name" , "sumu" ); cJSON_AddNumberToObject(root, "age" , 28 ); cJSON_AddNumberToObject(root, "weight" , 69.8 ); cjson_address = cJSON_CreateObject(); cJSON_AddStringToObject(cjson_address, "country" , "China" ); cJSON_AddStringToObject(cjson_address, "city" , "shanghai" ); cJSON_AddNumberToObject(cjson_address, "zip-code" , 999999 ); cJSON_AddItemToObject(root, "address" , cjson_address); cjson_skill = cJSON_CreateArray(); cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" )); cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "html" )); cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" )); cJSON_AddItemToObject(root, "skill" , cjson_skill); cJSON_AddFalseToObject(root, "student" ); str = cJSON_Print(root); printf ("%s\n" , str); return 0 ; }
1.3 编译源码 1 gcc cJSON.c main.c -o cJSON_test
1.4 运行测试 我们直接执行即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 sumu@sumu-virtual-machine:~/7Linux/cJSON-master$ ./cJSON_test { "name": "sumu", "age": 28, "weight": 69.8, "address": { "country": "China", "city": "shanghai", "zip-code": 999999 }, "skill": ["C", "html", "Python"], "student": false }
1.5 数据链表关系图 我根据自己的理解画了个简图如下,来帮助理解:
2. JSON数据解析实例 2.1 JSON数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 char *JSON_data = "{ \ \"name\":\"sumu\", \ \"age\": 28, \ \"weight\": 69.8, \ \"address\": \ { \ \"country\": \"China\",\ \"city\": \"shagnhai\",\ \"zip-code\": 999999\ }, \ \"skill\": [\"c\", \"html\", \"Python\"],\ \"student\": false \ }" ;
2.2 代码编写 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #include <stdio.h> #include "../cJSON/cJSON.h" char *JSON_data = "{ \ \"name\":\"sumu\", \ \"age\": 28, \ \"weight\": 69.8, \ \"address\": \ { \ \"country\": \"China\",\ \"city\": \"shagnhai\",\ \"zip-code\": 999999\ }, \ \"skill\": [\"c\", \"html\", \"Python\"],\ \"student\": false \ }" ;int main (void ) { cJSON* root = NULL ; cJSON* cjson_name = NULL ; cJSON* cjson_age = NULL ; cJSON* cjson_weight = NULL ; cJSON* cjson_address = NULL ; cJSON* cjson_address_country = NULL ; cJSON* cjson_address_city = NULL ; cJSON* cjson_address_zipcode = NULL ; cJSON* cjson_skill = NULL ; cJSON* cjson_skill_item = NULL ; int skill_array_size = 0 ; int i = 0 ; cJSON* cjson_student = NULL ; root = cJSON_Parse(JSON_data); if (root == NULL ) { printf ("parse fail.\n" ); return -1 ; } cjson_name = cJSON_GetObjectItem(root, "name" ); cjson_age = cJSON_GetObjectItem(root, "age" ); cjson_weight = cJSON_GetObjectItem(root, "weight" ); printf ("name: %s\n" , cjson_name->valuestring); printf ("age:%d\n" , cjson_age->valueint); printf ("weight:%.1f\n" , cjson_weight->valuedouble); cjson_address = cJSON_GetObjectItem(root, "address" ); cjson_address_country = cJSON_GetObjectItem(cjson_address, "country" ); cjson_address_city = cJSON_GetObjectItem(cjson_address, "city" ); cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code" ); printf ("address-country:%s\naddress-city:%s\naddress-zipcode:%d\n" , cjson_address_country->valuestring, cjson_address_city->valuestring, cjson_address_zipcode->valueint); cjson_skill = cJSON_GetObjectItem(root, "skill" ); skill_array_size = cJSON_GetArraySize(cjson_skill); printf ("skill:[" ); for (i = 0 ; i < skill_array_size; i++) { cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i); printf ("%s," , cjson_skill_item->valuestring); } printf ("\b]\n" ); cjson_student = cJSON_GetObjectItem(root, "student" ); if (cjson_student->valueint == 0 ) { printf ("student: false\n" ); } else { printf ("student:error\n" ); } return 0 ; }
2.3 编译源码 1 gcc cJSON.c main.c -o cJSON_test
2.4 运行测试 1 2 3 4 5 6 7 8 9 sumu@sumu-virtual-machine:~/7Linux/cJSON-master$ ./cJSON_test name: sumu age:28 weight:69.8 address-country:China address-city:shagnhai address-zipcode:999999 skill:[c,html,Python] student: false
参考资料
cJSON使用详细教程 | 一个轻量级C语言JSON解析器-CSDN博客
C/C++ 使用cjson库 操作Json格式文件(创建、插入、解析、修改、删除)_c++ json-CSDN博客