OpenHarmony之cJSON库使用介绍
一、前言
我们前面OpenHarmony设备配网 文章中,给大家提供的示例有使用cJSON解析和cJSON创建json数据的用法
那么有同学会提出疑问,我难道只能用cJSON库?
当然不是啊,你也可以用 json-parser、parson、jansson 等等三方库
回到正题,我们如何在OpenHarmony中,灵活熟练的使用cJSON库呢?
如果对JSON本身就不懂的,别急我们先带大家理解JSON,然后再去深入学习cJSON库的使用。
二、JSON理解
JSON(JavaScript Object Notation) 是一种
轻量级
的数据交换格式。
JSON采用完全独立于语言
的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等), 这些特性使JSON成为理想的数据交换语言。
我们可以在Be JSON中随便输入一个内容,查看报错的提示:
我们能看到期望的是如下格式的数据:
字符串、数字Number、NULL、BOOL、Json对象、Json数组,这些格式的数据
那么我们在JSON中,常用的有(Json对象、Json数组)
2种数据格式:
Json对象
Json数组
1、Json对象
Json对象使用的是
{ }
来描述,每个 Json 对象中都可以存储若干个元素,每一个元素都对应一个键值对(key:value 结构),元素和元素之间使用逗号间隔
key必须是字符串,value值类型可选,如:字符串、数字、Boolean、NULL、Json对象、Json数组
{
"count": 100,
"flag": true,
"paras": {
"Light": "ON",
"Motor": "OFF"
}
}
2、Json数组
Json数组使用的是
[ ]
来描述,[ ]
里面的元素和元素之间使用逗号间隔
,支持的数据类型:字符串、数字、Boolean、NULL、Json对象、Json数组
// 整形
[996,2399,1999,6999]
// 字符串
["张三", "李四", "王二", "麻子"]
// 混合使用
[111, 9.99, true, false, "交个朋友", null]
// 数组嵌套,数组使用,用逗号分隔
[
["张三", "李四", "王二", "麻子"],
[111, 9.99, true, false, "兄弟们支持了吗?", null]
]
// 数组嵌套对象
[
{
"king": {
"child": ["张三", "李四", "王二", "麻子"]
}
},
[111, 9.99, true, false, "你好,陌生人", null]
]
三、cJSON详解
有了上面的知识,来看cJSON会发现,其实也很简单,没有那么难,只需要知道对应方法的含义和如何使用它,就能解决开发中遇到的问题了。
我们看cJSON数据结构如下:
/* The cJSON structure: */
typedef struct cJSON
{
struct cJSON *next;
struct cJSON *prev;
struct cJSON *child;
int type;
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
double valuedouble;
char *string;
} cJSON;
char *string:表示对象中的
key
int type:用于描述数据元素的类型,type一共定义了7种
类型。
如果获取的类型是:Number类型,使用valueint
如果获取的类型是:double类型,使用valuedouble
如果获取的类型是:string类型,使用valuestring
我们可以通过如下方法去检查type类型:
大家看一下,源码中,就是通过这种方式,去判断type类型,然后去获取最终的数据值的:
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
{
if (!cJSON_IsString(item))
{
return NULL;
}
return item->valuestring;
}
...
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item)
{
if (!cJSON_IsNumber(item))
{
return NAN;
}
return item->valuedouble;
}
1、如何创建一个JSON对象?
带着问题去看源码并寻找解决答案
// cJSON.h
/* These calls create a cJSON item of the appropriate type. */
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);
我们刚刚在上面介绍JSON的时候,知道JSON可以是如下几种类型的:
字符串、数字Number、NULL、BOOL、Json对象、Json数组
所以我们可以通过cJSON_Create...
来创建JSON对象。
那么创建完JSON对象之后,如何添加键值对呢?
// cJSON.h
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);
我们看下面这样的json应该如何使用cJSON?
{
"pi": 3.141,
"happy": true,
"name": "头戴三叉束发紫金冠体挂西川红棉百花袍身披兽面吞头连环铠腰系勒甲玲珑狮蛮带手持方天画戟坐下嘶风赤兔马之吕小布是也"
}
使用方式:
int main()
{
cJSON * root;
// 创建根数据对象
root=cJSON_CreateObject();
// 添加键值对
cJSON_AddBoolToObject(root,"happy",true);
cJSON_AddNumberToObject(root,"pi",3.141);
cJSON_AddNumberToObject(root,"name","头戴三叉束发紫金冠体挂西川红棉百花袍身披兽面吞头连环铠腰系勒甲玲珑狮蛮带手持方天画戟坐下嘶风赤兔马之吕小布是也");
// 将json形式转换成字符串
char *out = cJSON_Print(root);
printf("%s\n",out);
// 释放内存,如果不删除会出现内存泄漏
cJSON_Delete(root);
free(out);
}
2、如何创建一个JSON数组?
看完上面的内容,我们应该知道应该用的是cJSON_CreateArray
对吧。
假如我们有如下json内容:
[111, 9.99, true, false, "交个朋友", null]
使用方式:
int main()
{
cJSON *root;
root = cJSON_CreateArray();
cJSON_AddItemToArray(root, cJSON_CreateNumber(111));
cJSON_AddItemToArray(root, cJSON_CreateNumber(9.99));
cJSON_AddItemToArray(root, cJSON_CreateBool(true));
cJSON_AddItemToArray(root, cJSON_CreateBool(false));
cJSON_AddItemToArray(root, cJSON_CreateString("交个朋友"));
cJSON_AddItemToArray(root, cJSON_CreateNull());
char *s = cJSON_PrintUnformatted(root);
if(s)
{
printf(" %s \n",s);
free(s);
}
// 必须要删除,否则会出现内存泄漏
cJSON_Delete(root);
return 0;
}
3、如何创建一个JSON对象嵌套数组?
{
"test":[{
"name":"雷布斯",
"motto":"碉堡了,友商是傻瓜"
}]
}
使用方式:
int main()
{
cJSON *root, *body, *list;
// json对象root
root = cJSON_CreateObject();
// root 添加键值对,test:json数组A
cJSON_AddItemToObject(root,"test", body = cJSON_CreateArray());
// json数组A,添加Json对象B
cJSON_AddItemToArray(body, list = cJSON_CreateObject());
// 在json对象B中添加键值对
cJSON_AddStringToObject(list,"name","雷布斯");
// 在json对象B中添加键值对
cJSON_AddNumberToObject(list,"motto","碉堡了,友商是傻瓜");
char *s = cJSON_PrintUnformatted(root);
if(s)
{
printf("%s \n",s);
free(s);
}
if(root)
{
// 必须要删除,否则会出现内存泄漏
cJSON_Delete(root);
}
return 0;
}
4、如何解析json?
// cJSON.h
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
将字符串转换为 cJSON 结构体
这里我们拿复杂的嵌套数据来讲解,json对象嵌套数组,如何解析呢?
{
"list": [{
"day": 1,
"money": -1999999
}, {
"day": 10,
"money": 1999999
}]
}
我们看到,最外层是一个JSONObject
然后通过key: list
获取JSONArray
JSONArray里面有2个JSONObject
然后通过key: happy
、key: money
获取对应的值
int main()
{
char *s = "{\"list\":[{\"day\":1,\"money\":-1999999},{\"day\":10,\"money\":1999999}]}";
cJSON *root = cJSON_Parse(s);
if(!root)
{
printf("cJSON_Parse失败 !\n");
return -1;
}
cJSON *list = cJSON_GetObjectItem(root, "list");
if(!list)
{
printf("没有发现key为list的Item!\n");
return -1;
}
// 这里我们需要获取数组的大小
int array_size = cJSON_GetArraySize(list);
printf("数组大小:%d\n",array_size);
for(int i=0; i< array_size; i++)
{
// 获取JSONArray
cJSON* item = cJSON_GetArrayItem(list, i);
cJSON* day = cJSON_GetObjectItem(item, "day");
printf("day is %d\n",day->valueint);
cJSON* money = cJSON_GetObjectItem(item, "money");
printf("money is %d\n",money->valueint);
}
if(root)
{
// 删除JSON并释放内存
cJSON_Delete(root);
}
return 0;
}
四、注意事项
刚刚上面我们介绍了,如何通过cJSON库:创建JSON以及如何解析JSON。
那么我们在cJSON解析数据的时候,一定要做数据健全性检查。
例如,我们刚写了下面2行代码:
cJSON *recvJson = cJSON_Parse(recvBuf);
cJSON *testID = cJSON_GetObjectItem(recvJson, "test_id");
...
我们这个时候能直接用testID
吗? 肯定不能,我们需要检查一下它是否存在,可增加如下代码进行判断:
if(testID == NULL || testID->type == cJSON_NULL)
{
printf("JSON数据有问题\r\n");
}
else
{ // 这里做正常的业务处理
...
}
这个时候可能有同学会疑问了,cJSON里面没有方法判断吗?
肯定有啊,请使用 cJSON_HasObjectItem
if(1 == cJSON_HasObjectItem(json,"test_id"))
{
// 这里做正常的业务处理
}
else
{
printf("JSON数据有问题\r\n");
}
那么我们这个时候,假设使用的是 testID->valuestring
获取内容,需要判断是否和本地的一个字符串值 雷布斯
是否相等,我们应该如何做呢?
我们可以使用 strcmp
来比较2个数据值是否相等
if (strcmp(testIDValue, "雷布斯") == 0)
{ // 这里判断2个数据值相等,这个分支里面写我们的业务代码
...
}