文章目录
JSON 解析器设计与实现
一、模块概述
在嵌入式系统中,JSON 作为一种轻量级的数据交换格式被广泛使用。虽然 cJSON 库提供了基础的 JSON 解析功能,但在实际应用中还需要考虑内存限制、类型安全等问题。本文介绍了一个基于 cJSON 的二次封装模块,提供了更安全、更易用的 JSON 处理接口。
1.1 设计目标
- 提供简单易用的 JSON 数据处理接口
- 确保内存和类型安全
- 适配嵌入式系统资源限制
- 统一的错误处理机制
1.2 核心功能
- JSON 字符串解析与生成
- 多种数据类型支持
- 参数有效性验证
- 内存管理和安全检查
二、数据结构设计
2.1 参数配置结构
typedef struct {
const char *key; // JSON 键名
json_param_type_t type; // 数据类型
int max_size; // 字符串最大长度
float scale; // 数值缩放因子
void *value; // 值指针
int is_required; // 必需标志
} json_param_config_t;
2.2 支持的数据类型
typedef enum {
JSON_TYPE_STRING, // 字符串类型
JSON_TYPE_INT, // 整数类型
JSON_TYPE_FLOAT, // 浮点数类型
JSON_TYPE_DOUBLE, // 双精度浮点
JSON_TYPE_OBJECT, // JSON对象
JSON_TYPE_ARRAY // JSON数组
} json_param_type_t;
三、核心接口实现
3.1 JSON字符串创建
int json_create(const json_param_config_t *params, int param_count, char *json_str, int size)
{
if (!params || !json_str || size <= 0) {
JSON_ERR("invalid param\r\n");
return SL_ERROR;
}
int ret = SL_ERROR;
cJSON *root = cJSON_CreateObject();
if (!root) {
JSON_ERR("create json object failed\r\n");
return SL_ERROR;
}
for (int i = 0; i < param_count; i++) {
if (params[i].value) {
json_add_param(root, ¶ms[i]);
}
}
char *temp = cJSON_PrintUnformatted(root);
if (temp) {
if (snprintf(json_str, size, "%s", temp) < size) {
ret = SL_EOK;
}
free(temp);
}
if (ret == SL_EOK) {
JSON_PRINTF("json_create: %s\r\n", json_str);
}
cJSON_Delete(root);
return ret;
}
关键实现:
- 参数有效性检查
- 创建JSON根对象
- 遍历添加键值对
- 生成JSON字符串
- 内存管理和清理
3.2 JSON字符串解析
int json_parse(const char *json_str, const json_param_config_t *params, int param_count)
{
if (!json_str || !params) {
JSON_ERR("invalid param\r\n");
return SL_ERROR;
}
cJSON *root = cJSON_Parse(json_str);
if (!root) {
JSON_ERR("parse json string failed\r\n");
return SL_ERROR;
}
int ret = SL_EOK;
for (int i = 0; i < param_count; i++) {
cJSON *item = cJSON_GetObjectItem(root, params[i].key);
if (item) {
if (json_get_param(item, (json_param_config_t *)¶ms[i]) != SL_EOK) {
ret = SL_ERROR;
break;
}
} else if (params[i].is_required) {
ret = SL_ERROR;
break;
}
}
if (ret == SL_EOK) {
JSON_PRINTF("json_parse: %s\r\n", json_str);
}
cJSON_Delete(root);
return ret;
}
关键实现:
- 输入验证
- JSON解析
- 参数遍历
- 数据提取转换
- 错误处理
3.3 参数操作接口
3.3.1 参数添加
static int json_add_param(cJSON *root, const json_param_config_t *param)
{
if (!root || !param || !param->value) {
JSON_ERR("invalid param\r\n");
return SL_ERROR;
}
switch (param->type) {
case JSON_TYPE_STRING:
cJSON_AddStringToObject(root, param->key, (char *)param->value);
break;
case JSON_TYPE_INT:
cJSON_AddNumberToObject(root, param->key, *(int *)param->value);
break;
case JSON_TYPE_DOUBLE:
cJSON_AddNumberToObject(root, param->key, *(double *)param->value);
break;
case JSON_TYPE_FLOAT: {
float val = *(float *)param->value;
if (param->scale != 0) {
val *= param->scale;
}
if (fabs(val - (int)val) < 0.000001) {
cJSON_AddNumberToObject(root, param->key, (int)val);
} else {
cJSON_AddNumberToObject(root, param->key, val);
}
break;
}
case JSON_TYPE_OBJECT:
case JSON_TYPE_ARRAY:
if (*(cJSON **)param->value) {
cJSON_AddItemToObject(root, param->key,
cJSON_Duplicate(*(cJSON **)param->value, 1));
}
break;
default:
JSON_ERR("invalid param type\r\n");
return SL_ERROR;
}
return SL_EOK;
}
关键实现:
- 类型安全检查
- 数值转换处理
- 浮点数精度控制
- 对象深拷贝
3.3.2 参数获取
static int json_get_param(cJSON *item, json_param_config_t *param)
{
if (!item || !param || !param->value) {
JSON_ERR("invalid param\r\n");
return SL_ERROR;
}
switch (param->type) {
case JSON_TYPE_STRING: {
if (!cJSON_IsString(item)) {
JSON_ERR("invalid param type\r\n");
return SL_ERROR;
}
strncpy((char *)param->value, item->valuestring, param->max_size - 1);
((char *)param->value)[param->max_size - 1] = '\0';
break;
}
case JSON_TYPE_INT:
if (!cJSON_IsNumber(item)) {
JSON_ERR("invalid param type\r\n");
return SL_ERROR;
}
*(int *)param->value = item->valueint;
break;
case JSON_TYPE_DOUBLE:
if (!cJSON_IsNumber(item)) {
JSON_ERR("invalid param type\r\n");
return SL_ERROR;
}
*(double *)param->value = item->valuedouble;
break;
case JSON_TYPE_FLOAT:
if (!cJSON_IsNumber(item)) {
JSON_ERR("invalid param type\r\n");
return SL_ERROR;
}
float val = (float)item->valuedouble;
if (param->scale != 0) {
val /= param->scale;
}
*(float *)param->value = val;
break;
case JSON_TYPE_OBJECT:
case JSON_TYPE_ARRAY:
*(cJSON **)param->value = cJSON_Duplicate(item, 1);
break;
default:
JSON_ERR("invalid param type\r\n");
return SL_ERROR;
}
return SL_EOK;
}
关键实现:
- 类型匹配验证
- 字符串安全拷贝
- 数值转换和缩放
- 复合类型深拷贝
四、使用示例
4.1 创建JSON
// 定义参数
json_param_config_t params[] = {
{
.key = "name",
.type = JSON_TYPE_STRING,
.max_size = 32,
.value = name_buffer,
.is_required = 1
},
{
.key = "temperature",
.type = JSON_TYPE_FLOAT,
.scale = 100,
.value = &temp_value,
.is_required = 1
}
};
// 创建JSON字符串
char json_str[256];
json_create(params, 2, json_str, sizeof(json_str));
4.2 解析JSON
const char *json = "{\"name\":\"sensor1\",\"temperature\":25.5}";
json_parse(json, params, 2);
五、注意事项
5.1 内存安全
- 字符串缓冲区溢出检查
- 对象深拷贝内存管理
- 资源释放确保
5.2 类型安全
- 严格的类型检查
- 数值范围验证
- 格式转换保护
5.3 错误处理
- 统一的错误码
- 详细的错误日志
- 异常情况处理
六、性能优化
6.1 内存优化
- 减少内存拷贝
- 合理使用栈空间
- 及时释放资源
6.2 效率优化
- 避免重复解析
- 优化字符串处理
- 合理使用缓存
基于cJSON的JSON解析器二次封装设计
1149

被折叠的 条评论
为什么被折叠?



