Разбор json с помощью YAJL в C

Должно быть, я делаю что-то не так... Или это может быть ошибка в 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()

Но я все же хотел бы знать, почему исходный код не работал.


person Steve Lazaridis    schedule 05.09.2011    source источник
comment
Я попробовал ваш код с той же версией yajl, но BuildType возвращает мне ephemeral...   -  person Fred    schedule 05.09.2011
comment
Действительно!? Это интересно... какую команду ты запускаешь? Какую версию gcc вы используете?   -  person Steve Lazaridis    schedule 05.09.2011
comment
Я не думаю, что это проблема, но вы неправильно завершаете fileData нулевым байтом. Добавьте fileData[rd] = '\0';, где это уместно.   -  person Per Johansson    schedule 05.09.2011
comment
Та же версия, что и у вас, а также ubuntu. Команда, которую я только что набрал ./a.out < config.json. Я определил fileData как fileData[4096] = {0}.   -  person Fred    schedule 05.09.2011
comment
@Фред, спасибо за отзыв. Приведенный выше код в основном является примером кода, поставляемого с библиотекой. Кто-нибудь еще видит результаты, аналогичные @Fred?   -  person Steve Lazaridis    schedule 06.09.2011


Ответы (2)


Я только что столкнулся с этой же ошибкой, используя версию 2.0.2. Похоже, это ошибка в yajl, и она была исправлена ​​в github («проверьте длину правильного объекта в yajl_tree_get», зафиксируйте 9c2948a33165c650122d131f31140c15321908f5).

Я применил этот патч, и теперь я могу нормально прочитать первый элемент.

person Phil    schedule 10.09.2011
comment
Окончательно! еще один человек с этой проблемой :) Спасибо за обновление! - person Steve Lazaridis; 10.09.2011
comment
Спасибо! Я также провел пару часов, задаваясь вопросом, что я делаю неправильно, отказываясь верить, что что-то настолько фундаментальное, как это, может пройти через набор тестов. - person jdo; 03.11.2011

Похоже, это ошибка в yajl...

Вау, не думал, что так бывает.

person Steve Lazaridis    schedule 10.09.2011