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;
}
posted @ 2021-05-30 17:21  海林的菜园子  阅读(249)  评论(0编辑  收藏  举报