前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >妙哉!cJSON设计思想解读及封装JSON数据方法示例

妙哉!cJSON设计思想解读及封装JSON数据方法示例

作者头像
Mculover666
发布2020-07-16 11:45:40
2.8K0
发布2020-07-16 11:45:40
举报
文章被收录于专栏:TencentOS-tiny

看了cJSON的源码后,惊呼其设计之巧妙,其代码之简洁,其使用之方便!只有两个文件cJSON.h和cJSON.c,非常适合学习C语言中的链表。

1. JSON 与 cJSON

JSON —— 轻量级的数据格式

JSON[1] 全称 JavaScript Object Notation,即 JS 对象简谱,是一种轻量级的数据格式。

它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。

JSON 语法规则

JSON 对象是一个无序的"名称/值"键值对的集合:

  • 以"{"开始,以"}"结束,允许嵌套使用;
  • 每个名称和值成对出现,名称和值之间使用":"分隔;
  • 键值对之间用","分隔
  • 在这些字符前后允许存在无意义的空白符;

对于键值,可以有如下值:

  • 一个新的 json 对象
  • 数组:使用"["和"]"表示
  • 数字:直接表示,可以是整数,也可以是浮点数
  • 字符串:使用引号"表示
  • 字面值:false、null、true 中的一个(必须是小写)

示例如下:

代码语言:javascript
复制
{
    "name": "mculover666",
    "age": 22,
    "weight": 55.5
    "address":
    {
        "country": "China",
        "zip-code": 111111
    },
    "skill": ["c", "Java", "Python"],
    "student": false
}

cJSON

cJSON 是一个使用 C 语言编写的 JSON 数据解析器,具有超轻便,可移植,单文件的特点,使用 MIT 开源协议。

cJSON 项目托管在 Github 上,仓库地址如下:

https://github.com/DaveGamble/cJSON

使用 Git 命令将其拉取到本地:

代码语言:javascript
复制
git clone https://github.com/DaveGamble/cJSON.git

从 Github 拉取 cJSON 源码后,文件非常多,但是其中 cJSON 的源码文件只有两个:

  • cJSON.h
  • cJSON.c

使用的时候,只需要将这两个文件复制到工程目录,然后包含头文件cJSON.h即可,如下:

代码语言:javascript
复制
#include "cJSON.h"

2. cJSON 数据结构和设计思想

cJSON 的设计思想从其数据结构上就能反映出来。

cJSON 使用 cJSON 结构体来表示一个 JSON 数据,定义在cJSON.h中,源码如下:

代码语言:javascript
复制
/* The cJSON structure: */
typedef struct cJSON
{
    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *next;
    struct cJSON *prev;
    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    struct cJSON *child;

    /* The type of the item, as above. */
    int type;

    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    /* The item's number, if type==cJSON_Number */
    double valuedouble;

    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    char *string;
} cJSON;

cJSON 的设计很巧妙。

首先,它不是将一整段 JSON 数据抽象出来,而是将其中的一条 JSON 数据抽象出来,也就是一个键值对,用上面的结构体 strcut cJSON 来表示,其中用来存放值的成员列表如下:

  • String:用于表示该键值对的名称;
  • type:用于表示该键值对中值的类型;
  • valuestring:如果键值类型(type)是字符串,则将该指针指向键值;
  • valueint:如果键值类型(type)是整数,则将该指针指向键值;
  • valuedouble:如果键值类型(type)是浮点数,则将该指针指向键值;

其次,一段完整的 JSON 数据中由很多键值对组成,并且涉及到键值对的查找、删除、添加,所以使用链表来存储整段 JSON 数据,如上面的代码所示:

  • next指针:指向下一个键值对
  • prev指针指向上一个键值对

最后,因为 JSON 数据支持嵌套,所以一个键值对的值会是一个新的 JSON 数据对象(一条新的链表),也有可能是一个数组,方便起见,在 cJSON 中,数组也表示为一个数组对象,用链表存储,所以:

在键值对结构体中,当该键值对的值是一个嵌套的 JSON 数据或者一个数组时,由child指针指向该条新链表。

3. JSON 数据封装

封装方法

封装 JSON 数据的过程,其实就是创建链表和向链表中添加节点的过程。

首先来讲述一下链表中的一些术语:

  • 头指针:指向链表头结点的指针;
  • 头结点:不存放有效数据,方便链表操作;
  • 首节点:第一个存放有效数据的节点;
  • 尾节点:最后一个存放有效数据的节点;

明白了这几个概念之后,我们开始讲述创建一段完整的 JSON 数据,即如何创建一条完整的链表。

  • ① 创建头指针:
代码语言:javascript
复制
 cJSON* cjson_test = NULL;
  • ② 创建头结点,并将头指针指向头结点:
代码语言:javascript
复制
cjson_test = cJSON_CreateObject();
  • ③ 尽情的向链表中添加节点:
代码语言:javascript
复制
cJSON_AddNullToObject(cJSON * const object, const char * const name);

cJSON_AddTrueToObject(cJSON * const object, const char * const name);

cJSON_AddFalseToObject(cJSON * const object, const char * const name);

cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);

cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);

cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);

cJSON_AddObjectToObject(cJSON * const object, const char * const name);

cJSON_AddArrayToObject(cJSON * const object, const char * const name);

输出 JSON 数据

上面讲述,一段完整的 JSON 数据就是一条长长的链表,那么,如何打印出这段 JSON 数据呢?

cJSON 提供了一个 API,可以将整条链表中存放的 JSON 信息输出到一个字符串中:

代码语言:javascript
复制
(char *) cJSON_Print(const cJSON *item);

使用的时候,只需要接收该函数返回的指针地址即可。

封装数据和打印数据示例

单纯的讲述方法还不够,下面用一个例子来说明,封装出开头给出的那段 JSON 数据:

代码语言:javascript
复制
#include <stdio.h>
#include "cJSON.h"

int main(void)
{
    cJSON* cjson_test = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_skill = NULL;
    char* str = NULL;

    /* 创建一个JSON数据对象(链表头结点) */
    cjson_test = cJSON_CreateObject();

    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON_AddStringToObject(cjson_test, "name", "mculover666");

    /* 添加一条整数类型的JSON数据(添加一个链表节点) */
    cJSON_AddNumberToObject(cjson_test, "age", 22);

    /* 添加一条浮点类型的JSON数据(添加一个链表节点) */
    cJSON_AddNumberToObject(cjson_test, "weight", 55.5);

    /* 添加一个嵌套的JSON数据(添加一个链表节点) */
    cjson_address = cJSON_CreateObject();
    cJSON_AddStringToObject(cjson_address, "country", "China");
    cJSON_AddNumberToObject(cjson_address, "zip-code", 111111);
    cJSON_AddItemToObject(cjson_test, "address", cjson_address);

    /* 添加一个数组类型的JSON数据(添加一个链表节点) */
    cjson_skill = cJSON_CreateArray();
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" ));
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java" ));
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" ));
    cJSON_AddItemToObject(cjson_test, "skill", cjson_skill);

    /* 添加一个值为 False 的布尔类型的JSON数据(添加一个链表节点) */
    cJSON_AddFalseToObject(cjson_test, "student");

    /* 打印JSON对象(整条链表)的所有数据 */
    str = cJSON_Print(cjson_test);
    printf("%s\n", str);

    return 0;
}

编译运行:

代码语言:javascript
复制
gcc cJSON.c example1.c -o example1.exe

实验结果如图:

实验结果

该 JSON 数据链表的关系如图:

JSON关系图

参考资料

[1] JSON: https://www.json.org/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Mculover666 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. JSON 与 cJSON
    • JSON —— 轻量级的数据格式
      • JSON 语法规则
        • cJSON
        • 2. cJSON 数据结构和设计思想
        • 3. JSON 数据封装
          • 封装方法
            • 输出 JSON 数据
              • 封装数据和打印数据示例
                • 参考资料
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档