JSON解析与创建
什么是json
这是一条json
{"name":"hany","age":18}
一对{}
就是一个JSON object,
object里的"mane"
"age"
被称为key name,"hany"
18
被称为key value。
KEY name是一个字符串;
下面重点说一下KEY value 的可选类型
value是INT型
{"age":18}
value是DOUBLE型
{"height":180.1}
value是STRING型
{"name":"hany"}
value是ARRAY型
{"module":[]}
value是OBJECT
{"people":{"name":"hany"}}
JSON的解析与创建
方法一:直接使用字符串操作
解析
使用C库函数strstr
判断有无关心的关键字即可。
#include <stdio.h>
#include <string.h>
const char *rpc_cmd = "{"id":5,"action":"led_on"}";
if (strstr(rpc_cmd, "led_on"))
{
printf("open led");
}
创建
先写出这条json的格式,再使用C库函数snprintf
对其进行value值填充即可
const char *query_did_format = "{\"id\":%d,\"method\":\"local.query_did\", \"params\":\"\"}";
char rpc_buf[64] = {0};
snprintf(rpc_buf, sizeof(rpc_buf), query_did_format, rand());
优点:操作简单,节省资源
缺点:处理复杂协议就显得很麻烦
方法二:使用CJSON库
解析
目标
static const char *monitor_without_hd = "{\n\
\t\t\"name\": \"lame monitor\",\n\
\t\t\"resolutions\":\t[{\n\
\t\t\t\"width\":\t640,\n\
\t\t\t\"height\":\t480\n\
\t\t}]\n\
}";
/*return 1 if the monitor supports full HD , 0 otherwise*/
static int supports_full_hd(const char * const monitor)
{
int status = 0;
/* 首先调用cJSON_Parse,解析JSON数据包。该函数会malloc出一块内存,使用完毕后要手动释放 */
cJSON *monitor_json = cJSON_Parse(monitor);
if (monitor_json == NULL)
{
status = 0;
goto end;
}
/* 在JSON Object中,查找 key name 为 “name”的 key, 找到后返回其 key value */
const cJSON *name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
/* 判断 key value是不是字符串,并且字符串不为空 */
if (cJSON_IsString(name) && (name->valuestring != NULL))
{
printf("checking monitor \"%s\", name->valuestring);
}
/* 在JSON Object中,查找key name 为"resolution"的key,找到后返回其值 */
const cJSON *resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
/* 判断resolution是不是数组 */
if (!cJSON_IsArray(resolutions))
{
goto end;
}
const cJSON *resolution = NULL;
/* 在resolutions数组中,遍历每一个JSON OBJECT */
cJSON_ArrayForEach(resolution, resolutions)
{
cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");
if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
{
status = 0;
goto end;
}
if (width->valueint == 1920 && width->valueint == 1080)
{
status = 1;
goto end;
}
}
end:
/*释放cJSON_Parse分配出来的内存*/
cJSON_Delete(monitor_json);
return status;
}
创建
目标
格式化的JSON
{
"name": "Awesome 4K",
"resolutions": [
{
"width": 1280,
"height": 720
},
{
"width": 1920,
"height": 1080
},
{
"width": 3840,
"height": 2160
}
]
}
未格式化的JSON
{"name": "Awesome 4K","resolutions": [{"width": 1280,"height": 720},{"width": 1920, "height": 1080},{"width": 3840,"height": 2160}]}
代码生成格式化的JSON
//NOTE: Returns a heap allocated string, you are required to free it after use.
void create_monitor_with_helpers(void)
{
const unsigned int resolution_numbers[3][2] = {
{1280, 720},
{1920, 1080},
{3840, 2160}
};
char *string = NULL;
cJSON *resolutions = NULL;
size_t index = 0;
/*创建{}。cJSON_CreateObject执行后,会申请一块内存,使用完毕后,需要手动释放*/
cJSON *monitor = cJSON_CreateObject();
/*{"name": "Awesome 4K"}*/
if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
{
goto end;
}
/*{"name": "Awesome 4K","resolutions":[]}*/
resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
if (resolutions == NULL)
{
goto end;
}
//对数组进行赋值
for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
{
//创建{}
cJSON *resolution = cJSON_CreateObject();
//加入键值对width
if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
{
goto end;
}
//加入键值对height
if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
{
goto end;
}
//将当前OBJECT 加入到数组
cJSON_AddItemToArray(resolutions, resolution);
}
//对创建好的JSON进行格式化。cJSON_Print执行后会提请一块内存,使用完毕后,需要手动释放
string = cJSON_Print(monitor);
if (string == NULL)
{
fprintf(stderr, "Failed to print monitor.\n");
}
else
{
cJSON_free(string);
}
end:
cJSON_Delete(monitor);
}
优点:能适用任何复杂的JSON协议,方便动态扩展键值对
缺点:会用到大量的动态内存,需要注意内存泄露问题;非线程安全
cJSON_Parse
cJSON_CreateObject
要用 cJSON_Delete
释放
cJSON_Print
cJSON_PrintUnformatted
要用 cJSON_free
释放
方法三:CJsonObject
简介
- CJsonObject是基于cJSON全新开发一个C++版的JSON库,CJsonObject的最大优势是轻量,简单好用,开发效率极高。
- CJsonObject只有4个文件,拷贝到自己代码里源码级集成即可,无须编译成库,且跨平台和编译器。
- 与大部分json解析库访问多层嵌套json非常麻烦不同,CJsonObject对多层嵌套json的读取和生成使用非常简单。
- 支持线程安全
- 更多内容请移步作者BLOG:https://www.cnblogs.com/bwar/p/11294452.html
方法四:struct2json
简介
使用cJSON
解析库,但是使用后的代码冗余且逻辑性差,故对cJSON库进行二次封装,实现一个 struct 与 JSON 之间快速互转的库。
目标
将这下面的结构体
点击查看代码
/* 籍贯 */
typedef struct {
char name[16];
} Hometown;
/* 学生 */
typedef struct {
uint8_t id;
uint8_t score[8];
char name[10];
double weight;
Hometown hometown;
} Student;
static Student orignal_student_obj = {
.id = 24,
.weight = 71.2,
.score = {1, 2, 3, 4, 5, 6, 7, 8},
.name = "armink",
.hometown.name = "China",
};
JSON串
{"id":24,"weight":71.200000,"score":[1,2,3,4,5,6,7,8],"name":"armink","hometown":{"name":"China"}}
进行数据相互转换
代码
点击查看代码
/**
* Student JSON object to structure object
*
* @param json_obj JSON object
*
* @return structure object
*/
static void *json_to_struct(cJSON* json_obj) {
/* create Student structure object */
s2j_create_struct_obj(struct_student, Student);
/* deserialize data to Student structure object. */
s2j_struct_get_basic_element(struct_student, json_obj, int, id);
s2j_struct_get_array_element(struct_student, json_obj, int, score);
s2j_struct_get_basic_element(struct_student, json_obj, string, name);
s2j_struct_get_basic_element(struct_student, json_obj, double, weight);
/* deserialize data to Student.Hometown structure object. */
s2j_struct_get_struct_element(struct_hometown, struct_student, json_hometown, json_obj, Hometown, hometown);
s2j_struct_get_basic_element(struct_hometown, json_hometown, string, name);
/* return Student structure object pointer */
return struct_student;
}
/**
* Student structure object to JSON object
*
* @param struct_obj structure object
*
* @param JSON object
*/
static cJSON *struct_to_json(void* struct_obj) {
Student *struct_student = (Student *)struct_obj;
/* create Student JSON object */
s2j_create_json_obj(json_student);
/* serialize data to Student JSON object. */
s2j_json_set_basic_element(json_student, struct_student, int, id);
s2j_json_set_basic_element(json_student, struct_student, double, weight);
s2j_json_set_array_element(json_student, struct_student, int, score, 8);
s2j_json_set_basic_element(json_student, struct_student, string, name);
/* serialize data to Student.Hometown JSON object. */
s2j_json_set_struct_element(json_hometown, json_student, struct_hometown, struct_student, Hometown, hometown);
s2j_json_set_basic_element(json_hometown, struct_hometown, string, name);
/* return Student JSON object pointer */
return json_student;
}