C环境下更简洁的cJSON辅助函数

2023年做过一个在C环境下,用来解析.json配置信息的辅助函数族,是用cJSON这个工具来做的一层封装:

一组完整的读Json配置信息的辅助函数_json帮助函数-CSDN博客

这一次进行代码重构时,在AI的帮助下,意识到这样的事:

json的规范里,并未定义路径分隔符,这就是为啥json解析时用到的那个cJSON那个接口会不太好用的原因。然后就有了对他的一个扩展:

1.为cJSON补充路径数列访问能力

cpp 复制代码
//将.json文件整体读入一个json Obj
cJSON *json_read_text_file(const char *filename){
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("Failed to open the file.\n");
        return NULL;
    }

    fseek(file, 0, SEEK_END);
    long file_size = ftell(file);
    fseek(file, 0, SEEK_SET);

    char *file_content = (char *)malloc(file_size + 1);
    fread(file_content, 1, file_size, file);
    file_content[file_size] = '\0';

    fclose(file);

    cJSON *json = cJSON_Parse(file_content);
    free(file_content);
    if (json == NULL) {
        printf("Failed to parse JSON.\n");
        free(file_content);
        return NULL;
    }


    return json;
}


//一个扩展:可以直接使用反斜杠路径提示符访问任何一个json中间节点和叶子节点
cJSON* gpJson_GetItemFromPath(cJSON* root, const char* path) {
    cJSON* current = root;
    char* path_copy = strdup(path);  // 复制路径
    char* token = strtok(path_copy, "\\");  // 使用 "\" 分割路径

    while (token != NULL) {
        if (current == NULL) break;  // 提前终止

        // 检查 token 是否包含数组下标(如 `key[1]`)
        char* bracket = strchr(token, '[');
        if (bracket != NULL && bracket[1] >= '0' && bracket[1] <= '9') {
            // 提取键名(`key` 部分)
            char* key = strndup(token, bracket - token);

            *bracket = '\0';  // 临时截断字符串

            // 提取下标(`1` 部分)
            int index = 0;
            char* end_bracket = strchr(bracket + 1, ']');
            if (end_bracket != NULL) {

                *end_bracket = '\0';  // 临时截断
                index = atoi(bracket + 1);  // 字符串转整数
            }

            // 获取对象中的键值
            current = cJSON_GetObjectItem(current, key);
            free(key);  // 释放临时键名内存

            // 若当前节点是数组且下标有效,则访问数组元素
            if (current != NULL && cJSON_IsArray(current) && index >= 0 && index < cJSON_GetArraySize(current)) {
                current = cJSON_GetArrayItem(current, index);
            } else {
                current = NULL;  // 无效访问
            }
        } else {
            // 普通键名访问
            current = cJSON_GetObjectItem(current, token);
        }
        token = strtok(NULL, "\\");
    }

    free(path_copy);  // 释放复制的路径
    return current;
}

2.用法演示

cpp 复制代码
//得到配置
    int i = 0;
    const char topic[1024];
    printf("sample group idx = %d\n", idxGroup);
    fflush(stdout);

//片段1: 得到jsonObj["channels"][3]["source"]["desc"]["ipAddr"], 一个string
    snprintf(topic, 1024, "channels[%d]\\source\\desc\\ipAddr", idxGroup);
    strncpy(papp->ip, cJSON_GetStringValue(gpJson_GetItemFromPath(jsonCfg, topic)), sizeof(papp->ip));



//片段2: 得到jsonObj["channels"][3]["source"]["desc"]["saps"], 一个integer
    snprintf(topic, 1024, "channels[%d]\\source\\desc\\saps", idxGroup);
    papp->saps = (int)cJSON_GetNumberValue(gpJson_GetItemFromPath(jsonCfg, topic));

    ....

//片段3:路径上可以包含任意的array:jsonObj["channels"][3]["source"]["desc"]["oem_ch"][5]
//    
    snprintf(topic, 1024, "channels[%d]\\source\\desc\\oem_ch[%i]", idxGroup, i);
    cJSON* dumb = gpJson_GetItemFromPath(jsonCfg, topic);
    if(dumb == NULL){
        papp->ch_src_list[i] = -1;
        needCheck = 0;
        continue;
    }
    else{
        papp->ch_src_list[i] = (int)cJSON_GetNumberValue(dumb);
        printf("% 2d", papp->ch_src_list[i]);
    }

3.结论及扩展

3.1 现在辅助函数只有两个函数。

1.读取.json文件;

2.然后就是解析全路径key反斜杠字符串。

3.2 如果使用C++语法,其实完全可以构造出一个支持:

jsonObj["channels"][3]["source"]["desc"]["saps"],这种语法规则的json读写类。

3.3 所有的终端叶子节点的json格式到char *, float之类的数据对象的转换,可以完全用cJSON本身的IO函数处理。不必画蛇添足,做出一堆比如

gpJson_get_string_item()

gpJson_get_float_item()一类的东西。

3.4 cJSON似乎没有处理default值,感觉这个地方可用宏来解决,更简单。仿照示例3.

相关推荐
咸甜适中6 小时前
rust语言,将JSON中的所有值以字符串形式存储到sqlite数据库中(逐行注释)
数据库·rust·sqlite·json
Ustinian_3107 小时前
【HTML】前端工具箱实现【文本处理/JSON工具/加解密/校验和/ASCII/时间戳转换等】【附完整源代码】
前端·html·json
消失的旧时光-19431 天前
Kotlinx.serialization 使用指南
android·kotlin·json
消失的旧时光-19432 天前
Kotlinx.serialization 项目集成
android·kotlin·json
坚持就完事了2 天前
JSON的了解
json
奥吼吼~~2 天前
标准输入输出stdio和JSON-RPC
网络协议·rpc·json
littlepeanut.top3 天前
C++中将FlatBuffers序列化为JSON
开发语言·c++·json·flatbuffers
遇见火星3 天前
LINUX的 jq命令行处理json字段指南
java·linux·json·jq
凌波粒4 天前
SpringMVC基础教程(2)--Controller/RestFul风格/JSON/数据转发和重定向
java·后端·spring·json·restful