项目使用之cJSON

项目为什么使用cJSON?

在一个偶然的开源项目中,该项目主要目的是通过ESP8266从网页上获取相关数据信息。当仔细地看完这个开源项目时,此时脑海中为什么使用cJSON这种轻量级的数据交换格式?我觉得该项目中使用cJSON的原因有如下:1.易于人阅读和编码,同时也易于机器的解析和生成。2.对于IOT设备来说,进行一次的数据交换必然不需要一次传输大量地数据,如果一次传输大量的数据对于微处理器的处理也是有要求地;3.网页端往往使用JavaScript Object 编写。接下来通过本篇文章详细地学习在嵌入式如何使用cJSON用于数据的传输。

cJSON数据格式使用详解

cJSON简述

cJSON是以标准C编码的一种轻量级的数据交换格式。同时也是一个超轻巧,携带方便,单文件,简单的JSON解析器。cJSON开源项目位置点击打开链接,更加详细的解释和示例请查看https://www.json.org/json-en.html主页。cJSON目前来说,就只有两个文件,cJSON.c和cJSON.h文件。直接把这里个文件添加到项目中。

cJSON结构体

typedef struct cJSON
{
    struct cJSON *next, *prev;
    struct cJSON *child;

    int type;

    char *valuestring;
    int valueint;
    double valuedouble;
    
    char *string;
}cJSON;

结构体几点说明:

  1. cJSON结构体为一个双向链表,并可通过child指针访问下一层。
  2. type变量决定数据项类型(键的类型),数据项可以是字符串可以是整型,也可以是浮点型。如果是整型值得话可从valueint,如果是浮点型的话可从vauluedouble取出,依次类推。
  3. string可理解为节点的名称,综合此处的第2点可理解为“键”的名称。
  4. 如果是对象或者数组,采用的是双向链表来实现,链表中的每一个节点表示数组中的一个元素或者对象中的一个字段。其中child表示头结点,next、prev分别表示下一个节点和前一个节点。valuestring、valueint、valuedouble分别表示字符串、整数、浮点数的字面量。

cJSON的三种语法

键/值对 key:value,用半角冒号分割。比如 "name":"Faye" 

文档对象JSON对象写在花括号中,可以包含多个键/值对。比如{ "name":"Faye" ,"address":"北京" }。 

数组JSON数组在方括号中书写:数组成员可以是对象,值,也可以是数组(只要有意)。 {"love": ["乒乓球","高尔夫","斯诺克","羽毛球","LOL","撩妹"]} 

cJSON各个API的使用

  • #define cJSON_False (1 << 0)

    #define cJSON_True (1 << 1)

    #define cJSON_NULL (1 << 2)

    #define cJSON_Number (1 << 3)

    #define cJSON_String (1 << 4)

    #define cJSON_Array (1 << 5)

    #define cJSON_Object (1 << 6)

     

    #define cJSON_IsReference 256

    #define cJSON_StringIsConst 512

    这些宏定义是对结构体type的值定义,处理时只需要将type的值&255进行位运算,即可得到json里储存的数据类型。

  • * The cJSON structure: */

    typedef struct cJSON {

    struct cJSON *next,*prev;  //同一级元素使用链表存储

    struct cJSON *child;           //如果是一个object或array的话,child为第一个儿子的指针

    int type;                               //value的类型

    char *valuestring;                //如果这个value是字符串类型,则此处为字符串值

    int valueint;                          //如果是数字的话,整数值

    double valuedouble;             //如果是数字的话,浮点数值

    char *string;                          //json对象的名称

    } cJSON;

  • cJSON内存管理:

    hook管理函数:

    在 c 语言中内存一般是 malloc 和 free 的。

    为了方便用户自由的管理内存, cjson 使用 Hook 技术来让使用者可以自定义内存管理函数。

    即用户自定义 malloc 和 free.

    具体实现方式可以参考下面的代码, 默认使用系统的 malloc 和 free 函数, 用过 cJSON_InitHooks 函数可以替换成用户自定义的 malloc 和 free 函数。

    typedef struct cJSON_Hooks {

    void *(*malloc_fn)(size_t sz);

    void (*free_fn)(void *ptr);

    } cJSON_Hooks;

    /* 对cJSON提供的分配,重分配,释放内存初始化函数 */

  • 各种API调用

    /* 将普通的json字符串处理成json对象,注意:使用完后需要将json指针释放*/

    extern cJSON *cJSON_Parse(const char *value);

    /*将cjson格式的数据,转换为普通字符串的新式,虽然json格式的数据也是一个字符串的样子,但这时候还是无法当成普通的字符串使用,注意:使用完后需要将json指针释放*/

    extern char *cJSON_Print(cJSON *item);

    /*将cjson格式的数据,以没有格式的形式转换成普通的字符串:也就是字符串中间不会有"\n" "\t"之类的东西存在,注意:使用完后需要将json指针释放*/

    extern char *cJSON_PrintUnformatted(cJSON *item);

    /*使用缓冲策略将cJSON实体呈现为文本。预缓冲是对最终大小的猜测。猜测良好可以减少重新分配。fmt=0给出未格式化,=1给出格式化*/

    extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);

    /*释放内存*/

    extern void cJSON_Delete(cJSON *c);

    /*获取数组里面元素的个数,指针array是一个指向数组的对象*/

    extern int cJSON_GetArraySize(cJSON *array);

    /*获取数组里面的元素,这个元素也可能是对象,item是对应元素的下标*/

    extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);

    /*获取键值内容(对象里面的对象),用一个新的 json 指针,指向该对象*/

    extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

    /*判断是否有key键值是string的项,如果有返回1,否则返回0*/

    extern int cJSON_HasObjectItem(cJSON *object,const char *string);

    /*当使用cJSON_Prase()函数解析数据时,如果失败就可以调用该函数,该函数会返回错误的原因*/

    extern const char *cJSON_GetErrorPtr(void);

    /* 这些是构造json的一些API */

    extern cJSON *cJSON_CreateNull(void); //创建一个空对象,暂时保留以后可能要用到

    extern cJSON *cJSON_CreateTrue(void); //创建一个true的对象

    extern cJSON *cJSON_CreateFalse(void); //创建一个false的对象

    extern cJSON *cJSON_CreateBool(int b); //创建一个bool对象

    extern cJSON *cJSON_CreateNumber(double num); //创建一个数字类型的对象

    extern cJSON *cJSON_CreateString(const char *string); //创建一个字符串类型的对象

    extern cJSON *cJSON_CreateArray(void); //创建一个数组类型的对象

    extern cJSON *cJSON_CreateObject(void); //创建一个根对象,它是cjson格式的头结点

    /* 创建数组其中里面可以设定为不同的数据类型*/

    extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); //整形

    extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); //浮点型

    extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); //double型

    extern cJSON *cJSON_CreateStringArray(const char **strings,int count); //字符串类型

    /* 向数组中添加对象*/

    extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);

    /*向对象中添加键值对,值的类型与相关函数有关*/

    extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);

    /*当字符串肯定是const(即一个文字,或者与常量一样好),并且肯定能在cJSON对象中存活下来时,可以使用这个*/

    extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);

    /* 将对项的引用附加到指定的数组/对象。当您想要将现有的cJSON添加到新的cJSON中,但又不想破坏现有的cJSON时,请使用此选项 */

    extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);

    extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);

    /* 从数组/对象中删除/分离项 */

    extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);

    extern void cJSON_DeleteItemFromArray(cJSON *array,int which);

    extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);

    extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);

    /* 更新数组项 */

    extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);//右移

    extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);

    extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);

    /* 复制一个cJSON项 */

    extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);

    /* Duplicate将在新的内存中创建与传递的cJSON相同的新项需要释放。递归!=0,它将复制与项连接的任何子节点。item->next和->prev指针从Duplicate返回时总是为0。*/

    /* ParseWithOpts允许您要求(并检查)JSON终止为空,并检索到解析的最后一个字节的指针 */

    /* 如果在return_parse_end中提供ptr,并且解析失败,那么return_parse_end将包含一个指向错误的指针。如果没有,那么cJSON_GetErrorPtr()就可以了。 */

    extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);

    extern void cJSON_Minify(char *json);

    /* 用于快速创建内容的宏. */

    #define cJSON_AddNullToObject(object,name)

    #define cJSON_AddTrueToObject(object,name)

    #define cJSON_AddFalseToObject(object,name)

    #define cJSON_AddBoolToObject(object,name,b)

    #define cJSON_AddNumberToObject(object,name,n)

    #define cJSON_AddStringToObject(object,name,s)

使用例子

先写分支在综合,先写子类在写父类

 

{
    "application": "sqlite-server",
    "port": "1",
    "destination": "sqlite-client",
    "payload":{
        "code" : 1002,
        "id": "010101010101010",
        "ep":ll,
        "pid":4246,
        "did":528,
        "serial:" 12004,
        "control:"{
            "on":"false",
            "cmd":"inser into message value ('good today XXX!')",
            "bri":100,
            "sat":100,
            "hue":100,
            "ctp":100
        }
    }
}
cJSON *root = cJSON_CreateObject();
if(!root) return -1;

cJSON_AddStringToObject(root, "application", application);
cJSON_AddStringToObject(root, "port", gateway_port_string);
cJSON_AddStringToObject(root, "destination", destiantion);

cJSON *payload = cJSON_CreateObject();
if(!payload) return -1;

cJSON_AddItemToObject(root, "payload", payload);
cJSON_AddNumberToObject(payload , "code", 1002);
cJSON_AddStringToObject(payload , "id", "0101010101010");
cJSON_AddNumberToObject(payload , "ep", 11);
cJSON_AddNumberToObject(payload , "pid", 4923);
cJSON_AddNumberToObject(payload , "did", 527);
cJSON_AddNumberToObject(payload , "serial"12004);

cJSON *control = cJSON_CreateObject();
if(!control) return -1;

cJSON_AddItemToObject(payload, "control", control);
cJSON_AddStringToObject(control , "on", "false");
cJSON_AddStringToObject(control, "cmd", "inser into message values ('good today xxx!')");
cJSON_AddNumberToObject(control, "bri", 100);
cJSON_AddNumberToObject(control, "sat", 100);
cJSON_AddNumberToObject(control, "hue", 100);
cJSON_AddNumberToObject(control, "ctp", 100);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值