Search code examples
c++jsoncpp

Problems with getting a node out of JSON with jsoncpp


Im trying to use jsoncpp to parse a set of json. The json has been generated from a webpage with simplejson from a django object. I get it from a particular URL using libcurl. WHen I use the toStyledString() function on the root I get this printed out.

[
   {
      "fields" : {
         "desc" : "Carol King test",
         "format" : "1",
         "genre" : "Pop",
         "mount" : "CarolKing",
         "name" : "Carol King",
         "protocol" : "0",
         "songs" : [ 27, 28, 29, 30, 31, 32, 33, 34 ],
         "url" : "http://192.168.0.5:8000/CarolKing"
      },
      "model" : "music.playlist",
      "pk" : 2
   }
]

So it seems like I am getting the data right and its in a Json::Value class.

The problem is that im unable to get a particular node out of the json structure. This is the code im using.

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <curl/curl.h>
#include <string>
#include "Parameter.h"
#include "lib_json/json.h"

using namespace std;

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
    cout << "-->write_data " << endl;
    string buf = string(static_cast<char *>(ptr), size *nmemb);
    stringstream * response = static_cast<stringstream *>(stream);
    response->write(buf.c_str(), (streamsize)buf.size());
    return size * nmemb;

}


int main(int sys_argc, char ** sys_argv) {
    CURL *curl;
    CURLcode res;
    stringstream response;
    string error;

    char ** argv = sys_argv;


    string file = argv[1];
    Parameter *parms = new Parameter(file);
    parms->ReadParameters();

    cout << "URL: " << parms->GetParameter("URL");


    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();
    if(curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, parms->GetParameter("URL").c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
        res = curl_easy_perform(curl);

        cout << "Playlists-JSON: " << response.str() << endl;
        curl_easy_cleanup(curl);
    }

    Json::Value root;
    Json::Reader reader;

    bool parsingSuccessful = reader.parse(response.str(), root);

    if(!parsingSuccessful)
    {
        cout << "Failed to parse configuration. " << reader.getFormatedErrorMessages();
        return 16;
    }

    cout << "Pretty-Print: " << root.toStyledString() << endl;
    const Json::Value fields = root["fields"]["songs"];


    return 0;
}

because of another issue I'm not using the actual libjson.so shared library, im just pulling in the files and compiling them in with my source (I'm guessing this is bad, but that problem is not the point of this question). Below is how my src folder is structured.

.:
bird  Bird.cpp  fopen.cpp  fopen.h  lib_json  Parameter.cpp  Parameter.h

./lib_json:
autolink.h  features.h  json_batchallocator.h  json_internalarray.inl  json_reader.cpp  json_valueiterator.inl  reader.h    value.h
config.h    forwards.h  json.h                 json_internalmap.inl    json_value.cpp   json_writer.cpp         sconscript  writer.h

and this is the output of make.

    munderwo@bertha:/local/Documents/inthebackground/Box/Bird/bird/Debug$ make
Building file: ../src/lib_json/json_reader.cpp
Invoking: GCC C++ Compiler
g++ -I"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/include" -I"/local/Documents/inthebackground/Box/Bird/bird/src" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/lib_json/json_reader.d" -MT"src/lib_json/json_reader.d" -o"src/lib_json/json_reader.o" "../src/lib_json/json_reader.cpp"
Finished building: ../src/lib_json/json_reader.cpp

Building file: ../src/lib_json/json_value.cpp
Invoking: GCC C++ Compiler
g++ -I"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/include" -I"/local/Documents/inthebackground/Box/Bird/bird/src" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/lib_json/json_value.d" -MT"src/lib_json/json_value.d" -o"src/lib_json/json_value.o" "../src/lib_json/json_value.cpp"
Finished building: ../src/lib_json/json_value.cpp

Building file: ../src/lib_json/json_writer.cpp
Invoking: GCC C++ Compiler
g++ -I"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/include" -I"/local/Documents/inthebackground/Box/Bird/bird/src" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/lib_json/json_writer.d" -MT"src/lib_json/json_writer.d" -o"src/lib_json/json_writer.o" "../src/lib_json/json_writer.cpp"
Finished building: ../src/lib_json/json_writer.cpp

Building file: ../src/Bird.cpp
Invoking: GCC C++ Compiler
g++ -I"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/include" -I"/local/Documents/inthebackground/Box/Bird/bird/src" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/Bird.d" -MT"src/Bird.d" -o"src/Bird.o" "../src/Bird.cpp"
Finished building: ../src/Bird.cpp

Building file: ../src/Parameter.cpp
Invoking: GCC C++ Compiler
g++ -I"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/include" -I"/local/Documents/inthebackground/Box/Bird/bird/src" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/Parameter.d" -MT"src/Parameter.d" -o"src/Parameter.o" "../src/Parameter.cpp"
../src/Parameter.cpp: In member function ‘int Parameter::ReadParameters()’:
../src/Parameter.cpp:47: warning: comparison between signed and unsigned integer expressions
Finished building: ../src/Parameter.cpp

Building file: ../src/fopen.cpp
Invoking: GCC C++ Compiler
g++ -I"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/include" -I"/local/Documents/inthebackground/Box/Bird/bird/src" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/fopen.d" -MT"src/fopen.d" -o"src/fopen.o" "../src/fopen.cpp"
Finished building: ../src/fopen.cpp

Building target: Bird
Invoking: GCC C++ Linker
g++ -L"/local/Documents/inthebackground/Box/Bird/bird/Libraries/i386/lib" -o"Bird"  ./src/lib_json/json_reader.o ./src/lib_json/json_value.o ./src/lib_json/json_writer.o  ./src/Bird.o ./src/Parameter.o ./src/fopen.o   -lcurl
Finished building target: Bird

and from all of that I get the following output when I execute Bird

*Bird: ../src/lib_json/json_value.cpp:1025: Json::Value& Json::Value::resolveReference(const char*, bool): Assertion `type_ == nullValue || type_ == objectValue' failed.*
URL: 127.0.0.1:8000/playlist-->write_data 
Playlists-JSON: [{"pk": 2, "model": "music.playlist", "fields": {"protocol": "0", "name": "Carol King", "format": "1", "url": "http://192.168.0.5:8000/CarolKing", "mount": "CarolKing", "genre": "Pop", "songs": [27, 28, 29, 30, 31, 32, 33, 34], "desc": "Carol King test"}}]
Pretty-Print: [
   {
      "fields" : {
         "desc" : "Carol King test",
         "format" : "1",
         "genre" : "Pop",
         "mount" : "CarolKing",
         "name" : "Carol King",
         "protocol" : "0",
         "songs" : [ 27, 28, 29, 30, 31, 32, 33, 34 ],
         "url" : "http://192.168.0.5:8000/CarolKing"
      },
      "model" : "music.playlist",
      "pk" : 2
   }
]

I dont get the problem if I comment out this line

const Json::Value fields = root["songs"];

Im totally open to the fact that im doing something wrong here. But I just dont know what it is. So what is causing the error:

Bird: ../src/lib_json/json_value.cpp:1025: Json::Value& Json::Value::resolveReference(const char*, bool): Assertion `type_ == nullValue || type_ == objectValue' failed.

thanks for any help you can give.

Cheers

Mark


Solution

  • So once again it was a case of not understanding what was going on.

    Because my json structure was from a Django model it was actually and array of json (I know im going to get the terminology wrong here, and I apologize in advance). This could be found from the following code:

    cout << "type: " << root.type() << endl;
    

    with the following output

    type: 6
    

    in jsoncpp, this means an array of json. This can also be infered from the Styledoutput from the starting and ending square brackets. Also from this enum in value.h starting on line 23

    enum ValueType
       {
          nullValue = 0, ///< 'null' value
          intValue,      ///< signed integer value
          uintValue,     ///< unsigned integer value
          realValue,     ///< double value
          stringValue,   ///< UTF-8 string value
          booleanValue,  ///< bool value
          arrayValue,    ///< array value (ordered list)
          objectValue    ///< object value (collection of name/value pairs).
       };
    

    This was harder to tell because I only had one row of data coming out of my Django Model at the time. As I understand now, I was trying to do an operation for an objectValue type json structure, when I really needed to select the initial array position first.

    So to actually get at the url I need to do something like this.

    for(int i = 0; i < root.size(); i++)
        {
            cout << root[i]["fields"]["url"].asString() << endl;
        }
    

    which will get you

    http://192.168.0.5:8000/CarolKing
    http://192.168.0.5:8000/CarolKing2
    

    from the following json

    [
       {
          "fields" : {
             "desc" : "Carol King test",
             "format" : "1",
             "genre" : "Pop",
             "mount" : "CarolKing",
             "name" : "Carol King",
             "protocol" : "0",
             "songs" : [ 27, 28, 29, 30, 31, 32, 33, 34 ],
             "url" : "http://192.168.0.5:8000/CarolKing"
          },
          "model" : "music.playlist",
          "pk" : 2
       },
       {
          "fields" : {
             "desc" : "Second carol King",
             "format" : "1",
             "genre" : "Pop",
             "mount" : "CarolKing2",
             "name" : "Carol King 2",
             "protocol" : "0",
             "songs" : [ 26, 27, 28, 29, 30 ],
             "url" : "http://192.168.0.5:8000/CarolKing2"
          },
          "model" : "music.playlist",
          "pk" : 35
       }
    ]
    

    Im putting this here so that if anyone else comes across this they will at least have some way of finding out what is wrong.

    Cheers

    Mark