简介
RapidJSON 是一个 C++ 的 JSON 解析器及生成器。它的灵感来自 RapidXml。
- RapidJSON 小而全。它同时支持 SAX 和 DOM 风格的 API。SAX 解析器只有约 500 行代码。
- RapidJSON 快。它的性能可与
strlen()
相比。可支持 SSE2/SSE4.2 加速。 - RapidJSON 独立。它不依赖于 BOOST 等外部库。它甚至不依赖于 STL。
- RapidJSON 对内存友好。在大部分 32/64 位机器上,每个 JSON 值只占 16 字节(除字符串外)。它预设使用一个快速的内存分配器,令分析器可以紧凑地分配内存。
- RapidJSON 对 Unicode 友好。它支持 UTF-8、UTF-16、UTF-32 (大端序/小端序),并内部支持这些编码的检测、校验及转码。例如,RapidJSON 可以在分析一个 UTF-8 文件至 DOM 时,把当中的 JSON 字符串转码至 UTF-16。它也支持代理对(surrogate pair)及
"\u0000"
(空字符)
使用方法:RapidJSON: 首页http://rapidjson.org/zh-cn/index.html
首先加载头文件
#include"rapidjson/reader.h"
#include"rapidjson/schema.h"
#include"rapidjson/stream.h"
#include"rapidjson/stringbuffer.h"
#include"rapidjson/uri.h"
#include"rapidjson/writer.h"
using namespace rapidjson;
这里 rapidjson 为作用域;
#include "rapidjson/document.h"
using namespace rapidjson;
Document document; 创建DOM树
document.Parse(json); 加载解析的json文件
那么现在该 JSON 就会被解析至 document
中,成为一棵 *DOM 树 *:
解析过程(也就是读取过程):
定义 dom 树
Document dom;//定义DOM树根
dom.Parse(str); //将解析的文本加载DOM树上 这里str必须为const char*
assert(dom.IsObject()); //断言数据类型 为树对象
举例:
{
"hello": "world",
"t": true ,
"f": false,
"n": null,
"i": 123,
"pi": 3.1416,
"a": [1, 2, 3, 4]
}
让我们查询一下根 Object 中有没有 "hello"
成员。由于一个 Value
可包含不同类型的值,我们可能需要验证它的类型,并使用合适的 API 去获取其值。在此例中,"hello"
成员关联到一个 JSON String。
assert(document.HasMember("hello"));
assert(document["hello"].IsString());
printf("hello = %s\n", document["hello"].GetString());
结果:world
JSON True/False 值是以 bool
表示的。
assert(document["t"].IsBool());
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
结果:true
JSON Null 值可用 IsNull()
查询。
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
结果:null
JSON Number 类型表示所有数值。然而,C++ 需要使用更专门的类型。
assert(document["i"].IsNumber());
// 在此情况下,IsUint()/IsInt64()/IsUint64() 也会返回 true
assert(document["i"].IsInt());
printf("i = %d\n", document["i"].GetInt());
// 另一种用法: (int)document["i"]
assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble());
结果:i = 123
结果:pi = 3.1416
JSON Array 包含一些元素。
// 使用引用来连续访问,方便之余还更高效。
const Value& a = document["a"];
assert(a.IsArray());
for (SizeType i = 0; i < a.Size(); i++) // 使用 SizeType 而不是 size_t
printf("a[%d] = %d\n", i, a[i].GetInt());
结果:
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
反解析过程(也就是写过程):
char name[] = "LI HUA";
string gender = "boy";
vector<string> hobby = { "足球","篮球","电影" };
map<string, double> score = { {"math",100},{"Chinese",86},{"English",85} };
string Lover_name = "Xiao Hong";
string Love_gender = "girl";
vector<string> Lover_hobby = { "画画","跳舞","唱歌" };
map<string, double> Lover_score = { {"数学", 78.5},{"语文", 89},{"英语", 90} };
开始写:
StringBuffer s;
定义缓冲buff 写入文件
Writer<StringBuffer> writer(s);
writer.StartObject();
writer.Key("name");
writer.String(name);
writer.Key("gender");
writer.String(gender.c_str());
writer.Key("hobby");
writer.StartArray();
for (const auto& item : hobby)
{
writer.String(item.c_str());
}
writer.EndArray();
writer.Key("score");
writer.StartObject();
for (auto &item : Lover_score) {
writer.Key((item.first).c_str());
writer.Double(item.second);
}
writer.EndObject();
writer.Key("lover");
writer.StartObject();
writer.Key("name");
writer.String(Lover_name.c_str());
writer.Key("gender");
writer.String(Love_gender.c_str());
writer.Key("hobby");
writer.StartArray();
for (auto &item : Lover_hobby) {
writer.String((item.c_str()));
}
writer.EndArray();
writer.Key("score");
writer.StartObject();
for (auto &item : Lover_score) {
writer.Key((item.first).c_str());
writer.Double(item.second);
}
writer.EndObject();
writer.EndObject();
writer.EndObject();//全局对象
std::string outFileName = R"(C:\Users\dell\Desktop\document.json)";
std::ofstream outfile(outFileName, std::ios::trunc);
outfile << "\n";
outfile << s.GetString();
outfile.close();
结果展示: