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: , , , ,
32 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. nomexs says:

    it’s great thanks!

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

  14. 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…

  15. 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
    ===

  16. 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.

  17. 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

  18. 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?

  19.  
Leave a Reply