Understanding RapidJson

With new technologies softwares need to evolve and adapt. My new task is to make cppagent generate output in Json (JavaScript Object Notation) format. Last week i spent sometime to try out different libraries and finally settled on using Rapidjson. Rapidjson is a json manipulation library  for c++ which is fast, simple and has compatibility with different c++ compilers in different platforms. In this post we will be looking at example codes to generate, parse and manipulate json data. For people who want to use this library i would highly recommend them to play with and understand the example codes first.

First we will write a simple program to write a sample json as below (the same simplewriter.cpp as in example) :

{
    "hello" : "world" ,
    "t" : true ,
    "f" : false ,
    "i" : 123 ,
    "pi" : 3.1416 ,
    "a": [
        0,
        1,
        2,
        3
    ]
}

To generate a Json output you need:

  • a StringBuffer object, a buffer object to write the Json output.
  • Writer object to write Json to the buffer. Here i have used PrettyWriter object to write human-readable and properly indented json output.
  • functions StartObject/EndObject to start and close a json object parenthesis “{” and  “}” respectively.
  • functions StartArray/EndArray to start and end a json array object i.e “[” and “]“.
  • functions String(), Uint(), Bool(), Null() , Double()  are called on writer object to write string, unsigned integer, boolean, null, floating point numbers respectively.
#include "rapidjson/stringbuffer.h"
#include "rapidjson/prettywriter.h"
#include <iostream>

using namespace rapidjson;
using namespace std;

template <typename Writer>
void display(Writer& writer );

int main() {
 StringBuffer s;
 PrettyWriter<StringBuffer> writer(s);
 display(writer);
 cout << s.GetString() << endl;   // GetString() stringify the Json
 }

template <typename Writer>
void display(Writer& writer){
 writer.StartObject();  // write "{"
 writer.String("hello"); // write string "hello"
 writer.String("world");
 writer.String("t");
 writer.Bool(true);   // write boolean value true
 writer.String("f");
 writer.Bool(false);
 writer.String("n");
 writer.Null();        // write null
 writer.String("i");
 writer.Uint(123);     // write unsigned integer value
 writer.String("pi");
 writer.Double(3.1416); // write floating point numbers
 writer.String("a");
 writer.StartArray();  // write "["
 for (unsigned i = 0; i < 4; i++)
 writer.Uint(i);
 writer.EndArray();   // End Array "]"
 writer.EndObject();  // end Object "}"
}

Next we will manipulate the Json document and change the value for key “Hello” to “C++” ,

To manipulate:

  • first you need to parse your json data into a Document object.
  • Next you may use a Value reference to the value of the desired node/key or you can directly access them as doc_object[‘key’] .
  • Finally you need to call the Accept method passing the Writer object to write the document to the StringBuffer object.

Below function changes the keywords for “hello” , “t”, “f” to “c++” , false , true respectively.


template <typename Document>
void changeDom(Document& d){
// any of methods shown below can be used to change the document
Value& node = d["hello"];  // using a reference
node.SetString("c++"); // call SetString() on the reference
d["f"] = true; // access directly and change
d["t"].SetBool(false); // best way
}

Now to put it all together:

Before Manupulation
{
     "hello": "world",
     "t": true,
     "f": false,
     "n": null,
     "i": 123,
     "pi": 3.1416,
     "a": [
        0,
        1,
        2,
        3
     ]
}
After Manupulation
{
     "hello": "c++",
     "t": false,
     "f": true,
     "n": null,
     "i": 123,
     "pi": 3.1416,
     "a": [
        0,
        1,
        2,
        3
      ]
}

The final code to display the above output:


#include "rapidjson/stringbuffer.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/document.h"
#include <iostream>

using namespace rapidjson;
using namespace std;

template <typename Writer>
void display(Writer& writer);

template <typename Document>
void changeDom(Document& d);

int main() {
 StringBuffer s;
 Document d;
 PrettyWriter<StringBuffer> writer(s);
 display(writer);
 cout << "Before Manupulation\n" << s.GetString() << endl ;
 d.Parse(s.GetString());
 changeDom(d);
 s.Clear();   // clear the buffer to prepare for a new json document
 writer.Reset(s);  // resetting writer for a fresh json doc
 d.Accept(writer); // writing parsed document to buffer
 cout << "After Manupulation\n" << s.GetString() << endl;
 }

template <typename Document>
void changeDom(Document& d){
Value& node = d["hello"];
node.SetString("c++");
d["f"] = true;
d["t"].SetBool(false);
}

template <typename Writer>
void display(Writer& writer){
 writer.StartObject();
 writer.String("hello");
 writer.String("world");
 writer.String("t");
 writer.Bool(true);
 writer.String("f");
 writer.Bool(false);
 writer.String("n");
 writer.Null();
 writer.String("i");
 writer.Uint(123);
 writer.String("pi");
 writer.Double(3.1416);
 writer.String("a");
 writer.StartArray();
 for (unsigned i = 0; i < 4; i++)
 writer.Uint(i);
 writer.EndArray();
 writer.EndObject();
}

[EDIT]

Added more complex examples in Understanding RapidJson – Part 2

Understanding RapidJson