一、cJson库
1. 功能简述
- 处理json数据,支持创建、解析以及操作json数据,适用于嵌入式系统
- 特点:轻量、易用、跨平台
- 代码地址
https://github.com/DaveGamble/cJSON.git,使用时只需要包含cJSON.c和cJSON.h
2. API介绍和使用
cJSON* cJSON_CreateObject(void); // 创建一个空的cJSON对象
cJSON* cJSON_CreateArray(void); // 创建一个空的cJSON数组
cJSON* cJSON_CreateString(const char *string); // 创建一个字符串cJSON对象
cJSON* cJSON_CreateNumber(double num); // 创建一个数字cJSON对象
cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); //
cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); //
3. 使用示例
// 创建JSON示例
cJSON *root = cJSON_CreateObject(); // 创建一个根节点
cJSON_AddStringToObject(root, "name", "John"); // 添加字符串对象到根节点中
cJSON_AddNumberToObject(root, "age", 30); // 添加数字对象到根节点中
cJSON *hobbies = cJSON_AddArrayToObject(root, "hobbies"); // 添加数组对象到根节点中
if (hobbies != NULL)
{cJSON_AddItemToArray(hobbies, cJSON_CreateString("reading")); // 往cJSON节点中添加字符串属性cJSON_AddItemToArray(hobbies, cJSON_CreateString("swimming")); // 往cJSON节点中添加字符串属性cJSON_AddItemToArray(hobbies, cJSON_CreateString("coding")); // 往cJSON节点中添加字符串属性
}
cJSON *friends = cJSON_AddArrayToObject(root, "friends"); // 添加数组对象到根节点中
if (friends != NULL)
{// 第一个朋友cJSON *friend1 = cJSON_CreateObject();cJSON_AddStringToObject(friend1, "name", "Alice");cJSON_AddNumberToObject(friend1, "age", 28);cJSON_AddItemToArray(friends, friend1); // 嵌套添加节点// 第二个朋友cJSON *friend2 = cJSON_CreateObject();cJSON_AddStringToObject(friend2, "name", "Bob");cJSON_AddNumberToObject(friend2, "age", 32);cJSON_AddItemToArray(friends, friend2); // 嵌套添加节点
}
char *json_string = cJSON_Print(root); // 生成一个格式化的字符串带空格
printf("%s\n", json_string);
cJSON_free(json_string); // 对应cJSON_Print的释放函数
char *json_string1 = cJSON_PrintUnformatted(root); // 生成一个紧凑的字符串不带空格
printf("%s\n", json_string1);
cJSON_free(json_string1); // 对应cJSON_PrintUnformatted的释放函数
cJSON_Delete(root); // 对应cJSON_CreateObject的释放函数
// 解析JSON示例
cJSON *json = cJSON_Parse(json_string); // 输入json字符串生成cJSON根节点
if (root == NULL) { // 错误检查
printf("解析错误\n");
return;
}
cJSON *name = cJSON_GetObjectItemCaseSensitive(json, "name"); // 从cJSON节点中根据名称获得对应的cJSON对象
if (name != NULL && cJSON_IsString(name))
{const char *name_str = cJSON_GetStringValue(name); // 处理字符串printf("姓名: %s\n", name_str);
}
cJSON_Delete(json); // 释放cJSON根节点
4. 主要数据结构与API实现方式
// 关键结构体
typedef struct cJSON
{struct cJSON *next;struct cJSON *prev; // 双向链表组织cJSON结构体struct cJSON *child; // json结构的子节点int type; // json对象的类型char *valuestring; // 字符串,类型是cJSON_String或cJSON_Raw时该值有效int valueint; // 数值,整数值,被valuedouble替代double valuedouble; // 数值,浮点数,类型是cJSON_Number时该值有效char *string; // 名称
} cJSON;
// 内存分配和释放函数
malloc、free、realloc分别对应global_hooks结构体的三个成员
void cJSON_InitHooks(cJSON_Hooks* hooks); // 该函数可以自定义内存的分配和释放函数
cJSON *cJSON_New_Item(const internal_hooks * const hooks); // 该函数调用malloc函数返回一个cJSON的结构体并返回指针
unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks); // 字符串复制函数,调用内存分配并memcpy
cJSON *cJSON_CreateObject(void); // 调用cJSON_New_Item获得一个新的cJSON对象,并设置type为cJSON_Object
cJSON *cJSON_CreateArray(void); // 调用cJSON_New_Item获得一个新的cJSON对象,并设置type为cJSON_Array
cJSON *cJSON_CreateNumber(double num); // 调用cJSON_New_Item获得一个新的cJSON对象,并设置type为cJSON_Number,并设置valuedouble成员
cJSON *cJSON_CreateRaw(const char *raw); // 调用cJSON_New_Item获得一个新的cJSON对象,并设置type为cJSON_Raw,并调用cJSON_strdup完成字符串
cJSON *cJSON_CreateString(const char *string); // 同上,区别是type是cJSON_String
cJSON *cJSON_CreateIntArray(const int *numbers, int count); // 数组表示一个节点,child成员是第一个数字节点,所有的数字节点使用双向链表连接
cJSON *cJSON_CreateFloatArray(const float *numbers, int count); // 同上
cJSON *cJSON_CreateDoubleArray(const double *numbers, int count); // 同上
cJSON *cJSON_CreateStringArray(const char *const *strings, int count); // 同上
cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); // 添加元素到cJSON对象中
cJSON_bool cJSON_AddItemToArray(cJSON *array, cJSON *item); // 添加元素到数组类型的cJSON对象中
cJSON_AddxxToObject; //创建一个xx,并将xx放入Object中
char *cJSON_Print(const cJSON *item); // 格式化输出json为字符串
char *JSON_PrintUnformatted(const cJSON *item); // 压缩输出json为字符串
cJSON *cJSON_Parse(const char *value); // 输入json字符串,输出JSON根节点
cJSON *name = cJSON_GetObjectItemCaseSensitive(json, "name"); // 从cJSON节点中根据名称获得对应的cJSON对象
cJSON_IsString是否是string
cJSON_IsNumber是否是number
cJSON_IsBool是否是布尔
cJSON_IsArray是否是数组,之后使用宏cJSON_ArrayForEach进行范围for循环,实际是一个for循环的封装
cJSON_GetStringValue返回json的字符串,类型不匹配返回NULL
cJSON_GetNumberValue返回json的数值,类型不匹配返回NAN
5. 需要关注的点
cJSON_CreateRaw中的字符串是原始的,不进行转义
cJSON_CreateIntArray创建了n+1个节点,其中一个节点作为父节点表示数组,其他的n个节点存储数据并通过双向链表连接
cJSON_ArrayForEach看起来像是范围for循环,实际是for循环的封装
- 关注的有数值、字符串、数组、嵌套
cJSON_CreateObject与cJSON_Delete对应
- 使用
cJSON_Print和cJSON_PrintUnformatted的返回值需要使用cJSON_free释放
- 使用
cJSON_AddxxToObject将json节点添加到Object,xx节点就不需要自己释放,释放Object的时候会释放掉xx
cJSON_Parse与cJSON_Delete对应