16

I'm trying to parse a JSON string encoded with PHP and sent over TCP to a C++ client.

My JSON strings are like this:

{"1":{"name":"MIKE","surname":"TAYLOR"},"2":{"name":"TOM","surname":"JERRY"}}

On the C++ client I'm using the jsoncpp libraries:

void decode()
{
    string text =     {"1":{"name":"MIKE","surname":"TAYLOR"},"2":{"name":"TOM","surname":"JERRY"}};
    Json::Value root;
    Json::Reader reader;
    bool parsingSuccessful = reader.parse( text, root );
    if ( !parsingSuccessful )
    {
        cout << "Error parsing the string" << endl;
    }
    const Json::Value mynames = root["name"];
    for ( int index = 0; index < mynames.size(); ++index )  
    {
        cout << mynames[index] << endl;
    }
}

The problem is that I'm not getting anything as output, not even the error about the parsing(if any). Could you possibly help me to understand what I'm doing wrong ?

mistapink
  • 1,926
  • 1
  • 26
  • 37
Podarce
  • 473
  • 1
  • 6
  • 22
  • 1
    this code won't even compile. First of all you need to escape your json string to C++ string. If needed for bigger strings please refer to [link](https://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c) solution – kalimba Nov 14 '17 at 11:47
  • @kalimba You are absolutely right. I’m parsing a tcp stream, but I wrote a function with a string to explain the code I wrote. I forgot the escape sequence. Thanks for the head up. – Podarce Nov 14 '17 at 15:06

2 Answers2

29

Your problem is: there is no root["name"]. Your document should be like this:

{ "people": [{"id": 1, "name":"MIKE","surname":"TAYLOR"}, {"id": 2, "name":"TOM","surname":"JERRY"} ]}

And your code like this:

void decode()
{
    string text ="{ \"people\": [{\"id\": 1, \"name\":\"MIKE\",\"surname\":\"TAYLOR\"}, {\"id\": 2, \"name\":\"TOM\",\"surname\":\"JERRY\"} ]}";
    Json::Value root;
    Json::Reader reader;
    bool parsingSuccessful = reader.parse( text, root );
    if ( !parsingSuccessful )
    {
        cout << "Error parsing the string" << endl;
    }

    const Json::Value mynames = root["people"];

    for ( int index = 0; index < mynames.size(); ++index )
    {
        cout << mynames[index] << endl;
    }
}

If you want to keep your data as is:

void decode()
{
  //string text ="{ \"people\": [{\"id\": 1, \"name\":\"MIKE\",\"surname\":\"TAYLOR\"}, {\"id\": 2, \"name\":\"TOM\",\"surname\":\"JERRY\"} ]}";
  string text ="{ \"1\": {\"name\":\"MIKE\",\"surname\":\"TAYLOR\"}, \"2\": {\"name\":\"TOM\",\"surname\":\"JERRY\"} }";
  Json::Value root;
  Json::Reader reader;
  bool parsingSuccessful = reader.parse( text, root );
  if ( !parsingSuccessful )
  {
    cout << "Error parsing the string" << endl;
  }

  for( Json::Value::const_iterator outer = root.begin() ; outer != root.end() ; outer++ )
  {
    for( Json::Value::const_iterator inner = (*outer).begin() ; inner!= (*outer).end() ; inner++ )
    {
      cout << inner.key() << ": " << *inner << endl;
    }
  }
}

Traverse the root object directly, using iterators (don't treat it as it was an array.

If Json::Reader doesn't work, try Json::CharReader instead:

void decode()
{
  string text ="{\"1\":{\"name\":\"MIKE\",\"surname\":\"TAYLOR\"},\"2\":{\"name\":\"TOM\",\"surname\":\"JERRY\"}}";

  Json::CharReaderBuilder builder;
  Json::CharReader * reader = builder.newCharReader();

  Json::Value root;
  string errors;

  bool parsingSuccessful = reader->parse(text.c_str(), text.c_str() + text.size(), &root, &errors);
  delete reader;

  if ( !parsingSuccessful )
  {
    cout << text << endl;
    cout << errors << endl;
  }

  for( Json::Value::const_iterator outer = root.begin() ; outer != root.end() ; outer++ )
  {
    for( Json::Value::const_iterator inner = (*outer).begin() ; inner!= (*outer).end() ; inner++ )
    {
      cout << inner.key() << ": " << *inner << endl;
    }
  }
}
p-a-o-l-o
  • 9,807
  • 2
  • 22
  • 35
  • Thanks for your answer, sir. I have some questions on given answer, please. 1) why do I need to write the text string like this ? My string comes directly from the php json_encode, so it should be correct 2) If I would like to keep the associative array as "1":{},"2":{} , can I do it and just prepend the root "people" ? I'm a bit confused. – Podarce Nov 14 '17 at 11:39
  • Made some tests with the code, the problem is in bool parsingSuccessful = reader.parse( text, root ); Looks like nothings gets executed past that line. Could it be for the deprecated use of Json::Reader reader ? Please note that I don't have compiler errors. – Podarce Nov 14 '17 at 12:05
  • Added a CharReader-based example. – p-a-o-l-o Nov 14 '17 at 13:29
  • 1
    there's another example here: https://neverfriday.com/2013/07/26/learning-jsoncpp/ –  Apr 17 '18 at 00:27
  • 1
    Use C++11 feature: R prefix for making a raw string. – isnullxbh Apr 20 '18 at 09:58
  • @isnullxbh is quite right, the data string is much easier written without all that tedious escaping as `string text = R"json({"1":{"name":"MIKE","surname":"TAYLOR"}, "2":{"name":"TOM","surname":"JERRY"}})json";` – FeRD Jun 19 '19 at 23:58
  • 2
    `Json::Reader()` shows as deprecated; use CharReader and CharReaderBuilder. – Technophile Mar 11 '21 at 17:52
11

You can also read from a stringstream:

std::stringstream sstr(stringJson);
Json::Value json;
sstr >> json;
waynix
  • 501
  • 3
  • 13