首页 > 解决方案 > 将此 Json 文件的输入转换为 C 结构

问题描述

我有一个名为 name.json 的 Json 文件,下面可以看到这样一个 Json 文件的示例

{
  "set": 5,
  "low": 0,
  "draw_set": "0.1 up to 0.3",
  "Wupet": "Hold",
  "": null
}

但也有可能是 Json 文件有另一种结构。

{
  "set": 5,
  "low": 0,
  "draw_set": "0.1 up to 0.3",
  "W_set": "Ramp 1.5 ∞C/min",
  "Wset": 0,
  "Wupet": "Hold",
  "": null
}

我想将此 Json 文件的输入(每个文件中的属性及其类型可能不同)转换为 C 结构,其中结构会自动检测 Json 文件中有哪些属性(及其类型)。“”中的属性“”:null(可以给随机属性名)

然后我想自动将 Json 值的值分配给对象 Book1 的结构。

我的代码计划

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Books {
   float  set[50];
   int  low[50];
   char  draw_set[100];
   char  Wupet[100];
};

int main( ) {
    /* Read name.Json file */


   struct Books Book1;        /* Declare Book1 of type Book */
   /* Convert content Json to Struct Book1 with it's actual values*/

   return 0;
}

编辑:如果 Json 文件中存在“Wset”和“W_set”键,我不想忽略它们。Json 文件的键随时都在改变(未来可能会出现许多未知属性)。钥匙的数量不能保证。保证“多行拆分”属性?应为空键名称指定一个随机名称(可以出现多个键,如空键名称) 应自动检测和创建结构的属性类型。Json 文件包含单个记录(对象)

我想在运行时处理这些结构。

标签: cjsonstruct

解决方案


应该自动检测和创建结构的属性类型。

如果没有一些古怪的宏,你就无法做到这一点。C 中结构的字段在编译时是固定的。

自动填充你的结构需要能够找出你的结构的字段和类型:反射。C 没有反射。您可以编写一些聪明的宏,但对于这么简单的事情可能不值得。

如果没有一些古怪的宏,基于 JSON 自动将字段添加到您的结构中也是不可能的。

相反,我们会将 JSON 解析为灵活的数据结构,您可以随心所欲地使用它。如果要将它们全部放入一个结构中,则该结构必须包含所有可能的字段。有一些技术可以编写扩展结构,因此您可以为不同类型的书籍拥有一个基本的Book然后是附加的扩展结构。

JSON-Glib两者都提供。它将 JSON 解析为 JsonNodes,可以是 JsonArrays 或 JsonObjects。然后你可以对他们做任何你想做的事情。


在我们这样做之前,结构需要一些工作。

struct Books {
    gint64      set;
    gint64      low;
    const char  *draw_set;
    const char  *wupet;
};

set不是浮点数,而是整数。

我们使用 GLib 类型来匹配 GLib 库返回的内容并避免大数字溢出。

读取输入时应避免使用固定大小的缓冲区,它们很容易溢出。相反,JSON-Glib 可以分配正确的内存量。我们将复制它并存储一个指向它的指针。


这是一个使用 JSON-Glib 解析 JSON 文件并手动填充结构的示例。

#include <stdlib.h>
#include <stdio.h>
#include <glib-object.h>
#include <json-glib/json-glib.h>

struct Books {
    gint64      set;
    gint64      low;
    char        *draw_set;
    char        *wupet;
};

int main(int argc, char** argv) {
    GError *error = NULL;

    if (argc < 2) {
        printf("Usage: test <filename.json>\n");
        return EXIT_FAILURE;
    }

    // Parse the JSON from the file
    JsonParser *parser = json_parser_new();
    json_parser_load_from_file(parser, argv[1], &error);
    if(error) {
        printf("Unable to parse `%s': %s\n", argv[1], error->message);
        g_error_free(error);
        g_object_unref(parser);
        return EXIT_FAILURE;
    }

    // Get the root
    JsonNode *root = json_parser_get_root(parser);

    // Turn the root into a JSON object
    JsonObject *stuff = json_node_get_object(root);

    // Get each object member and assign it to the struct.
    struct Books book = {
        .set = json_object_get_int_member(stuff, "set"),
        .low = json_object_get_int_member(stuff, "low"),
        // Duplicate the strings to avoid pointing to memory inside the parser.
        .draw_set = g_strdup(json_object_get_string_member(stuff, "draw_set")),
        .wupet = g_strdup(json_object_get_string_member(stuff, "Wupet"))
    };

    printf(
        "set = %ld, low = %ld, draw_set = '%s', wupet = '%s'\n",
        book.set, book.low, book.draw_set, book.wupet
    );

    // We're finished working with the parser. Deallocate the
    // parser and all the memory it has allocated, including
    // the nodes.
    g_object_unref(parser);

    return EXIT_SUCCESS;
}

推荐阅读