Why is Jansson's is_json_object() failing to recognize my JSON string?

22.1k Views Asked by At

I am new to C++ and cannot figure out how to strip some miscellaneous data from a string and then parse it as JSON.

I've ended up using the most documented JSON parser I could find - jansson. It seems excellent, although I'm stuck at the first hurdle.

My program receives a string in the following format:

5::/chat:{"name":"steve","args":[{"connection":"true"}, { "chatbody" : "I am the body" }]}

I've stripped everything outside the curly brackets with:

std::string str=message;
unsigned pos = str.find("{");
std::string string = str.substr (pos);

That leaves:

{
    "name": "steve",
    "args": [
        {
            "connection": "true"
        },
        {
            "chatbody": "I am the body"
        }
    ]
}

I'm stuck at stage one parsing this. I have converted the string to a char and then tried to use json_loads, but I don't get anything useful out...

The whole thing looks like this:

void processJson(string message)
{
    json_t *root;
    json_error_t error;
    size_t i;

    std::string str=message;
    unsigned pos = str.find("{");
    std::string str3 = str.substr (pos);

    const char * c = str.c_str();

    json_t *data, *sha, *name;

    root = json_loads(c, 0, &error);
    data = json_array_get(root, i);        
    cout << data;

    if(!json_is_object(root))
    {
      fprintf(stderr, "error: commit data %d is not an object\n", i + 1);
    }

}

I need to get the values out, but I just get 01, 02, 03....

is_json_object just says:

error: commit data 1068826 is not an object
error: commit data 1068825 is not an object
error: commit data 1068822 is not an object

What am I doing wrong and how can I properly format this? Ultimately I'll need to iterate over an array but cannot get past this. I'm sure this is just a beginner's mistake.

-EDIT-

Trying to avoid using Boost because of a strict size requirement.

4

There are 4 best solutions below

1
On

For JSON formatting, I've searched for a pretty print solution via C++ to no avail. Finally, I found some java code which I eventually converted to C++. Try the following for JSON formatting:

std::string formattedJson(char *json)
{
    std::string pretty;

    if (json == NULL || strlen(json) == 0)
    {
        return pretty;
    }

    std::string str     = std::string(json);
    bool        quoted  = false;
    bool        escaped = false;
    std::string INDENT  = "    ";
    int         indent  = 0;
    int         length  = (int) str.length();
    int         i;

    for (i = 0 ; i < length ; i++)
    {
        char ch = str[i];

        switch (ch)
        {
            case '{':
            case '[':
                pretty += ch;

                if (!quoted)
                {
                    pretty += "\n";

                    if (!(str[i+1] == '}' || str[i+1] == ']'))
                    {
                        ++indent;

                        for (int j = 0 ; j < indent ; j++)
                        {
                            pretty += INDENT;
                        }
                    }
                }

                break;

            case '}':
            case ']':
                if (!quoted)
                {
                    if ((i > 0) && (!(str[i-1] == '{' || str[i-1] == '[')))
                    {
                        pretty += "\n";

                        --indent;

                        for (int j = 0 ; j < indent ; j++)
                        {
                            pretty += INDENT;
                        }
                    }
                    else if ((i > 0) && ((str[i-1] == '[' && ch == ']') || (str[i-1] == '{' && ch == '}')))
                    {
                        for (int j = 0 ; j < indent ; j++)
                        {
                            pretty += INDENT;
                        }
                    }
                }

                pretty += ch;

                break;

            case '"':
                pretty += ch;
                escaped = false;

                if (i > 0 && str[i-1] == '\\')
                {
                    escaped = !escaped;
                }

                if (!escaped)
                {
                    quoted = !quoted;
                }

                break;

            case ',':
                pretty += ch;

                if (!quoted)
                {
                    pretty += "\n";

                    for (int j = 0 ; j < indent ; j++)
                    {
                        pretty += INDENT;
                    }
                }

                break;

            case ':':
                pretty += ch;

                if (!quoted)
                {
                    pretty += " ";
                }

                break;

            default:
                pretty += ch;

                break;
        }
    }

    return pretty;
}
0
On

Casablanca (REST C++ SDK) has a pretty nice JSON parser which you can use even if you don't use the HTTP functionality.

You can extract the JSON parser files into a static library and link it with your existing project. The files to extract are:

src\json\json.cpp
src\json\json_parsing.cpp
src\json\json_serialization.cpp
src\utilities\asyncrt_utils.cpp

include\cpprest\json.h
include\cpprest\xxpublic.h
include\cpprest\basic_types.h
include\cpprest\asyncrt_utils.h

I can confirm this works as I've used it recently as a static library for my projects.

I also tried to use Jansson but the parser in Casablanca simply feels easier to use and has better Unicode support.

9
On

I'm not familiar with whatever JSON library you're using, but here's a few suggestions about what might be wrong.

  • size_t i is not initialized to anything, and is then passed into json_array_get.
  • json_array_get is passed the root object, which is not a JSON array, but a JSON object. In JSON terminology, root["args"] would be the array.

Of course, depending on the semantics of your JSON library, neither of this might be issues at all, but they seem like red flags to me.

3
On

You could always use an existing solution like Boost's property tree, which has a function for automatically parsing JSON files. It's literally as easy as adding these two headers:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

And then adding this small snippet of code in, where jsonfile obviously means your filename.

boost::property_tree::ptree jsontree;
boost::property_tree::read_json(jsonfile, jsontree);

If you ever want to extract information from your JSON tree, you can do it like this, where type is the type of the data you want you extract, and insert.key.path.here is the path to your key, with each parent key separated by periods.

jsonfile.get<type>(insert.key.path.here);

In addition, I don't believe the JSON string you have there is valid. You did good removing the excess around the JSON string itself, but I believe there's a problem here:

"connection" : true,

You can check the validity of your JSON string here: http://jsonformatter.curiousconcept.com/