在C中使用YAJL解析json

发布于 2024-12-02 18:49:22 字数 6500 浏览 1 评论 0原文

我一定做错了什么......或者这可能是 YAJL 中的一个错误,但我非常怀疑这一点。 我无法从 json 对象中检索第一个元素。我回到 YAJL 源代码并使用示例 parse_config.c 对此进行测试,但它也失败了。

使用sample.config,

/*
 * The configuration file for Yahoo! BrowserPlus, included in the YAJL
 * tree as a sample configuration file for parsing.
 *
 * This is the configuration file for BrowserPlus
 */

{
    // The type of build this is, which is accessible to JavaScript via
    // BrowserPlus.getPlatformInfo(); 
    // Different build types should only differ in signatures accepted
    // (BrowserPlus.crt) and configured distribution servers.
    "BuildType": "ephemeral",

    // the base url for the "primary" distribution server.  This server will
    // be the single source of truth for Permissions, and will used to 
    // attain services
    "DistServer": "http://browserplus.yahoo.com",

    // An array of "secondary" distribution servers, which will be checked
    // in order for services if the primary server has no components
    // available which match an issued require statement.
    "SecondaryDistServers": [
      "http://first.fictional.server",
      "http://second.fictional.server"
    ],

    // Logging Setup
    "Logging" :
    {
        // Log level.  Values: "debug"|"info"|"warn"|"error"|"fatal"|"off"
        "level": "BP_LOG_LEVEL",

        // Destination.  Values: "file"|"console"|"win32"
        "dest": "BP_LOG_DEST",

        // Log message layout.  Values: "standard"|"source"|"raw"
        "layout": "standard",

        // Time format.  Values: "utc"|"local"|"msec"
        "timeFormat": "utc",

        // File size in KB which will trigger a rollover
        "fileRolloverKB": 2048,

        // Whether to send file logging from each service to a distinct file.
        // Values: "combined"|"separate"
        "serviceLogMode": "combined"
    },

    // Daemon setup
    // Syntax: "Options": "option1 option2 etc"
    // -fg        run in foreground, log to console
    "Options":"",

    // Auto-shutdown daemon if idle for this time.  Use 0 for no auto-shutdown.
    "MaxIdleSecs": 5,

    // At the end of each BrowserPlus session a small web request is made
    // to yahoo to indicate that BrowserPlus was used.  This report includes
    // * information about the browser being used
    // * an "installation id", which is a unique token that's generated
    //   the first time BrowserPlus runs.
    //
    // By design, there is *no information* in this request that gives
    // Yahoo! information about:
    //   a) the site that the user is visiting (see, "url": false)
    //   b) who the user is (the installation token cannot be tracked to a
    //      specific user).
    //
    // This information is primarily captured to help Yahoo! understand
    // adoption and usage of the BrowserPlus platform.
    "UsageReporting":
    {
       "enabled": true,
       "url": false,
       "id": true
    },

    // "Breakpoints" is an array of strings holding named breakpoints.
    // Platform code checks for specific entries at certain key points, and if 
    // a matching entry is found here a DebugBreak will be performed.
    // For developers with Visual Studio installed, the DebugBreak will cause an
    // opportunity to perform just-in-time attachment of an existing or new 
    // debugger instance.
    // The currently-defined breakpoints are listed below:
    //      runServiceProcess - A DebugBreak is performed in the service 
    //                          "harness" just prior to service load.
    //      ax.FinalConstruct - A DebugBreak is performed at entry to 
    //                          FinalConstruct of the ActiveX plugin.
    //      PluginInit -        Very early in the NPAPI plugin initialization.
    //                          A wonderful spot to stop and set more
    //                          breakpoints.
    //"Breakpoints": ["runServiceProcess"],

    // How often we check for service updates.  We guarantee at least this
    // much time will pass between checks, though the true time may be
    // much more if sites which use browserplus are not visited.
    // The time is in seconds.
    "ServiceUpdatePollPeriod": 86400
}

我尝试检索“BuildType”<--JSON 对象的第一个元素。

我更改了 parse_config.c 文件来执行此操作...这是代码:

int
main(void)
{
    size_t rd;
    yajl_val node;
    char errbuf[1024];

    /* null plug buffers */
    fileData[0] = errbuf[0] = 0;

    /* read the entire config file */
    rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);

    /* file read error handling */
    if (rd == 0 && !feof(stdin)) {
        fprintf(stderr, "error encountered on file read\n");
        return 1;
    } else if (rd >= sizeof(fileData) - 1) {
        fprintf(stderr, "config file too big\n");
        return 1;
    }

    /* we have the whole config file in memory.  let's parse it ... */
    node = yajl_tree_parse((const char *) fileData, errbuf, sizeof(errbuf));

    /* parse error handling */
    if (node == NULL) {
        fprintf(stderr, "parse_error: ");
        if (strlen(errbuf)) fprintf(stderr, " %s", errbuf);
        else fprintf(stderr, "unknown error");
        fprintf(stderr, "\n");
        return 1;
    }

    /* ... and extract a nested value from the config file */
    {
        //const char * path[] = { "Logging", "timeFormat", (const char *) 0 };

注意:如果我尝试获取“DistServer”,它工作得很好,但“BuildType”返回 NULL。

        const char * path[] = { "BuildType", (const char *) 0 };
        //const char * path[] = { "DistServer", (const char *) 0 };
        yajl_val v = yajl_tree_get(node, path, yajl_t_string);
        if (v) printf("%s: %s\n", path[0], YAJL_GET_STRING(v));
        else   printf("no such node: %s\n", path[0] );
        //if (v) printf("%s/%s: %s\n", path[0], path[1], YAJL_GET_STRING(v));
        //else   printf("no such node: %s/%s\n", path[0], path[1]);
    }

    yajl_tree_free(node);

    return 0;
}

我正在使用最新的 YAJL 版本:2.0.2。

提前致谢!

编辑:

这是我的命令输出:

./parse_config  < ../../example/sample.config 
no such node: BuildType

注意,我正在运行的 parse_config 位于 build/example 目录中

我的 gcc 版本是: gcc 版本 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)

编辑 2 作为记录,这是随 YAJL 附带的示例代码。我故意使用它而不是我自己的代码,以确保问题不仅仅与我的应用程序有关。同时,我通过使用库提供的回调机制解决了这个问题,并使用

yajl_parse()
and 
yajl_complete_parse()

但我仍然想知道为什么原始代码不起作用。

I must be doing something wrong... Or this may be a bug in YAJL, but I highly doubt that.
I'm unable to retrieve the first element from a json object. I went back to the YAJL source to test this with the example parse_config.c and it failed as well.

Using the sample.config

/*
 * The configuration file for Yahoo! BrowserPlus, included in the YAJL
 * tree as a sample configuration file for parsing.
 *
 * This is the configuration file for BrowserPlus
 */

{
    // The type of build this is, which is accessible to JavaScript via
    // BrowserPlus.getPlatformInfo(); 
    // Different build types should only differ in signatures accepted
    // (BrowserPlus.crt) and configured distribution servers.
    "BuildType": "ephemeral",

    // the base url for the "primary" distribution server.  This server will
    // be the single source of truth for Permissions, and will used to 
    // attain services
    "DistServer": "http://browserplus.yahoo.com",

    // An array of "secondary" distribution servers, which will be checked
    // in order for services if the primary server has no components
    // available which match an issued require statement.
    "SecondaryDistServers": [
      "http://first.fictional.server",
      "http://second.fictional.server"
    ],

    // Logging Setup
    "Logging" :
    {
        // Log level.  Values: "debug"|"info"|"warn"|"error"|"fatal"|"off"
        "level": "BP_LOG_LEVEL",

        // Destination.  Values: "file"|"console"|"win32"
        "dest": "BP_LOG_DEST",

        // Log message layout.  Values: "standard"|"source"|"raw"
        "layout": "standard",

        // Time format.  Values: "utc"|"local"|"msec"
        "timeFormat": "utc",

        // File size in KB which will trigger a rollover
        "fileRolloverKB": 2048,

        // Whether to send file logging from each service to a distinct file.
        // Values: "combined"|"separate"
        "serviceLogMode": "combined"
    },

    // Daemon setup
    // Syntax: "Options": "option1 option2 etc"
    // -fg        run in foreground, log to console
    "Options":"",

    // Auto-shutdown daemon if idle for this time.  Use 0 for no auto-shutdown.
    "MaxIdleSecs": 5,

    // At the end of each BrowserPlus session a small web request is made
    // to yahoo to indicate that BrowserPlus was used.  This report includes
    // * information about the browser being used
    // * an "installation id", which is a unique token that's generated
    //   the first time BrowserPlus runs.
    //
    // By design, there is *no information* in this request that gives
    // Yahoo! information about:
    //   a) the site that the user is visiting (see, "url": false)
    //   b) who the user is (the installation token cannot be tracked to a
    //      specific user).
    //
    // This information is primarily captured to help Yahoo! understand
    // adoption and usage of the BrowserPlus platform.
    "UsageReporting":
    {
       "enabled": true,
       "url": false,
       "id": true
    },

    // "Breakpoints" is an array of strings holding named breakpoints.
    // Platform code checks for specific entries at certain key points, and if 
    // a matching entry is found here a DebugBreak will be performed.
    // For developers with Visual Studio installed, the DebugBreak will cause an
    // opportunity to perform just-in-time attachment of an existing or new 
    // debugger instance.
    // The currently-defined breakpoints are listed below:
    //      runServiceProcess - A DebugBreak is performed in the service 
    //                          "harness" just prior to service load.
    //      ax.FinalConstruct - A DebugBreak is performed at entry to 
    //                          FinalConstruct of the ActiveX plugin.
    //      PluginInit -        Very early in the NPAPI plugin initialization.
    //                          A wonderful spot to stop and set more
    //                          breakpoints.
    //"Breakpoints": ["runServiceProcess"],

    // How often we check for service updates.  We guarantee at least this
    // much time will pass between checks, though the true time may be
    // much more if sites which use browserplus are not visited.
    // The time is in seconds.
    "ServiceUpdatePollPeriod": 86400
}

I try and retrieve the "BuildType" <-- the first element of the JSON object.

I changed the parse_config.c file to do this... here's the code:

int
main(void)
{
    size_t rd;
    yajl_val node;
    char errbuf[1024];

    /* null plug buffers */
    fileData[0] = errbuf[0] = 0;

    /* read the entire config file */
    rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);

    /* file read error handling */
    if (rd == 0 && !feof(stdin)) {
        fprintf(stderr, "error encountered on file read\n");
        return 1;
    } else if (rd >= sizeof(fileData) - 1) {
        fprintf(stderr, "config file too big\n");
        return 1;
    }

    /* we have the whole config file in memory.  let's parse it ... */
    node = yajl_tree_parse((const char *) fileData, errbuf, sizeof(errbuf));

    /* parse error handling */
    if (node == NULL) {
        fprintf(stderr, "parse_error: ");
        if (strlen(errbuf)) fprintf(stderr, " %s", errbuf);
        else fprintf(stderr, "unknown error");
        fprintf(stderr, "\n");
        return 1;
    }

    /* ... and extract a nested value from the config file */
    {
        //const char * path[] = { "Logging", "timeFormat", (const char *) 0 };

Note: If I try to get "DistServer" it works just fine, but "BuildType" returns NULL.

        const char * path[] = { "BuildType", (const char *) 0 };
        //const char * path[] = { "DistServer", (const char *) 0 };
        yajl_val v = yajl_tree_get(node, path, yajl_t_string);
        if (v) printf("%s: %s\n", path[0], YAJL_GET_STRING(v));
        else   printf("no such node: %s\n", path[0] );
        //if (v) printf("%s/%s: %s\n", path[0], path[1], YAJL_GET_STRING(v));
        //else   printf("no such node: %s/%s\n", path[0], path[1]);
    }

    yajl_tree_free(node);

    return 0;
}

I'm using the latest YAJL version: 2.0.2.

Thanks in advance!

EDIT:

Here's my command output:

./parse_config  < ../../example/sample.config 
no such node: BuildType

Note, the parse_config that I'm running is in the one in the build/example directory

My gcc version is:
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)

EDIT 2
For the record, this is the sample code that comes with This code came with YAJL. I purposely used it instead of my own code to make sure that the problem wasn't only related to my application. Meanwhile I've worked around the problem by using the callback mechanism the library provides and using

yajl_parse()
and 
yajl_complete_parse()

But I still would like to know why the original code wasn't working.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

娜些时光,永不杰束 2024-12-09 18:49:22

我刚刚使用 2.0.2 版本遇到了同样的错误。这似乎是 yajl 中的一个错误,并已在 github 中修复(“验证 yajl_tree_get 中正确对象的长度”,提交 9c2948a33165c650122d131f31140c15321908f5)。

我已经应用了这个补丁,现在我可以很好地阅读第一个项目了。

I just hit this same bug, using version 2.0.2. It appears to be a bug in yajl and has been fixed in github ("validate the length of the correct object in yajl_tree_get", commit 9c2948a33165c650122d131f31140c15321908f5).

I've applied this patch and I'm now able to read the first item fine.

心的位置 2024-12-09 18:49:22

这看起来像是 yajl 中的一个 bug ...

哇,我没想到本来就是这样。

This looks like it's a bug in yajl...

Wow, I didn't think that would have been the case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文