cJSON库 ======= 作者:陈之敏 时间:2020年08月15日 关键字:csdk、RDA8910、二次开发、cJSON 目录 ---- `点击这里查看所有博文 `__   最近听说有的小伙伴看了我的教程后,有一些问题都跑到官方的gitee上面去问去了。导致官方的人没搞懂问的是啥,小伙伴们也没能知道自己想要的答案。给大家造成了困扰,这里我说声抱歉。   既然出现了这个问题,我这里就声明一下,本系列教程所涉及的内容(demo)不是官方的作品。我个人觉得官方的demo内容太多太全,往往都是把一个模块内所有的东西全部放在一起。这样的话对新手不是很友好,阅读起来也比较费劲。我就把官方的部分demo进行相关的简化,并推出教程这样的话可能会对新手朋友们有一定的帮助。   有时候周末闲暇时间我也会加上一些我觉得好玩的模块在里面,这些可能在官方的demo都没有,比如cJSON、PAHO-MQTT、http-client。   这就是官方的代码仓库。 .. code:: c git clone --recursive https://gitee.com/openLuat/Luat_CSDK_Air724U.git   当然各位小伙伴在看本教程时,我建议还是使用我下面提供的仓库比较好,看完之后在迁移到官方的仓库⇧。 .. code:: c git clone --recursive https://gitee.com/chenxiahuaxu/RDA8910_CSDK.git   再看本教程过程中如果遇到了问题,可以在本人的代码仓库下面评论。也可以在本人的\ `博客 `__\ 下面评论。我要是看到的话,并且这个问题在我的能力范围的话我会尽力解答的(非官方,不要对我要求太多哦,要求太多我可能就不管啦)。 一、前言 --------   JSON(JavaScript Object Notation,JavaScript对象表示法)是一种由道格拉斯·克罗克福特构想和设计、轻量级的数据交换语言,该语言以易于让人阅读的文字为基础,用来传输由属性值或者序列性的值组成的数据对象。尽管JSON是JavaScript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。   JSON 数据格式与语言无关,脱胎自JavaScript,但当前很多编程语言都支持 JSON 格式数据的生成和解析。JSON 的官方 MIME 类型是 application/json,文件扩展名是 .json。   JSON 解析器和 JSON 库支持许多不同的编程语言。 JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。 由于这种相似性, 无需解析器, JavaScript 程序能够使用内建的 eval() 函数, 用 JSON 数据来生成原生的 JavaScript 对象。   JSON 是存储和交换文本信息的语法。 类似 XML。 JSON 比 XML 更小、 更快, 更易解析。   JSON 具有自我描述性, 语法简洁, 易于理解。   关于JSON的介绍,需要了解的兄弟们请参考我的\ ``合宙Air模块Luat开发``\ 专题,\ ``第10篇``\ 文章\ `JSON字符串的生成与解析 `__\ 。 |在这里插入图片描述|   总之就是一句话。JSON很常见,虽然与 JavaScript 紧密相连,但 JSON 与语言无关,JSON 使用与其他语言类似的约定(例如,C,C ++,Java,Perl ,Lua和 Python),使 JSON 成为理想的数据交换语言。   在c语言中同样有很多用于JSON生成和解析的库,其中免费开源好用的当属cJSON。那么今天我们就来耍一下。   cJSON库文件在demo里面的\ ``cJSON``\ 例程有提供,直接拷贝一份出来即可使用。不需要做其他的改动。 二、编写测试程序 ---------------- 2.1、了解本例程所用到的函数 ---------------------------   使用cJSON服务需要包含\ ``#include "cJSON.h""``\ 头文件,我们这里只用到了13个函数,分别是: >/**JSON解析 >提供一个JSON块,这将返回一个您可以查询的cJSON对象。 > @param ``value``\ :JSON字符串\ @return cJSON对象指针**/ - CJSON_PUBLIC(cJSON *) ``cJSON_Parse``\ (const char*\ value) .. /*\*\ *从JSON对象中获取键值对。不区分大小写。*\ @param ``object``\ :要查询的cJSON对象     ``string``\ :要查询的键值对 \*@return cJSON对象指针 \**/ - CJSON_PUBLIC(cJSON *) ``cJSON_GetObjectItem``\ (const cJSON* const object, const char \* const string) .. /*判断该对象是不是字符串类型*\ @param ``object``\ :要查询的cJSON对象 \*@return 真值,是字符串类型 \**/ - CJSON_PUBLIC(cJSON_bool) ``cJSON_IsString``\ (const cJSON \* const item); .. /*判断该对象是不是数字类型*\ @param ``object``\ :要查询的cJSON对象 \*@return 真值,是字数字类型 \**/ - CJSON_PUBLIC(cJSON_bool) ``cJSON_IsNumber``\ (const cJSON \* const item) .. /*获取数组(或对象)中的项目数。*\ @param ``object``\ :要查询的cJSON对象 \*@return 项目数 \**/ - CJSON_PUBLIC(int) ``cJSON_GetArraySize``\ (const cJSON \*array) .. /*删除cJSON结构。*\ @param ``object``\ :要删除的cJSON对象 \**/ - CJSON_PUBLIC(void) ``cJSON_Delete``\ (cJSON \*item) .. /*创建一个cJSON对象*\ @return 创建的对象 \**/ \* CJSON_PUBLIC(cJSON \*) ``cJSON_CreateObject``\ (void) /*添加一个字符串到cJSON对象中*\ @param ``object``\ :要添加的cJSON对象 *@param ``name``\ :要添加的键*\ @param ``string``\ :要添加的值 \*@return cJSON对象指针 \**/ - CJSON_PUBLIC(cJSON\ *) ``cJSON_AddStringToObject``\ (cJSON* const object, const char \* const name, const char \* const string); .. /*添加一个数字到cJSON对象中*\ @param ``object``\ :要添加的cJSON对象 *@param ``name``\ :要添加的键*\ @param ``number``\ :要添加的值 \*@return cJSON对象指针 \**/ - CJSON_PUBLIC(cJSON\ *) ``cJSON_AddNumberToObject``\ (cJSON* const object, const char \* const name, const double number) .. /*添加一个cJSON对象到cJSON对象中*\ @param ``object``\ :要添加的cJSON对象 *@param ``name``\ :要添加的键*\ @param ``item``\ :要添加的值 \*@return cJSON对象指针 \**/ - CJSON_PUBLIC(cJSON_bool) ``cJSON_AddItemToObject``\ (cJSON *object, const char*\ string, cJSON \*item); .. /*创建一个数组对象*\ @param ``numbers``\ :要创建的数组 *@param ``count``\ :数组的长度*\ @return 创建的对象 \**/ - CJSON_PUBLIC(cJSON *) ``cJSON_CreateIntArray``\ (const int*\ numbers, int count) .. /*将cJSON项目/实体/结构呈现为文本。*\ @param ``item``\ :cJSON对象 \*@return 字符串 \**/ - CJSON_PUBLIC(char *) ``cJSON_Print``\ (const cJSON*\ item) .. /*释放内存*\ @param ``object``\ :要释放的内存块 \**/ - CJSON_PUBLIC(void) ``cJSON_free``\ (void \*object); ## 2.2、编写cJSON解析程序   解析程序负责将一个json格式的字符串转换成cJSON对象,并在其中查找需要的键值对。要注意的是,查找完毕后需要删除\ ``cJSON_Parse``\ 函数创建的父节点。 .. code:: c // jsonRoot 是您要剖析的数据 //首先整体判断是否为一个json格式的数据 iot_debug_print("[cJSON_Test] cJSON_Parsing Start"); cJSON *pJsonRoot = cJSON_Parse(jsonRoot); //如果是否json格式数据 if (pJsonRoot != NULL) { iot_debug_print("[cJSON_Test] cJSON TRUE"); iot_debug_print("[cJSON_Test] cJSON:%s", jsonRoot); } else { iot_debug_print("[cJSON_Test] cJSON ERROR"); } //解析imei字段字符串内容 cJSON *pimeiAdress = cJSON_GetObjectItem(pJsonRoot, "imei"); //判断imei字段是否json格式 if (pimeiAdress) { //判断mac字段是否string类型 if (cJSON_IsString(pimeiAdress)) iot_debug_print("[cJSON_Test] get imeiAdress:%s", pimeiAdress->valuestring); } else iot_debug_print("[cJSON_Test] get imeiAdress failed"); //解析Num字段int内容 cJSON *pNumber = cJSON_GetObjectItem(pJsonRoot, "Num"); //判断Num字段是否存在 if (pNumber) { //判断mac字段是否数字整型类型 if (cJSON_IsNumber(pNumber)) iot_debug_print("[cJSON_Test] get Num:%d", pNumber->valueint); } else iot_debug_print("[cJSON_Test] get Num failed"); //解析value字段内容,判断是否为json cJSON *pValue = cJSON_GetObjectItem(pJsonRoot, "Value"); if (pValue) { //进一步剖析里面的name字段:注意这个根节点是 pValue cJSON *pName = cJSON_GetObjectItem(pValue, "name"); if (pName) { if (cJSON_IsString(pName)) iot_debug_print("[cJSON_Test] get value->Name:%s", pName->valuestring); } else iot_debug_print("[cJSON_Test] get pValue->pName failed"); //进一步剖析里面的age字段:注意这个根节点是 pValue cJSON *pAge = cJSON_GetObjectItem(pValue, "age"); if (pAge) { if (cJSON_IsNumber(pAge)) iot_debug_print("[cJSON_Test] get value->Age:%d", pAge->valueint); } else iot_debug_print("[cJSON_Test] get pValue->pAge failed"); //进一步剖析里面的blog字段:注意这个根节点是 pValue cJSON *pBlog = cJSON_GetObjectItem(pValue, "blog"); if (pBlog) { if (cJSON_IsString(pBlog)) iot_debug_print("[cJSON_Test] get value->pBlog:%s", pBlog->valuestring); } else iot_debug_print("[cJSON_Test] get pValue->pBlog failed"); } else iot_debug_print("[cJSON_Test] get pValue failed"); //剖析数组 cJSON *pArry = cJSON_GetObjectItem(pJsonRoot, "hexArry"); if (pArry) { //获取数组长度 int arryLength = cJSON_GetArraySize(pArry); iot_debug_print("[cJSON_Test] get arryLength:%d", arryLength); //逐个打印 int i; for (i = 0; i < arryLength; i++) iot_debug_print("[cJSON_Test] get cJSON_GetArrayItem(pArry, %d)= %d", i, cJSON_GetArrayItem(pArry, i)->valueint); } else iot_debug_print("[cJSON_Test] get pArry failed"); //释放内存 cJSON_Delete(pJsonRoot); iot_debug_print("[cJSON_Test] cJSON_Parsing Stop");   相比Luat中的json解析,cJSON用起来真的是太复杂了。 ## 2.3、编写cJSON生成程序   生成程序,首先创建一个空的对象(实际是一个链表),然后将不同的键值对依次插入。全部插入完成后,打印查看,最后删除\ ``cJSON_CreateObject``\ 函数创建的父对象\ ``pRoot`` 。 .. code:: c //取一下本地的station的mac地址,保存在全局变量tempMessage iot_debug_print("[cJSON_Test] cJSON_Generate Start"); cJSON *pRoot = cJSON_CreateObject(); //新增一个字段imei到根点,数值是tempMessage char tempMessage[] = "8661111111111111"; cJSON_AddStringToObject(pRoot, "imei", tempMessage); //新增一个字段number到根点,数值是2 cJSON_AddNumberToObject(pRoot, "number", 2020); cJSON *pValue = cJSON_CreateObject(); cJSON_AddStringToObject(pValue, "name", "cx"); cJSON_AddNumberToObject(pValue, "age", 17); cJSON_AddItemToObject(pRoot, "value", pValue); //数组初始化 int hex[5] = {11, 12, 13, 14, 15}; cJSON *pHex = cJSON_CreateIntArray(hex, 5); //创建一个长度为5的int型的数组json元素 cJSON_AddItemToObject(pRoot, "hex", pHex); //将数组元素添加进pRoot char *s = cJSON_Print(pRoot); iot_debug_print("[cJSON_Test] creatJson:%s", s); //释放内存 cJSON_free((void *)s); //释放内存 //cJSON_Delete(pHex); //释放内存 //cJSON_Delete(pValue); //释放内存 cJSON_Delete(pRoot); iot_debug_print("[cJSON_Test] cJSON_Generate Stop"); 三、编译并下载程序 ------------------   完整代码在这,自取。 .. code:: c /* * @Author: your name * @Date: 2020-05-19 14:05:32 * @LastEditTime: 2020-06-15 00:10:00 * @LastEditors: Please set LastEditors * @Description: In User Settings Edit * @FilePath: \RDA8910_CSDK\USER\user_main.c */ #include "string.h" //#include "cs_types.h" #include "osi_log.h" #include "osi_api.h" #include "am_openat.h" #include "am_openat_vat.h" #include "am_openat_common.h" #include "iot_debug.h" #include "iot_uart.h" #include "iot_os.h" #include "iot_gpio.h" #include "iot_pmd.h" #include "iot_adc.h" #include "iot_vat.h" #include "iot_network.h" #include "iot_socket.h" #include "cJSON.h" //#include "MQTTClient.h" HANDLE TestTask_HANDLE = NULL; #define jsonRoot "{\r\n" \ "\"imei\": \"8661111111111111\",\r\n" \ "\"Num\": 142,\r\n" \ "\"Value\": {\r\n" \ "\"name\": \"cx\",\r\n" \ "\"age\": 18,\r\n" \ "\"blog\": \"https://blog.csdn.net/weixin_44570083/article/details/104285283\"\r\n" \ "},\r\n" \ "\"hexArry\": [31, 56, 36, 1365, 263]\r\n" \ "}\r\n" //JSON解析 void cJSON_Parsing() { // jsonRoot 是您要剖析的数据 //首先整体判断是否为一个json格式的数据 iot_debug_print("[cJSON_Test] cJSON_Parsing Start"); cJSON *pJsonRoot = cJSON_Parse(jsonRoot); //如果是否json格式数据 if (pJsonRoot != NULL) { iot_debug_print("[cJSON_Test] cJSON TRUE"); iot_debug_print("[cJSON_Test] cJSON:%s", jsonRoot); } else { iot_debug_print("[cJSON_Test] cJSON ERROR"); } //解析imei字段字符串内容 cJSON *pimeiAdress = cJSON_GetObjectItem(pJsonRoot, "imei"); //判断imei字段是否json格式 if (pimeiAdress) { //判断mac字段是否string类型 if (cJSON_IsString(pimeiAdress)) iot_debug_print("[cJSON_Test] get imeiAdress:%s", pimeiAdress->valuestring); } else iot_debug_print("[cJSON_Test] get imeiAdress failed"); //解析Num字段int内容 cJSON *pNumber = cJSON_GetObjectItem(pJsonRoot, "Num"); //判断Num字段是否存在 if (pNumber) { //判断mac字段是否数字整型类型 if (cJSON_IsNumber(pNumber)) iot_debug_print("[cJSON_Test] get Num:%d", pNumber->valueint); } else iot_debug_print("[cJSON_Test] get Num failed"); //解析value字段内容,判断是否为json cJSON *pValue = cJSON_GetObjectItem(pJsonRoot, "Value"); if (pValue) { //进一步剖析里面的name字段:注意这个根节点是 pValue cJSON *pName = cJSON_GetObjectItem(pValue, "name"); if (pName) { if (cJSON_IsString(pName)) iot_debug_print("[cJSON_Test] get value->Name:%s", pName->valuestring); } else iot_debug_print("[cJSON_Test] get pValue->pName failed"); //进一步剖析里面的age字段:注意这个根节点是 pValue cJSON *pAge = cJSON_GetObjectItem(pValue, "age"); if (pAge) { if (cJSON_IsNumber(pAge)) iot_debug_print("[cJSON_Test] get value->Age:%d", pAge->valueint); } else iot_debug_print("[cJSON_Test] get pValue->pAge failed"); //进一步剖析里面的blog字段:注意这个根节点是 pValue cJSON *pBlog = cJSON_GetObjectItem(pValue, "blog"); if (pBlog) { if (cJSON_IsString(pBlog)) iot_debug_print("[cJSON_Test] get value->pBlog:%s", pBlog->valuestring); } else iot_debug_print("[cJSON_Test] get pValue->pBlog failed"); } else iot_debug_print("[cJSON_Test] get pValue failed"); //剖析数组 cJSON *pArry = cJSON_GetObjectItem(pJsonRoot, "hexArry"); if (pArry) { //获取数组长度 int arryLength = cJSON_GetArraySize(pArry); iot_debug_print("[cJSON_Test] get arryLength:%d", arryLength); //逐个打印 int i; for (i = 0; i < arryLength; i++) iot_debug_print("[cJSON_Test] get cJSON_GetArrayItem(pArry, %d)= %d", i, cJSON_GetArrayItem(pArry, i)->valueint); } else iot_debug_print("[cJSON_Test] get pArry failed"); //释放内存 cJSON_Delete(pJsonRoot); iot_debug_print("[cJSON_Test] cJSON_Parsing Stop"); } //JSON生成 void cJSON_Generate() { //取一下本地的station的mac地址,保存在全局变量tempMessage iot_debug_print("[cJSON_Test] cJSON_Generate Start"); cJSON *pRoot = cJSON_CreateObject(); //新增一个字段imei到根点,数值是tempMessage char tempMessage[] = "8661111111111111"; cJSON_AddStringToObject(pRoot, "imei", tempMessage); //新增一个字段number到根点,数值是2 cJSON_AddNumberToObject(pRoot, "number", 2020); cJSON *pValue = cJSON_CreateObject(); cJSON_AddStringToObject(pValue, "name", "cx"); cJSON_AddNumberToObject(pValue, "age", 17); cJSON_AddItemToObject(pRoot, "value", pValue); //数组初始化 int hex[5] = {11, 12, 13, 14, 15}; cJSON *pHex = cJSON_CreateIntArray(hex, 5); //创建一个长度为5的int型的数组json元素 cJSON_AddItemToObject(pRoot, "hex", pHex); //将数组元素添加进pRoot char *s = cJSON_Print(pRoot); iot_debug_print("[cJSON_Test] creatJson:%s", s); //释放内存 cJSON_free((void *)s); //释放内存 //cJSON_Delete(pHex); //释放内存 //cJSON_Delete(pValue); //释放内存 cJSON_Delete(pRoot); iot_debug_print("[cJSON_Test] cJSON_Generate Stop"); } //main函数 int appimg_enter(void *param) { //系统休眠 iot_os_sleep(20000); cJSON_Parsing(); cJSON_Generate(); return 0; } //退出提示 void appimg_exit(void) { OSI_LOGI(0, "application image exit"); } 四、分析结果 ------------   查看输出的日志信息,可以看到JSON的解析与生成都是正确的。 .. code:: c [00:11:49.559] [59599] [ 7216] [ ] [ ] [ ] OPEN/ : [cJSON_Test] cJSON_Parsing Start [00:11:49.559] [59603] [ 7217] [ ] [ ] [ ] OPEN/ : [cJSON_Test] cJSON TRUE [00:11:49.559] [59604] [ 7218] [ ] [ ] [ ] OPEN/ : [cJSON_Test] cJSON:{ "imei": "8661111111111111", "Num": 142, "Value": { "name": "cx", "age": 18, "blog": "https://blog.csdn.net/weixin_44570083/article/details/104285283" }, "hexArry": [31, 56, 36, 1365, 263] } [00:11:49.559] [59605] [ 7219] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get imeiAdress:8661111111111111 [00:11:49.559] [59606] [ 7220] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get Num:142 [00:11:49.559] [59606] [ 7221] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get value->Name:cx [00:11:49.559] [59606] [ 7222] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get value->Age:18 [00:11:49.559] [59607] [ 7223] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get value->pBlog:https://blog.csdn.net/weixin_44570083/article/details/104285283 [00:11:49.559] [59607] [ 7224] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get arryLength:5 [00:11:49.559] [59608] [ 7225] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get cJSON_GetArrayItem(pArry, 0)= 31 [00:11:49.559] [59608] [ 7226] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get cJSON_GetArrayItem(pArry, 1)= 56 [00:11:49.559] [59608] [ 7227] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get cJSON_GetArrayItem(pArry, 2)= 36 [00:11:49.559] [59608] [ 7228] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get cJSON_GetArrayItem(pArry, 3)= 1365 [00:11:49.559] [59609] [ 7229] [ ] [ ] [ ] OPEN/ : [cJSON_Test] get cJSON_GetArrayItem(pArry, 4)= 263 [00:11:49.559] [59609] [ 7230] [ ] [ ] [ ] OPEN/ : [cJSON_Test] cJSON_Parsing Stop [00:11:49.559] [59610] [ 7231] [ ] [ ] [ ] OPEN/ : [cJSON_Test] cJSON_Generate Start [00:11:49.559] [59619] [ 7232] [ ] [ ] [ ] OPEN/ : [cJSON_Test] creatJson:{ "imei": "8661111111111111", "number": 2020, "value": { "name": "cx", "age": 17 }, "hex": [11, 12, 13, 14, 15] } [00:11:49.615] [59620] [ 7233] [ ] [ ] [ ] OPEN/ : [cJSON_Test] cJSON_Generate Stop .. 不会下载的\ `点击这里 `__\ ,进去查看我的\ ``RDA8910 CSDK二次开发入门教程``\ 专题第一篇博文\ ``1、RDA8910CSDK二次开发:环境搭建``\ 里面讲了怎么下载 这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束 .. |在这里插入图片描述| image:: https://img-blog.csdnimg.cn/20200615004541627.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70