V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
monkeyNik
V2EX  ›  C

最好用的 C 语言 JSON 解析器

  •  
  •   monkeyNik · 2023-09-12 00:46:43 +08:00 · 1281 次点击
    这是一个创建于 470 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文介绍开源 C 语言库Melon的 JSON 解析器。

    相信很多读者都听说过甚至使用过 cJSON 开源库。那么本文就拿 cJSON 与 Melon 的 JSON 组件进行对比。

    下面我们就来一起看一看。

    编码 Encode

    假设我们要构建如下 JSON:

    {
        "name": "Awesome 4K",
        "resolutions": [
            {
                "width": 1280,
                "height": 720
            },
            {
                "width": 1920,
                "height": 1080
            },
            {
                "width": 3840,
                "height": 2160
            }
        ]
    }
    

    那么,我们先看一下cJSON的构建代码:

    #include <stdio.h>
    #include <cjson/cJSON.h>
    
    //NOTE: Returns a heap allocated string, you are required to free it after use.
    char *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 *monitor = cJSON_CreateObject();
    
        if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
        {
            goto end;
        }
    
        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();
    
            if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
            {
                goto end;
            }
    
            if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
            {
                goto end;
            }
    
            cJSON_AddItemToArray(resolutions, resolution);
        }
    
        string = cJSON_Print(monitor);
        if (string == NULL)
        {
            fprintf(stderr, "Failed to print monitor.\n");
        }
    
    end:
        cJSON_Delete(monitor);
        return string;
    }
    
    int main(void)
    {
        char *p;
        p = create_monitor_with_helpers();
        printf("%s\n", p);
        return 0;
    }
    

    下面,我们一起看下使用Melon 的 JSON 组件的代码:

    #include <stdio.h>
    #include "mln_json.h"
    #include "mln_log.h"
    
    static mln_string_t *generate(void)
    {
        mln_json_t j;
        mln_string_t *ret;
    
        mln_json_init(&j);
    
        mln_json_generate(&j, "{s:s,s:[{s:d,s:d},{s:d,s:d},{s:d,s:d}]}", \
            "name", "Awesome 4K", "resolutions", "width", 1280, "height", 720, \
            "width", 1920, "height", 1080, "width", 3840, "height", 2160);
        ret = mln_json_encode(&j);
    
        mln_json_destroy(&j);
    
        return ret;
    }
    
    int main(void)
    {
        mln_string_t *p;
        p = generate();
        mln_log(none, "%S\n", p);
        return 0;
    }
    

    解码 Decode

    假设我们有如下 JSON:

    {
        "name": "Awesome 4K",
        "resolutions": [
            {
                "width": 1280,
                "height": 720
            }
        ]
    }
    

    下面一起来看下解码,还是先上cJSON的代码:

    #include <stdio.h>
    #include <cjson/cJSON.h>
    
    /* return 1 if the monitor supports full hd, 0 otherwise */
    int supports_full_hd(const char * const monitor)
    {
        const cJSON *resolution = NULL;
        const cJSON *resolutions = NULL;
        cJSON *monitor_json = cJSON_Parse(monitor);
        if (monitor_json == NULL)
            return -1;
    
        resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
        cJSON_ArrayForEach(resolution, resolutions)
        {
            cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
            return width->valuedouble;
        }
    
        cJSON_Delete(monitor_json);
        return -1;
    }
    
    int main(void)
    {
        char p[] = "{\"name\":\"Awesome 4K\",\"resolutions\":[{\"width\":1280,\"height\":720}]}";
        int i = supports_full_hd(p);
        printf("%d\n", i);
        return 0;
    }
    

    接下来是Melon 的 JSON 组件的解码代码:

    #include <stdio.h>
    #include "mln_json.h"
    #include "mln_log.h"
    
    static int handler(mln_json_t *j, void *data)
    {
        return (int)M_JSON_GET_DATA_NUMBER(j);
    }
    
    static int parse(mln_string_t *p)
    {
        mln_json_t j;
        mln_string_t exp = mln_string("resolutions.0.width");
        mln_json_decode(p, &j);
        return mln_json_parse(&j, &exp, handler, NULL);
    }
    
    int main(void)
    {
        mln_string_t p = mln_string("{\"name\":\"Awesome 4K\",\"resolutions\":[{\"width\":1280,\"height\":720}]}");
        int i = parse(&p);
        mln_log(none, "%d\n", i);
        return 0;
    }
    

    结语

    Melon 的 JSON 组件主要提供了如下四个函数来便于使用者构建和解析 JSON:

    • mln_json_decode解码 JSON 字符串为 JSON 结构体结点
    • mln_json_parse从解码的 JSON 结构体中,根据给定表达式,获取对应的 JSON 子结点
    • mln_json_generate根据给定的格式信息构建 JSON 结构体
    • mln_json_encode根据生成的 JSON 结构体生成 JSON 字符串

    Melon 的 JSON 组件提供了易于阅读和使用的函数接口,更易于开发者对项目的维护。

    欢迎大家来试用开源 C 语言库 Melon 。

    Github: https://github.com/Water-Melon/Melon

    yolee599
        1
    yolee599  
       2023-09-12 09:10:27 +08:00 via Android
    性能怎么样呢?其实我写 C 不喜欢用参数列表,看着逻辑不清晰
    xi4oyu
        2
    xi4oyu  
       2023-09-12 10:13:08 +08:00
    可以看看这个,我觉得用起来更简单: https://github.com/gd-zth/ezJSON
    FaiChou
        3
    FaiChou  
       2023-09-12 11:42:27 +08:00
    赞呀,最近在学 C 语言,刚好要拿 cJSON 来研究,这下又加了一个学习案例。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5316 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 07:26 · PVG 15:26 · LAX 23:26 · JFK 02:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.