ESP8266学习笔记(8)——第三方库cJSON使用

一、JSON简介

JSON (JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。

1.1 JSON 语法规则

在 JS 语言中,一切都是对象。 因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:

● 对象表示为键值对
● 数据由逗号分隔
● 花括号保存对象
● 方括号保存数组

1.2 JSON 键/值对

JSON 键值对是用来保存 JS 对象的一种方式,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值:

{"firstName": "Json"}

二、添加cJSON

链接:https://pan.baidu.com/s/1t4hn6CHpqK94OJpk4b0Bjw 提取码:zyjb
cJSON.h 添加到工程的 include/ 目录下
cJSON.c 添加到工程的 user/ 目录下

三、生成JSON数据

流程:创建JSON结构体 --> 添加数据 --> 释放内存

3.1 创建JSON结构体

cJSON *pRoot = cJSON_CreateObject();                         // 创建JSON根部结构体
cJSON *pValue = cJSON_CreateObject();                        // 创建JSON子叶结构体

3.2 添加字符串类型数据

cJSON_AddStringToObject(pRoot,"mac","65:c6:3a:b2:33:c8");    // 添加字符串类型数据到根部结构体
cJSON_AddItemToObject(pRoot, "value",pValue);
cJSON_AddStringToObject(pValue,"day","Sunday");              // 添加字符串类型数据到子叶结构体

3.3 添加整型数据

cJSON_AddNumberToObject(pRoot,"number",2);                   // 添加整型数据到根部结构体

3.4 添加数组类型数据

3.4.1 整型数组

int hex[5]={51,15,63,22,96};
cJSON *pHex = cJSON_CreateIntArray(hex,5);                   // 创建整型数组类型结构体
cJSON_AddItemToObject(pRoot,"hex",pHex);                     // 添加整型数组到数组类型结构体

3.4.2 JSON对象数组

cJSON * pArray = cJSON_CreateArray();                        // 创建数组类型结构体
cJSON_AddItemToObject(pRoot,"info",pArray);                  // 添加数组到根部结构体
cJSON * pArray_relay = cJSON_CreateObject();                 // 创建JSON子叶结构体
cJSON_AddItemToArray(pArray,pArray_relay);                   // 添加子叶结构体到数组结构体            
cJSON_AddStringToObject(pArray_relay, "relay", "on");        // 添加字符串类型数据到子叶结构体

3.5 格式化JSON对象

char *sendData == cJSON_Print(pRoot);                        // 从cJSON对象中获取有格式的JSON对象
os_printf("data:%s\n", sendData);                            // 打印数据

生成JSON格式:

{
    "mac": "65:c6:3a:b2:33:c8",
    "value": 
     {
        "day": "Sunday"                
     },
    "number": 2,
    "hex": [51,15,63,22,96],
    "info": 
    [
        {
            "relay": "on"        
        }
    ]
}

3.6 释放内存

cJSON_free((void *) sendData);                             // 释放cJSON_Print ()分配出来的内存空间
cJSON_Delete(pRoot);                                       // 释放cJSON_CreateObject ()分配出来的内存空间

这里说明一下,我们前面调用了3次cJSON_CreateObject (),最后只需要针对root调用一次释放即可,因为后面创建的对象也是挂接在root上的。

四、解析JSON数据

流程:判断JSON格式 --> 解析数据 --> 释放内存

4.1 判断是否JSON格式

// receiveData是要剖析的数据
//首先整体判断是否为一个json格式的数据
cJSON *pJsonRoot = cJSON_Parse(receiveData);
//如果是否json格式数据
if (pJsonRoot !=NULL)
{
    ···
}

4.2 解析字符串类型数据

char bssid[23] = {0};
cJSON *pMacAdress = cJSON_GetObjectItem(pJsonRoot, "mac");    // 解析mac字段字符串内容
if (!pMacAdress) return;                                      // 判断mac字段是否json格式
else
{
    if (cJSON_IsString(pMacAdress))                           // 判断mac字段是否string类型
    {
        strcpy(bssid, pMacAdress->valuestring);               // 拷贝内容到字符串数组
    }
}

4.3 解析子叶结构体

char strDay[23] = {0};
cJSON *pValue = cJSON_GetObjectItem(pJsonRoot, "value");      // 解析value字段内容
if (!pValue) return;                                          // 判断value字段是否json格式
else
{
    cJSON *pDay = cJSON_GetObjectItem(pValue, "day");         // 解析子节点pValue的day字段字符串内容
    if (!pDay) return;                                        // 判断day字段是否json格式
    else
    {
        if (cJSON_IsString(pDay))                             // 判断day字段是否string类型
        {
            strcpy(strDay, pDay->valuestring);                // 拷贝内容到字符串数组
        }
    }
}

4.4 解析整型数组数据

cJSON *pArry = cJSON_GetObjectItem(pJsonRoot, "hex");        // 解析hex字段数组内容
if (!pArry) return;                                          // 判断hex字段是否json格式
else
{
    int arryLength = cJSON_GetArraySize(pArry);              // 获取数组长度
    int i;
    for (i = 0; i < arryLength; i++)
    {                                                        // 打印数组内容
        os_printf("cJSON_GetArrayItem(pArry, %d)= %d\n",i,cJSON_GetArrayItem(pArry, i)->valueint);        
    }
}

4.5 解析JSON对象数组数据

cJSON *pArryInfo = cJSON_GetObjectItem(pJsonRoot, "info");   // 解析info字段数组内容
cJSON *pInfoItem = NULL;
cJSON *pInfoObj = NULL;
char strRelay[23] = {0};
if (!pArryInfo) return;                                      // 判断info字段是否json格式
else
{
    int arryLength = cJSON_GetArraySize(pArryInfo);          // 获取数组长度
    int i;
    for (i = 0; i < arryLength; i++)
    {
        pInfoItem = cJSON_GetArrayItem(pArryInfo, i);        // 获取数组中JSON对象
        if(NULL != pInfoItem)
        {
            pInfoObj = cJSON_GetObjectItem(pInfoItem,"relay");// 解析relay字段字符串内容   
            if(pInfoObj)
            {
                strcpy(strRelay, pInfoObj->valuestring);      // 拷贝内容到字符串数组
            }
        }                                                   
    }
}

解析JSON数据:

{
    "mac": "65:c6:3a:b2:33:c8",
    "value": 
     {
        "day": "Sunday"                
     },
    "number": 2,
    "hex": [51,15,63,22,96],
    "info": 
    [
        {
            "relay": "on"        
        }
    ]
}

4.6 释放内存

cJSON_Delete(pJsonRoot);                                      // 释放cJSON_Parse()分配出来的内存空间

五、常用库函数

  1. 从给定的JSON字符串中得到cJSON对象
    cJSON *cJSON_Parse(const char *value)
  2. 从cJSON对象中获取有格式的JSON对象
    char *cJSON_Print(cJSON *item)
  3. 删除cJSON对象,释放链表占用的内存空间
    void cJSON_Delete(cJSON *c)
  4. 获取cJSON对象数组成员的个数
    int cJSON_GetArraySize(cJSON *array)
  5. 根据下标获取cJSON对象数组中的对象
    cJSON *cJSON_GetArrayItem(cJSON*array,int item)
  6. 根据键获取对应的值(cJSON对象)
    cJSON *cJSON_GetObjectItem(cJSON*object,const char *string)
  7. 新增一个字符串类型字段到JSON格式的数据
    cJSON_AddStringToObject(object,name,s)
  8. 新增一个新的子节点cJSON到根节点
    void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)

• 由 Leung 写于 2019 年 1 月 29 日

• 参考:Esp8266 进阶之路28 【高级篇】教你轻松自如使用cJson在乐鑫 esp8266
    cJSON的结构与常用函数说明

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,084评论 1 32
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,072评论 0 3
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,894评论 2 89
  • 史上最全的iOS面试题及答案 迷途的羔羊--专为路痴量身打造的品牌。史上最精准的定位。想迷路都难!闪电更新中......
    南虞阅读 1,493评论 0 8
  • 忠诚 忠诚是作为一名员工应该具备的最起码的品得,也是一种责任!对于一个忠诚的员工,除了做好份内的事,任何时候,都不...
    Lzr_2017阅读 116评论 0 2