STM32之cJSON的打包和解析

@fsw  March 29, 2019

最近在学习STM32,由于需要传输较多的参数因此想到json,虽然keil自带了json包,但是我还是想使用cjson,因为以前我在ESP8266上面也用到过。
cJSON的配置使用也很简单,如何把cJSON加入工程可以看这里https://blog.csdn.net/yannanxiu/article/details/52712078
使用test文件编译通过后,鉴于test里面的程序太复杂,我开始尝试删掉自己重新写。
文章最后机翻了下cJSON.h里面的一些函数
下面是cJSON的结构体

  /*The cJSON结构  */
typedef struct cJSON
{
        /* next / prev允许您遍历数组/对象链。或者,使用GetArraySize /GetArrayItem //GetObjectItem */
        struct cJSON *next;
        struct cJSON *prev;
        struct cJSON *child;// 数组或对象的子节点。
        int type;// 项目的类型,如上所述. 
        char *valuestring;//字符串
        int valueint;//整数值
        double valuedouble;//浮点值
        char *string;//项目的名称字符串,如果此项目是子项,或者在对象的子项列表中。
} cJSON;

1.使用cJSON库打包
json打包就是先创建一个数据包,然后往里面添加数据

    #include <stdio.h>
    #include <stdlib.h>
    #include "cJSON.h"
    #include "test.h"

int cJSON_main(void)
{
        cJSON * json =  cJSON_CreateObject();//创建数据包
        cJSON * item =  cJSON_CreateObject();//创建数据包(二级)

        cJSON_AddItemToObject(json, "group", cJSON_CreateString("noble team"));//添加数据
        cJSON_AddItemToObject(json, "member", item);//在json下添加子集item
        cJSON_AddItemToObject(item, "noble1", cJSON_CreateString("卡特-A259"));//给item添加数据
        cJSON_AddItemToObject(item, "noble2", cJSON_CreateString("凯瑟琳-B320"));
        cJSON_AddItemToObject(item, "noble3", cJSON_CreateString("俊-A266"));
        cJSON_AddItemToObject(item, "noble4", cJSON_CreateString("埃米尔-A239"));
        cJSON_AddItemToObject(item, "noble5", cJSON_CreateString("乔治-052"));
        cJSON_AddItemToObject(item, "noble6", cJSON_CreateString("斯巴达-B312"));

        printf("%s\n", cJSON_Print(json));
        cJSON_Delete(json);//释放内存
                    cJSON_Delete(item);
}

输出结果

{
"group":    "noble team",
"member":    {
    "noble1":    "卡特-A259",
    "noble2":    "凯瑟琳-B320",
    "noble3":    "俊-A266",
    "noble4":    "埃米尔-A239",
    "noble5":    "乔治-052",
    "noble6":    "斯巴达-B312"
   }
}

2.数据解析

介绍几个用到的重要函数

CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);

作用:将一个JSON数据包,按照cJSON结构体的结构序列化整个数据包,并在堆中开辟一块内存存储cJSON结构体
返回值:成功返回一个指向内存块中的cJSON的指针,失败返回NULL

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

作用:获取JSON字符串字段值
返回值:成功返回一个指向cJSON类型的结构体指针,失败返回NULL

char  *cJSON_Print(cJSON *item);

作用:将cJSON数据解析成JSON字符串,并在堆中开辟一块char*的内存空间存储JSON字符串
返回值:成功返回一个char*指针该指针指向位于堆中JSON字符串,失败返回NULL

void   cJSON_Delete(cJSON *c);

作用:释放位于堆中cJSON结构体内存

下面是json解析的全部代码

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
#include "test.h"
        
int cJSON_main(void)
{
        cJSON *json,*json_name,*json_passwd,*json_num;//JSON数据包创建
        char* out="{\"name\":\"jhon\",\"passwd\":\"123\",\"num\":1}";
        //printf("%s\n",out);
        json = cJSON_Parse(out); //解析成json形式
        if(json==NULL)
        {
            printf("json pack into cjson error...");//判断cJSON_Parse是否打包成功
        }
        else
        {                
            cJSON_Print(json);//打包成功调用cJSON_Print打印输出
            printf("ok\r\n");
        }
    
        json_name = cJSON_GetObjectItem( json , "name" );  //获取键值内容
        json_passwd = cJSON_GetObjectItem( json , "passwd" );
        json_num = cJSON_GetObjectItem( json , "num" );
 
        printf("name:%s\npasswd:%s\nnum:%d\n",json_name->valuestring,json_passwd->valuestring,json_num->valueint);
 
        cJSON_Delete(json);  //释放内存 
        free(out);
    }

输出结果

ok
name:jhon
passwd:123
num:1

下面是cJSON.h函数的解释机翻

  /*The cJSON结构  */
typedef struct cJSON
{
        /* next / prev允许您遍历数组/对象链。或者,使用GetArraySize 
  /GetArrayItem / GetObjectItem */
        struct cJSON *next;
        struct cJSON *prev;
        /* 数组或对象项将有一个子指针指向数组/对象中的项链。*/
        struct cJSON *child;
        /* 项目的类型,如上所述. */
        int type;
        /* item的字符串,如果type == cJSON_String并且type == cJSON_Raw  */
        char *valuestring;
        /* w入valueint是DEPRECATED,使用cJSON_SetNumberValue代替*/
        int valueint;
        /* 项目的编号,如果type == cJSON_Number */
        double valuedouble;
        /* 项目的名称字符串,如果此项目是子项,或者在对象的子项列表中。 */
        char *string;
} cJSON;

typedef struct cJSON_Hooks
{
            /* malloc / free是Windows上的CDECL,无论编译器的默认调用约定如何,因此请确保挂钩允许直接传递这些函数。*/
            void *(CJSON_CDECL *malloc_fn)(size_t sz);
            void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;

typedef int cJSON_bool;

/* 限制嵌套数组/对象在cJSON拒绝解析它们之前的深度 *这是为了防止堆栈溢出。*/
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000//最大深度1000
#endif

/* 将cJSON的版本作为字符串返回 */
CJSON_PUBLIC(const char*) cJSON_Version(void);

/* 为cJSON提供malloc,realloc和free函数 */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);

/*内存管理:调用者总是负责释放cJSON_Parse(带有cJSON_Delete)和cJSON_Print(带有stdlib free,cJSON_Hooks.free_fn或cJSON_free)的所有变体的结果。例外是cJSON_PrintPreallocated,调用者对缓冲区负有全部责任。*/
  /*提供一个JSON块,这将返回一个可以查询的cJSON对象。*/
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
/* ParseWithOpts允许您要求(并检查)JSON是否为空终止,并检索指向解析的最终字节的指针。*/
 /*如果在return_parse_end中提供ptr并且解析失败,则return_parse_end将包含指向错误的指针,因此将匹配cJSON_GetErrorPtr()。*/
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);

/*将cJSON实体渲染为文本以进行传输/存储。*/
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/*将cJSON实体渲染为文本以进行传输/存储,无需任何格式。*/
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/*使用缓冲策略将cJSON实体渲染为文本。预缓冲是对最终尺寸的猜测。猜测很好地减少了重新分配。fmt = 0给出无格式,= 1给出格式化*/
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/*使用已在内存中分配给定长度的缓冲区将cJSON实体渲染为文本。成功时返回1,失败时返回0。*/
   /*注意:cJSON在估计它将使用多少内存时并不总是100%准确,因此安全分配比实际需要多5个字节*/
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/*删除cJSON实体和所有子实体。*/
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);

/*返回数组(或对象)中的项数。*/
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/*从数组“array”中检索项目编号“index”。如果不成功则返回NULL。*/
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/*从对象获取项目“字符串”。不区分大小写。*/
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/*用于分析失败的解析。这将返回指向解析错误的指针。你可能需要回顾几个字符来理解它。当cJSON_Parse()成功时,cJSON_Parse()返回0时定义。*/
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/*检查项是否为字符串并返回其valuestring */
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);

/*这些函数检查项目的类型*/
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);

/*这些调用创建适当类型的cJSON项。*/
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);

/*创建一个字符串,其中valuestring引用一个字符串,它不会被cJSON_Delete 释放*/
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/ *创建一个只引用它的元素的对象/数组它们不会被cJSON_Delete释放 */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);

/*这些实用程序创建一个计数项数组。*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);

/*将项附加到指定的数组/对象。*/
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/*当string绝对是const(即文字,或者说好)时使用它,并且肯定会在cJSON对象中存活。*警告:使用此功能时,请务必检查(item-> type&cJSON_StringIsConst)为零之前,写入`item-> string` */
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/*将对项的引用附加到指定的数组/对象。如果要将现有cJSON添加到新的cJSON,但不想破坏现有的cJSON,请使用此选项。*/
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);

/*从数组/对象中删除/分离项目。*/
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);

/*更新数组项。*/
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /*将预先存在的项目向右移动。*/
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);

/*复制一个cJSON项目*/
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate将在你传递的新内存中创建一个新的,相同的cJSON项目需要被释放。使用recurse!= 0,它将复制连接到该项目的所有子项。从Duplicate返回时,item-> next和 - > prev指针始终为零。递归地比较两个cJSON项的相等性。如果a或b为NULL或无效,则它们将被视为不相等。 case_sensitive确定对象键是否区分大小写(1)或不区分大小写(0)*/

CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper函数用于同时创建和添加项目到对象。它们返回添加的项目或失败时为NULL。*/
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);

/*当分配一个整数值时,它也需要传播到有价值的值。*/
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/*用于迭代数组或对象的宏*/
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))

/*cJSON_SetNumberValue宏的助手*/
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)

/* malloc / free对象使用已使用cJSON_InitHooks设置的malloc / free函数*/
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
阅读量:686

添加新评论