6

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";
}
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Gary S
  • 313
  • 1
  • 4
  • 9

1 Answers1

11

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.

iksemyonov
  • 4,106
  • 1
  • 22
  • 42
  • Thanks, that's helpful. So what would be the proper way to access it without using the `operator[]()`? – Gary S Jun 11 '17 at 00:35
  • @GaryS To be able to tell for sure, we need to see the JSON string you're receiving, given that's not confidential data. Can you save it in a string and paste somewhere? – iksemyonov Jun 11 '17 at 10:13
  • @GaryS You can use `operator[]()`, but with an integer index, when the object is an array. Since you expect the object to be addressable by a string key, and it's not, that probably means you're not receiving the data you intend or the actual format of the data is different from your expectations. That's why we need the string itself. – iksemyonov Jun 11 '17 at 10:30
  • here is an example of what I'm receiving: https://pastebin.com/45agMNnb – Gary S Jun 11 '17 at 23:01
  • @GaryS See the update to my answer. It addresses the data you've attached. – iksemyonov Jun 12 '17 at 13:12
  • Ah so it returns some sort of multidimensional array. Everything makes sense now. Thanks, you really helped! – Gary S Jun 12 '17 at 20:17
  • @GaryS You're welcome! Please note that it's not a *multi-dim* array, it's a series of nested one-dimensional arrays. Does that make sense? – iksemyonov Jun 12 '17 at 20:22
  • @GaryS The syntax looks similar to that of a multi-dim array (i.e. a series of `[]`'s) but it's just a coincidence of chaining a few `operator[]()`'s. Some of the index arrays, some index dictionaries (key-value maps). – iksemyonov Jun 12 '17 at 20:25
  • I see now. Thanks again! – Gary S Jun 12 '17 at 23:42