>

1. Parse json

use doc.Parse() to parse a json string, also, rapidjson provides a ParseInsitu() which can be use to parse json in place.
After getting parsed value into rapidjson::Document, we can extract the field out.

use doc.HasMember("key_name") to test member existence, use doc["key_name"].IsString() to get test value type, and use d["key_name"].GetString() to extract the value.

Besides, we can iterate over the object members as <key, value>, the value is actually an index, we can use const array to store the type names, then use the returned index to get it.

1
2
3
4

static const char* typenames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
for (Value::ConstMemberIterator it = doc.MemberBegin(); it != doc.MemberEnd(); ++it)
printf("Type of member %s is %s\n", it->name.GetString(), typenames[it->value.GetType()]);

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void readjson() {
std::stringstream ss;
std::ifstream file(injson);
if (file) {
ss << file.rdbuf();
file.close();

} else {
throw std::runtime_error("!! Unable to open json file");
}

Document doc;
if (doc.Parse<0>(ss.str().c_str()).HasParseError())
throw std::invalid_argument("json parse error");

// Start parsing json string
assert(d.HasMember("id"));
assert(d["date"].IsInt());
int id = doc["id"].GetInt();
std::string version = doc["version"].GetString();
std::string date = doc["data"].GetString();
const Value& array = doc["file"];
std::vector<std::string> files;
for (rapidjson::SizeType i = 0; i < array.Size(); i++) {
files.emplace_back(array[i].GetString());
}

std::cout << "id: " << id << std::endl;
std::cout << "version: " << version << std::endl;
std::cout << "date: " << date << std::endl;
std::cout << "files" << std::endl;
for (auto &f : files) {
std::cout << "\t";
std::cout << f << std::endl;
}
}

2. Serialize to json

RapidJson provides Writer<StringBuffer> and PrettyWriter<StringBuffer> both of which can be used to write key values into json string.

the type of doc["key_name"] is rapidjson::Value, we can use doc["key_name"].SetString() to set value, or we can even specify an allocator and string length, like this:

1
2
Value author;
author.SetString(buffer2, static_cast<SizeType>(len), doc.GetAllocator());

How to add values to an array?

1
2
3
4
5
6
7
Value& a = document["a"];   // This time we uses non-const reference.
Document::AllocatorType& allocator = document.GetAllocator();
for (int i = 5; i <= 10; i++)
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.

// Fluent API
a.PushBack("Lua", allocator).PushBack("Mio", allocator);

Add members to json

1
2
// Variable 'buffer' is unusable now but 'author' has already made a copy.
document.AddMember("author", author, document.GetAllocator());

after the writer is constructed

1
document.Accept(writer);    // Accept() traverses the DOM and generates Handler events.

##### (1) Array
1
2
3
4
5
std::vector<int> vals{0, 1, 2};
for (auto &i: vals) {
writer.Int(i);
}
writer.EndArray();

Result:

[
    0,
    1,
    2
]

##### (2) Key : Array We can use `writer` to write key and value recursively.
1
2
3
4
5
6
7
8
9
10
11
12
std::vector<int> vals{0, 1, 3};
StringBuffer sbuf;
PrettyWriter<StringBuffer> writer(sbuf);
writer.StartObject();
writer.String("key"); // key
writer.StartArray(); // value
for (auto &i: vals) {
writer.Int(i);
}
writer.EndArray();
writer.EndObject();
std::cout << sbuf.GetString() << std::endl;

Result:

{ “key”: [
0,
1,
2
]
}

We can also construct the rapidjson::Value first and then write it to writer.
Firstly, we create a empty object for the whole json document using d.SetObject(), then we create a rapidjson::Value which stores an array using Value key_array(rapidjson::kArrayType), after we setting all elements of the array, we add this array object to the document object using d.AddMembeer("key", key_array, allocator), finally we create a writer to accept the document.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
std::vector<int> vals{0, 1, 3};

rapidjson::Document d;
d.SetObject();

Value key(kArrayType);
Document::AllocatorType& allocator = d.GetAllocator();

// key.PushBack(0, allocator).PushBack(512, allocator);
for (auto &i: keys) {
key.PushBack(i, allocator);
}
d.AddMember("key", key, allocator);
StringBuffer sb;
PrettyWriter<StringBuffer> writer(sb);
d.Accept(writer);
std::cout << sb.GetString() << std::endl;

Result:

{ “key”: [
0,
1,
2
]
}


##### More examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void writejson() {
std::stringstream ss_date;
time_t t = time(nullptr);
struct tm * now = localtime(&t);
ss_date << (now->tm_year + 1900) << '-' << (now->tm_mon + 1) << '-' << now->tm_mday;
StringBuffer s;
PrettyWriter<StringBuffer> writer(s);

writer.StartObject();
writer.Key("version");
writer.String("1.0");
writer.Key("id");
writer.Int(123);
writer.Key("date");
#if RAPIDJSON_HAS_STDSTRING
writer.String(ss_date.str());
#else
writer.String(ss_date.str().c_str(), static_cast<SizeType>(ss_date.str().length())); // Supplying length of string is faster.
#endif
writer.Key("file");
writer.StartArray();
std::vector<std::string> paths{"0.mp3", "1.mp3", "2.mp3", "3.mp3"};
// m_vWriteFilePath is a vector<std::string> which contains 0.mp3 1.mp3 ...
for (const auto& path : paths) {
writer.String(path.c_str());
}
writer.EndArray();
writer.EndObject();

std::ofstream of("out.json");
of << s.GetString();
if (!of.good())
throw std::runtime_error("Can't write the JSON string to the file!");

}

###### Reference https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp