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