Problems with getting a node out of JSON with jsoncpp

Mark Lakewood picture Mark Lakewood · Dec 14, 2010 · Viewed 15.1k times · Source

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

Answer

Mark Lakewood picture Mark Lakewood · Dec 15, 2010

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