nlohmann / json

JSON for Modern C++
https://json.nlohmann.me
MIT License
41.25k stars 6.57k forks source link

Json parsed from raw string does not interpret lists of objects like json parsed from file #4341

Closed schil227 closed 2 months ago

schil227 commented 2 months ago

Description

Depending on if json is loaded from a file, or if it is parsed from a string, it exhibits different behavior when iterating over lists of objects (see Reproduction steps for an example). When the json is read from a file, it iterates over the list of objects successfully. When the json is parsed from a string, an error is thrown.

The same behavior is observed when using the "json" syntax, e.g. json j2 = { {"pi", 3.141}, ...

Reproduction steps

Consider the following json:

{
    "fruits": [
        {
            "key": "fruit.banana",
            "value": "0"
        },
        {
            "key": "fruit.apple",
            "value": "4"
        }
    ]
}

It contains an entry "fruits", which is a list of objects. I iterate over this list of object and make a change, like so:

    for(int x = 0; x < fruit_json["fruits"].size(); x++){
        std::cout << "Item: " << fruit_json["fruits"][x]["key"] << std::endl;

        fruit_json["fruits"][x]["value"]  = std::to_string(x*4);
    }

(where fruit_json is a nlohmann::json object, containing the above json example)

When fruit_json is created from loading a file, the loop is processed correctly:

    std::ifstream ifs("fruits.json");
    json jf = json::parse(ifs);

    for(int x = 0; x < fruit_json["fruits"].size(); x++){
        std::cout << "Item: " << fruit_json["fruits"][x]["key"] << std::endl;

        fruit_json["fruits"][x]["value"]  = std::to_string(x*4);
    }

(fruits.json contains the json object above)

Output:

Item: "fruit.banana" Item: "fruit.apple"

However, when the same object is parsed from a string, it does not successfully traverse the list:

    nlohmann::json fruit_json = R"(
    {
        "fruits": [
            {
                "key": "fruit.banana",
                "value": "0"
            },
            {
                "key": "fruit.apple",
                "value": "4"
            }
        ]
    }
    )";

    for(int x = 0; x < fruit_json["fruits"].size(); x++){
        std::cout << "Item: " << fruit_json["fruits"][x]["key"] << std::endl;

        fruit_json["fruits"][x]["value"]  = std::to_string(x*4);
    }

Output:

terminate called after throwing an instance of 'nlohmann::detail::type_error' what(): [json.exception.type_error.305] cannot use operator[] with a string argument with string

Expected vs. actual results

I would expect the behavior to be the same, regardless of where the json is sourced from. I would also expect any json, regardless of the source, to iterate over lists of objects in the same manner as the code provided in the reproduction steps.

Minimal code example

nlohmann::json fruit_json = R"(
{
    "fruits": [
        {
            "key": "fruit.banana",
            "value": "0"
        },
        {
            "key": "fruit.apple",
            "value": "4"
        }
    ]
}
)";

for(int x = 0; x < fruit_json["fruits"].size(); x++){
    std::cout << "Item: " << fruit_json["fruits"][x]["key"] << std::endl;

    fruit_json["fruits"][x]["value"]  = std::to_string(x*4);
}

Error messages

terminate called after throwing an instance of 'nlohmann::detail::type_error'
  what():  [json.exception.type_error.305] cannot use operator[] with a string argument with string

Compiler and operating system

gcc 10.2.1, Ubuntu 20.04

Library version

3.9.1

Validation

nlohmann commented 2 months ago

You forgot the _json suffix for the string:

    nlohmann::json fruit_json = R"(
{
    "fruits": [
        {
            "key": "fruit.banana",
            "value": "0"
        },
        {
            "key": "fruit.apple",
            "value": "4"
        }
    ]
}
)"_json;

Without that string, you just cast the string to a json, but do not parse it.

schil227 commented 2 months ago

Ah... yes you're right. Thank you very much for the quick reply! Love the library btw.