Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I use the [] operator to access an array in nlohmann's C++ JSON library?

I'm using this JSON library for C++ in order to get information from Twitter's API, which returns a JSON array to my program (that I'm storing in responseData). But when I try to access "name" in the returned array, it doesn't allow me to.

Here is the error I'm getting after the termination of the process:

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

And here is the portion of the code that I'm dealing with:

    if(!responseData.empty()&&response_code==0) {
    std::cout<<responseData<<"<---\n";
    std::cout<<nlohmann::json::parse(responseData.c_str())["name"]<<"<!-\n";
}
like image 506
Gary S Avatar asked Feb 04 '23 07:02

Gary S


1 Answers

I know little to nothing about JSON and this is the first time I've come across the aforementioned library, but I find the question interesting, and the code is a challenge to read for me, so I'll try to explain my findings.

What happens is that for you to use the operator[]() to access the basic_json<> object by key, not an index, the object should be of internal type value_t::object (enum class value_t {}). If that condition fails, the exception you're seeing is thrown, with the actual type of the object reported. Now as far as I've understood, the type of the object is determined by the parser automatically based on the syntax of the string you pass to it. (OK, it can be more than just a string, there is a list of overloads for various entities that can represent a linear range of characters, as far as I understand.) "Array" is reported for data that starts with a square bracket "[".

Hence, to be sure what is going on, we need to see the actual data that the parser is receiving. There appears to be an automatic deduction of the type, as I've noted above, and only a certain range of operations is permitted for each type. To use the key-value accessor, it looks like the string should represent an object, and start with a curly brace "{".


Given the example data:

[
    {
    "trends":
    [
        {
        "name":"#XboxE3",
        "url":"http:\/\/twitter.com\/search?q=%23XboxE3",
        "promoted_content":null,
        "query":"%23XboxE3",
        "tweet_volume":371447
        },
        {
        "name":"Anthem",
        "url":"http:\/\/twitter.com\/search?q=Anthem",
        "promoted_content":null,
        "query":"Anthem",
        "tweet_volume":71013
        }
    ],
    "as_of":"2017-06-11T22:57:57Z",
    "created_at":"2017-06-11T22:55:37Z",
    "locations":
    [
        {
        "name":"Worldwide",
        "woeid":1
        }
    ]
    }
]

This appears to be an hierarchical data structure, so that to get to the "name" element, you need to descend towards it. The topmost element is an array denoted by []. It contains a single element - an unnamed object. We need the "trends" array. In that array, every element is an object again. So the query would look like this I think:

auto response = nlohmann::json::parse(responseData.c_str());
std::cout << response[0]["trends"][0]["name"];

operator[]()'s should be chainable, since they return a reference to the basic_json<> object. That's how operator chaining is implemented, and the chaining itself is a typical design. Same idea is used in operator<<() of std::cin.

like image 151
iksemyonov Avatar answered Feb 18 '23 05:02

iksemyonov