In order to realize a project of mine I started looking for a Qt library for mapping JSON data to Qt objects.

I came over a couple of solutions but none of them made me happy. So in the last weekend I wrote my own library : QJson

The library is based on Qt toolkit and converts JSON data to QVariant instances.
JSON arrays will be mapped to QVariantList instances, while JSON’s objects will be mapped to QVariantMap.
The JSON parser is generated with Bison, while the scanner has been coded by me.

Usage

Converting JSON’s data to QVariant instance is really simple:

// create a JSonDriver instance
JSonDriver driver;
bool ok;
// json is a QString containing the data to convert
QVariant result = driver.parse (json, &ok);

Suppose you’re going to convert this JSON data:

{
“encoding” : “UTF-8″,
“plug-ins” : [
"python",
"c++",
"ruby"
],
“indent” : { “length” : 3, “use_space” : true }
}

The following code would convert the JSON data and parse it:

JSonDriver driver;
bool ok;
QVariantMap result = driver.parse (json, &ok).toMap();
if (!ok) {
    qFatal("An error occured during parsing");
    exit (1);
}
qDebug() << "encoding:" << result["encoding"].toString();
qDebug() << "plugins:";
foreach (QVariant plugin, result["plug-ins"].toList()) {
    qDebug() << "\t-" << plugin.toString();
}
QVariantMap nestedMap = result["indent"].toMap();
qDebug() << "length:" << nestedMap["length"].toInt();
qDebug() << "use_space:" << nestedMap["use_space"].toBool();

The output would be:

encoding: “UTF-8″
plugins:
- “python”
- “c++”
- “ruby”
length: 3
use_space: true

Requirements

QJson requires:

  • cmake
  • Qt

Obtain the source

Actually QJson code is hosted on KDE subversion repository. You can download it using a svn client:

svn co svn://anonsvn.kde.org/home/kde/trunk/playground/libs/qjson

For more informations visit QJson site

Tags: , , , ,
45 Responses to “QJson: a Qt-based library for mapping JSON data to QVariant objects”
  1. Anonymous says:

    Looks good, but did you look at http://www.fredemmott.co.uk/blog_161?

    Maybe you could cooperate?

    • Flavio says:

      Before creating QJson I tried JsonQt. I discovered that it works only when receiving JSON objects and not arrays (if you try to map something like [50, "foo"] it reports a parsing error). I wanted to fix this problem but reading the code I discovered that Fred Emmott didn’t use a parser generator.
      I think that using a parser generator can help a lot and so I came out with QJson.

  2. Thanks a lot! I need this very functionality for a project a mine, but hadn’t got around to writing the code yet. The API I had in mind would work exactly the same as yours =) Thanks again!

  3. Thanks for this library, it’s opening many technological doors ^^
    I’m a lazy coder too …

  4. Anonymous says:

    You might like to also add ‘bison’ to your requirements list.

    • Flavio says:

      No Bison is not a requirement for the final developers. It’s needed just when the grammar file is changed, and this shouldn’t be done (unless JSON specs change or a bug in my parser is found).
      All the files generated by Bison are shipped with QJson sources

  5. Hi,

    I’m using this code in a project of mine (as I was already suggesting above) and it is working great! I just discovered one bug though:
    When you input a JSON string containing the following string: “\\n” (using C syntax, so that’s a single backslash and an n), you get this very string “\\n” in the QVariantMap. However, according to JSON.org, “\\n” is the official escape sequence for a newline, and so should be converted to “\n” (which is a newline character, still using C syntax).
    If you do not translate “\\n” back to “\n”, it becomes impossible to do a two-way conversion from a QVariantMap with strings than contain newlines to JSON and back.
    Hope I made it clear what I meant :)

    Greetings,
    Arend jr.

    • Flavio says:

      JSon grammar description reports:
      char
      any-Unicode-character-
      except-”-or-\-or-
      control-character
      \”
      \\
      \/
      \b
      \f
      \n
      \r
      \t
      \u four-hex-digits

      So the newline char is \n while \\ is just to be interpreted as the escaping of \
      Take a look at the TestJSonDriver::testEscapeChars method.

      Maybe I am wrong or I didn’t understand you, feel free to correct me.

      • Thanks for your reply!

        I just took a look at the testEscapeChars method, and found this:

        QString json = “[\"\b \f \n \r \t \", \" \\ \\/ \\\" \"]“;
        QVariantList list;
        list.append (QVariant(“\b \f \n \r \t “));
        list.append (QVariant(” \\ \\/ \\\” “));

        The JSON string you are using here as input is not valid from what I can tell, because “\n”, “\r”, etc. are not valid inside a JSON string. So these lines should IMHO become:

        QString json = “[\"\\b \\f \\n \\r \\t \", \" \\\\ \\/ \\\" \"]“;
        QVariantList list;
        list.append (QVariant(“\b \f \n \r \t “));
        list.append (QVariant(” \\ / \” “));

        With these changes, I think the test should be correct.

        Finally, here is the unescaping function I use now to properly unescape the strings:

        QString unescapeJsonString(const QString &string) {
        QString unescapedString;
        unescapedString.reserve(string.length());

        for (int i = 0; i < string.length(); i++) {
        QChar character = string[i];
        if (character == ‘\\’) {
        if (i == string.length() – 1) {
        qDebug() << “json_parser: Unfinished escape sequence!”;
        break;
        }
        i++;
        switch (string[i].unicode()) {
        case ‘”‘:
        unescapedString += ‘”‘;
        break;
        case ‘\\’:
        unescapedString += ‘\\’;
        break;
        case ‘b’:
        unescapedString += ‘\b’;
        break;
        case ‘f’:
        unescapedString += ‘\f’;
        break;
        case ‘n’:
        unescapedString += ‘\n’;
        break;
        case ‘r’:
        unescapedString += ‘\r’;
        break;
        case ‘t’:
        unescapedString += ‘\t’;
        break;
        default:
        qDebug() << “json_parser.cc: Unrecognized escape sequence!”;
        unescapedString += string[i];
        break;
        }
        } else {
        unescapedString += character;
        }
        }
        return unescapedString;
        }

        Greetings,
        Arend jr.

        • Flavio says:

          Thanks for the report Arend. I have fixed the scanner and I have updated the test code.
          Now you shouldn’t need to use your function.

          Feel free to contact me for clarifications.

  6. PS.: The same goes for other control characters.

  7. no Chinese support says:

    I found QJson doesn’t support Chinese.

  8. Phillip Jacobs says:

    Hey Flavio. I’m a bit new to Qt, and am having trouble using your library to grab data from a twitter feed. The json string goes like so:
    [
    {“user”:
    {“followers_count”:100,”description”:”Google: nickhere”,”url”:”",”profile_image_url”:”",”protected”:false,”location”:”Austin, Texas”,”screen_name”:”nickhere”,”name”:”nickhere”,”id”:00000000},
    “text”:”msghere”,
    “truncated”:false,
    “favorited”:false,
    “in_reply_to_user_id”:null,
    “created_at”:”Mon Mar 30 03:20:54 +0000 2009″,
    “source”:”web”,
    “in_reply_to_status_id”:null,
    “id”:00000000000},
    etc…

    Do you think you could help me out? I looked through the documentation of QVariant, and QVariantMap, and am having no luck iterating through the parsed result. It doesn’t seem like there’s a QVariant::toArray(), which might be a better fit.

    At any rate, thanks for taking a look.

  9. Prakash says:

    First I managed to make a .pro file and build it on windows. Seems to work good. Thanks for your effort too.
    One question though.

    from json_driver.h
    @param ok if a conversion error occurs, *ok is set to false; otherwise *ok is set to true.

    and the example code says
    # if (status) {
    # qFatal(“An error occured during parsing”);
    # exit (1);
    # }

    So is status being true is a error or not and error? The sample code runs things status is an error and exists, but it does not print any error info.

    • Flavio says:

      You should checkout latest version of QJson from SVN. I have committed lots of changes (and even more are coming).

      Now the right syntax is
      driver.parse(json, &ok);
      if (!ok) {
      qCritical(“we got an error!”);
      }

      I have updated the post reflecting this API change.

      • Prakash says:

        Thanks,

        I am pretty sure that I had checked out the code from the svn repo last night. So it should be pretty latest?

        Also, I am kinda not sure tieing QJson with a particular compiler and few platforms, does the compiler you prefered do something special?

        • Flavio says:

          I have commited new changes this morning (currently my timezone is GMT+1), so please check out the code.

          The code is based on Qt, so I think that all compilers supported by Qt should work fine.

        • Prakash says:

          yes it does except that for some reason snprintf gives compiler error, (undefined) since it is a debuging instruction, I have commented that out.

          Yes, I have checkout the latest few min back, things has changed.

          Thanks.

  10. Prakash says:

    Hi looks like snprintf is not a portable function, can you consider using QString::number instead?

  11. Prakash says:

    Numbers are stroed as QVariant::Int, which is incorrect, large numbers in the json file is returned as negative value, I guess it is logical that all numbers be just one type, Double or float.

  12. rap dinle says:

    fine.. thanks.

  13. nomexs says:

    it’s great thanks!

  14. [...] de las dependencias kopete-facebook es qjson, una librería que extiende Qt para añadirle un JSON Parser, necesario para procesar los datos [...]

  15. steven says:

    Hi guys, I just want to know how to build QJson under windows, i’m using qt creator under vista.

    I tried to use 1. shared lib and 2. simply import the source files to an existing GUI project, both didn’t work, I got error like this:
    ===
    …../debug/moc_serializerrunnable.cpp:42: error: definition of static data member ‘SerializerRunnable::staticMetaObject’ of dllimport’d class
    ===

    I just started to learn Qt, please help me…

  16. steven says:

    And I also got a bunch of warnings like this:
    ===
    …../serializer.cpp:36: warning: non-inline function ‘QJson::Serializer::~Serializer()’ is defined after prior declaration as dllimport: attribute ignored
    ===

  17. Deepak says:

    Hi,

    I get the following log/error when I try to run ‘Configure’ using Cmake (version 2.6 patch4)

    The C compiler identification is GNU
    The CXX compiler identification is GNU
    Check for working C compiler: C:/Qt/2009.03/mingw/bin/gcc.exe
    Check for working C compiler: C:/Qt/2009.03/mingw/bin/gcc.exe — works
    Detecting C compiler ABI info
    Detecting C compiler ABI info – done
    Check for working CXX compiler: C:/Qt/2009.03/mingw/bin/g++.exe
    Check for working CXX compiler: C:/Qt/2009.03/mingw/bin/g++.exe — works
    Detecting CXX compiler ABI info
    Detecting CXX compiler ABI info – done
    CMake Error at CMakeLists.txt:24 (qt4_wrap_cpp):
    Unknown CMake command “qt4_wrap_cpp”.

    Can some one let me knw how to fix this.

  18. Deepak says:

    Managed to solve it,

    1. Make sure mingw is set i the classpath
    2. run the following commands to install QJson

    cmake -G “MinGW Makefiles” ..
    mingw32-make
    mingw32-make install

  19. Deepak says:

    Hi,

    On building the project after including the qtjson header files, I get this error
    undefined reference to `_imp___ZN5QJson6ParserC1Ev’
    undefined reference to `_imp___ZN5QJson6ParserD1Ev

    Can any one throw some light this?

    • LAXC says:

      I have the same error, someone to know how solve it?

      • Flavio says:

        Could you give me more details?
        What operative system, version of Qt and cmake are you using?

        What version of qjson are you trying to build?

        • quentin says:

          Hello I need help, I have problem with qjson
          I have same error that Deepak.
          I use windows, Qt 4.6.0.
          The version of qjson is qjson-0.7.1.

          • LX says:

            This is because you have to integrate the qjson0.dll in your .pro-File

            e.g.
            “LIBS += -L../lib -lqjson0″

            if you have a fileconstellation like
            c:/myproject/helloqjason.pro
            c:/lib/qjson0.dll

            maybe you also need
            “DEFINES += QMAKE_BUILD”

            to get the qjson0.dll file i had to build the qjson.pro which comes with a new package in the gitorious-repository.
            —————————-
            (I recogniced this solution when i looked at the example in tests/parser/parser.pro)

  20. Girija says:

    Hi,

    how to parse the following json output through QJson ?

    [{"id":2,"name":"AAA"},{"id":1,"name":"BBB"}].

    Please help me. Thanks in advance

    • Flavio says:

      Just use this code:

      // create a JSonDriver instance
      QJson::Parser parser;
      bool ok;
      
      // json is a QString containing the data to convert
      QVariant result = parser.parse (json, &ok);

      You can find more details here.

  21. Girija says:

    I am using the following code,
    QJson::Parser parser;
    bool ok;
    QVariantMap result = parser.parse (cityReply->readAll(), &ok).toMap();
    if (!ok) {
    qFatal(“An error occurred during parsing”);
    exit (1);
    }
    qDebug() << "Name :" <readAll() in messagebox then I can view the webservice result (json String).

    Please help me. Thanks in advance

  22. Girija says:

    I am using the following code,
    QJson::Parser parser;
    bool ok;
    QVariantMap result = parser.parse (cityReply->readAll(), &ok).toMap();
    if (!ok) {
    qFatal(“An error occurred during parsing”);
    exit (1);
    }
    qDebug() << "Name :" <readAll() in messagebox then I can view the webservice result (json String).

    • Flavio says:

      Have you checked parser.errorString() and parser.errorLine() output? Are you sure you are parsing some valid json object? Could you provide me the json object you are converting?

      Please contact me using my email address, it will be easier.

  23. Girija says:

    ok i will send a mail to you.

  24. Girija says:

    Thank u very much. It is very nice.

  25. cwrx says:

    Hi. im encountering error when calling parse() with non JSON object. It was actually the firstline of xml header .
    is there any API to check if a string is not JSON string?

  26. cwrx says:

    and what i mean by error is somekind of exception in VS2008.

  27. deep parsing says:

    How do you parse this without using too many foreach loop in a foreach loop?

    {
    “encoding” : “UTF-8″,
    “location” : [ [ x, y, z ], [ x, y, z ], [x, y, z ] ],
    “indent” : { “length” : 3, “use_space” : true }
    }

  28.