I can't parse a JSON file when the nested structure is an array

sdk 2.1.0

nRF9160

Hi,

I need to parse a JSON file and for that I'm trying to use zephyr's json.h library.

Based on the automatic test file I built a piece of code for this task, but it is not working when the nested structure is an array...

Let me explain my tests:
1-when the nested structure is not declared as an array everything works as expected

struct test_nested {
    int nested_int;
    const char *nested_string[10];
    size_t nested_string_len;
};

struct test_struct {
    struct test_nested nested_obj_array;
    int some_int;
};

static const struct json_obj_descr nested_descr[] = {
    JSON_OBJ_DESCR_PRIM(struct test_nested, nested_int, JSON_TOK_NUMBER),
    JSON_OBJ_DESCR_ARRAY(struct test_nested, nested_string, 10, nested_string_len, JSON_TOK_STRING),
};

static const struct json_obj_descr test_descr[] = {
    JSON_OBJ_DESCR_OBJECT(struct test_struct, nested_obj_array, nested_descr),
    JSON_OBJ_DESCR_PRIM(struct test_struct, some_int, JSON_TOK_NUMBER),
};

struct test_struct test2;
    char encoded2[] = "{\"nested_obj_array\":"
                      "{\"nested_int\":22,"
                      "\"nested_string\":[\"string11\",\"string12\",\"string13\",\"string14\"]},"
                      "\"some_int\":123"
                      "}";
    LOG_DBG("encoded:%s", encoded2);
    const struct test_struct expected2 = {
        .nested_obj_array = {.nested_int = 22, .nested_string = {"string11", "string12", "string13", "string14"}, .nested_string_len = 4},
        .some_int = 123,
    };
    int ret;

    ret = json_obj_parse(encoded2, sizeof(encoded2) - 1, test_descr,
                         ARRAY_SIZE(test_descr), &test2);

    if (ret != (1 << ARRAY_SIZE(test_descr)) - 1) {
        LOG_DBG("Not all fields decoded correctly! ret:%d != size:%d", ret, (1 << ARRAY_SIZE(test_descr)) - 1);
    }
    if (test2.some_int != expected2.some_int) {
        LOG_DBG("some_int not decoded correctly.");
    }
    LOG_DBG("test2.some_int=%d", test2.some_int);
    if (test2.nested_obj_array.nested_string_len != expected2.nested_obj_array.nested_string_len) {
        LOG_DBG("Number of nested_string fields not decoded correctly. decode:%d, expected:%d", test2.nested_obj_array.nested_string_len, expected2.nested_obj_array.nested_string_len);
    }
    LOG_DBG("test2.nested_obj_array.nested_string_len=%d", test2.nested_obj_array.nested_string_len);

    for (int i = 0; i < expected2.nested_obj_array.nested_string_len; i++) {
        if (0 != strcmp(test2.nested_obj_array.nested_string[i], expected2.nested_obj_array.nested_string[i])) {
            LOG_DBG("test2.nested_obj_array.nested_string[%d] not decoded correctly", i);
        }
        LOG_DBG("test2.nested_obj_array.nested_string[%d]=%s", i, test2.nested_obj_array.nested_string[i]);
    }
    if (test2.nested_obj_array.nested_int != expected2.nested_obj_array.nested_int) {
        LOG_DBG("nested_int not decoded correctly.");
    }
    LOG_DBG("test2.nested_obj_array.nested_int=%d", test2.nested_obj_array.nested_int);

output:

[00:00:28.371,063] <dbg> encoded:{"nested_obj_array":{"nested_int":22,"nested_string":["string11","string12","string13","string14"]},"some_int":123}
[00:00:28.372,039] <dbg> test2.some_int=123
[00:00:28.372,589] <dbg> test2.nested_obj_array.nested_string_len=4
[00:00:28.373,229] <dbg> test2.nested_obj_array.nested_string[0]=string11
[00:00:28.373,901] <dbg> test2.nested_obj_array.nested_string[1]=string12
[00:00:28.374,542] <dbg> test2.nested_obj_array.nested_string[2]=string13
[00:00:28.375,213] <dbg> test2.nested_obj_array.nested_string[3]=string14
[00:00:28.375,854] <dbg> test2.nested_obj_array.nested_int=22

2-when the nested structure is declared as an array but only contains one argument, it also works

struct test_nested {
    int nested_int;
    const char *nested_string[10];
    size_t nested_string_len;
};

struct test_struct {
    struct test_nested nested_obj_array[5];
    size_t nested_obj_array_len;
    int some_int;
};

static const struct json_obj_descr nested_descr[] = {
    JSON_OBJ_DESCR_PRIM(struct test_nested, nested_int, JSON_TOK_NUMBER),
    JSON_OBJ_DESCR_ARRAY(struct test_nested, nested_string, 10, nested_string_len, JSON_TOK_STRING),
};

static const struct json_obj_descr test_descr[] = {
    JSON_OBJ_DESCR_OBJ_ARRAY(struct test_struct, nested_obj_array, 5, nested_obj_array_len,
                             nested_descr, ARRAY_SIZE(nested_descr)),
    // JSON_OBJ_DESCR_OBJECT(struct test_struct, nested_obj_array, nested_descr),
    JSON_OBJ_DESCR_PRIM(struct test_struct, some_int, JSON_TOK_NUMBER),
};

struct test_struct test3;
    char encoded3[] = "{\"nested_obj_array\":["
                      "{\"nested_int\":22,"
                      "\"nested_string\":[\"string11\",\"string12\",\"string13\",\"string14\"]}"
                      "],"
                      "\"some_int\":123"
                      "}";
    LOG_DBG("encoded:%s", encoded3);
    const struct test_struct expected3 = {
        .nested_obj_array = {[0] = {.nested_int = 22, .nested_string = {"string11", "string12", "string13", "string14"}, .nested_string_len = 4}
                             },
        .some_int = 123,
        .nested_obj_array_len = 1,
    };
    int ret;

    ret = json_obj_parse(encoded3, sizeof(encoded3) - 1, test_descr,
                         ARRAY_SIZE(test_descr), &test3);

    if (ret != (1 << ARRAY_SIZE(test_descr)) - 1) {
        LOG_DBG("Not all fields decoded correctly! ret:%d != size:%d", ret, (1 << ARRAY_SIZE(test_descr)) - 1);
    }
    if (test3.some_int != expected3.some_int) {
        LOG_DBG("some_int not decoded correctly.");
    }
    LOG_DBG("test3.some_int=%d", test3.some_int);
    if (test3.nested_obj_array_len != expected3.nested_obj_array_len) {
        LOG_DBG("Number of nested_obj_array_len fields not decoded correctly. decode:%d, expected:%d", test3.nested_obj_array_len, expected3.nested_obj_array_len);
    }
    LOG_DBG("test3.nested_obj_array_len=%d", test3.nested_obj_array_len);
    for (size_t j = 0; j < expected3.nested_obj_array_len; j++) {
        if (test3.nested_obj_array[j].nested_string_len != expected3.nested_obj_array[j].nested_string_len) {
            LOG_DBG("Number of nested_obj_array[%d].nested_string_len fields not decoded correctly. decode:%d, expected:%d", j, test3.nested_obj_array[j].nested_string_len, expected3.nested_obj_array[j].nested_string_len);
        }
        LOG_DBG("test3.nested_obj_array[%d].nested_string_len=%d", j, test3.nested_obj_array[j].nested_string_len);
        
        for (int i = 0; i < expected3.nested_obj_array[j].nested_string_len; i++) {
            if (0 != strcmp(test3.nested_obj_array[j].nested_string[i], expected3.nested_obj_array[j].nested_string[i])) {
                LOG_DBG("nested_obj_array[%d].nested_string[%d] not decoded correctly", j, i);
            }
            LOG_DBG("test3.nested_obj_array[%d].nested_string[%d]=%s", j, i, test3.nested_obj_array[j].nested_string[i]);
        }
        if (test3.nested_obj_array[j].nested_int != expected3.nested_obj_array[j].nested_int) {
                LOG_DBG("nested_int not decoded correctly.");
            }
        LOG_DBG("test3.nested_obj_array[%d].nested_int=%d", j, test3.nested_obj_array[j].nested_int);
    }

output:

[00:01:30.089,050] <dbg> encoded:{"nested_obj_array":[{"nested_int":22,"nested_string":["string11","string12","string13","string14"]}],"some_int":123}
[00:01:30.090,057] <dbg> test3.some_int=123
[00:01:30.090,606] <dbg> test3.nested_obj_array_len=1
[00:01:30.091,217] <dbg> test3.nested_obj_array[0].nested_string_len=4
[00:01:30.091,857] <dbg> test3.nested_obj_array[0].nested_string[0]=string11
[00:01:30.092,529] <dbg> test3.nested_obj_array[0].nested_string[1]=string12
[00:01:30.093,200] <dbg> test3.nested_obj_array[0].nested_string[2]=string13
[00:01:30.093,902] <dbg> test3.nested_obj_array[0].nested_string[3]=string14
[00:01:30.094,573] <dbg> test3.nested_obj_array[0].nested_int=22

3-when the nested structure is declared as an array but contains several arguments it does not parse correctly...

struct test_nested {
    int nested_int;
    const char *nested_string[10];
    size_t nested_string_len;
};

struct test_struct {
    struct test_nested nested_obj_array[5];
    size_t nested_obj_array_len;
    int some_int;
};

static const struct json_obj_descr nested_descr[] = {
    JSON_OBJ_DESCR_PRIM(struct test_nested, nested_int, JSON_TOK_NUMBER),
    JSON_OBJ_DESCR_ARRAY(struct test_nested, nested_string, 10, nested_string_len, JSON_TOK_STRING),
};

static const struct json_obj_descr test_descr[] = {
    JSON_OBJ_DESCR_OBJ_ARRAY(struct test_struct, nested_obj_array, 5, nested_obj_array_len,
                             nested_descr, ARRAY_SIZE(nested_descr)),
    // JSON_OBJ_DESCR_OBJECT(struct test_struct, nested_obj_array, nested_descr),
    JSON_OBJ_DESCR_PRIM(struct test_struct, some_int, JSON_TOK_NUMBER),
};

struct test_struct test3;
    char encoded3[] = "{\"nested_obj_array\":["
                      "{\"nested_int\":22,"
                      "\"nested_string\":[\"string11\",\"string12\",\"string13\",\"string14\"]},"
                      "{\"nested_int\":33,"
                      "\"nested_string\":[\"string21\",\"string22\",\"string23\",\"string24\"]}"
                      "],"
                      "\"some_int\":123"
                      "}";
    LOG_DBG("encoded:%s", encoded3);
    const struct test_struct expected3 = {
        .nested_obj_array = {[0] = {.nested_int = 22, .nested_string = {"string11", "string12", "string13", "string14"}, .nested_string_len = 4},
                             [1] = {.nested_int = 33, .nested_string = {"string21", "string22", "string23", "string24"}, .nested_string_len = 4}
                             },
        .some_int = 123,
        .nested_obj_array_len = 2,
    };
    int ret;

    ret = json_obj_parse(encoded3, sizeof(encoded3) - 1, test_descr,
                         ARRAY_SIZE(test_descr), &test3);

    if (ret != (1 << ARRAY_SIZE(test_descr)) - 1) {
        LOG_DBG("Not all fields decoded correctly! ret:%d != size:%d", ret, (1 << ARRAY_SIZE(test_descr)) - 1);
    }
    if (test3.some_int != expected3.some_int) {
        LOG_DBG("some_int not decoded correctly.");
    }
    LOG_DBG("test3.some_int=%d", test3.some_int);
    if (test3.nested_obj_array_len != expected3.nested_obj_array_len) {
        LOG_DBG("Number of nested_obj_array_len fields not decoded correctly. decode:%d, expected:%d", test3.nested_obj_array_len, expected3.nested_obj_array_len);
    }
    LOG_DBG("test3.nested_obj_array_len=%d", test3.nested_obj_array_len);
    for (size_t j = 0; j < expected3.nested_obj_array_len; j++) {
        if (test3.nested_obj_array[j].nested_string_len != expected3.nested_obj_array[j].nested_string_len) {
            LOG_DBG("Number of nested_obj_array[%d].nested_string_len fields not decoded correctly. decode:%d, expected:%d", j, test3.nested_obj_array[j].nested_string_len, expected3.nested_obj_array[j].nested_string_len);
        }
        LOG_DBG("test3.nested_obj_array[%d].nested_string_len=%d", j, test3.nested_obj_array[j].nested_string_len);
        
        for (int i = 0; i < expected3.nested_obj_array[j].nested_string_len; i++) {
            if (0 != strcmp(test3.nested_obj_array[j].nested_string[i], expected3.nested_obj_array[j].nested_string[i])) {
                LOG_DBG("nested_obj_array[%d].nested_string[%d] not decoded correctly", j, i);
            }
            LOG_DBG("test3.nested_obj_array[%d].nested_string[%d]=%s", j, i, test3.nested_obj_array[j].nested_string[i]);
        }
        if (test3.nested_obj_array[j].nested_int != expected3.nested_obj_array[j].nested_int) {
                LOG_DBG("nested_int not decoded correctly.");
            }
        LOG_DBG("test3.nested_obj_array[%d].nested_int=%d", j, test3.nested_obj_array[j].nested_int);
    }

output:

[00:00:55.869,873] <dbg> encoded:{"nested_obj_array":[{"nested_int":22,"nested_string":["string11","string12","string13","string14"]},{"nested_int":33,"nested_string":["string21","string22","string23","string24"]}],"some_int":123}
[00:00:55.871,215] <dbg> test3.some_int=123
[00:00:55.871,765] <dbg> test3.nested_obj_array_len=2
[00:00:55.872,375] <dbg> Number of nested_obj_array[0].nested_string_len fields not decoded correctly. decode:33, expected:4
[00:00:55.873,168] <dbg> test3.nested_obj_array[0].nested_string_len=33
[00:00:55.873,840] <dbg> test3.nested_obj_array[0].nested_string[0]=string11
[00:00:55.874,542] <dbg> test3.nested_obj_array[0].nested_string[1]=string12
[00:00:55.875,213] <dbg> test3.nested_obj_array[0].nested_string[2]=string13
[00:00:55.875,915] <dbg> test3.nested_obj_array[0].nested_string[3]=string14
[00:00:55.876,586] <dbg> test3.nested_obj_array[0].nested_int=22
[00:00:55.877,227] <dbg> Number of nested_obj_array[1].nested_string_len fields not decoded correctly. decode:243463, expected:4
[00:00:55.878,051] <dbg> test3.nested_obj_array[1].nested_string_len=243463
[00:00:55.878,753] <dbg> nested_obj_array[1].nested_string[0] not decoded correctly
[00:00:55.879,425] <dbg> test3.nested_obj_array[1].nested_string[0]=string22
[00:00:55.880,126] <dbg> nested_obj_array[1].nested_string[1] not decoded correctly
[00:00:55.880,798] <dbg> test3.nested_obj_array[1].nested_string[1]=string23
[00:00:55.881,500] <dbg> nested_obj_array[1].nested_string[2] not decoded correctly
[00:00:55.882,171] <dbg> test3.nested_obj_array[1].nested_string[2]=string24
[00:00:55.882,873] <dbg> nested_obj_array[1].nested_string[3] not decoded correctly
[00:00:55.883,544] <dbg> test3.nested_obj_array[1].nested_string[3]=
[00:00:55.884,216] <dbg> nested_int not decoded correctly.
[00:00:55.884,796] <dbg> test3.nested_obj_array[1].nested_int=537041920

What am I doing wrong?
Can you tell me how I can do this?

The final objective is to be able to parse a JSON with the following format:

{
  "nested_obj": [
    {
      "nested_int": 123,
      "nested_int2": 45,
      "nested_nested_obj": {
        "nested_nested_array": [
          "array1",
          "array2",
          "array3",
          "..."
        ]
      }
    },
    {
      "nested_int": 678,
      "nested_int2": 90,
      "nested_nested_obj": {
        "nested_nested_array": [
          "array1",
          "array2",
          "array3",
          "..."
        ]
      }
    }
  ],
  "some_string": "string"
}

Thanks!
Regards,
Ricardo

Related