简介
RapidJSON是一个高效的C++ JSON解析器和生成器。它专注于性能和易用性,使得处理JSON数据变得简单和快速。RapidJSON支持现代的JSON特性,如嵌套对象、数组、Unicode编码和注释。它的API简洁易用,可以轻松解析和生成JSON数据。无论你的项目需要处理大量的JSON数据,还是只需要解析或生成少量的JSON数据,RapidJSON都能提供出色的性能和便利的API,成为你的理想选择。
说明文档
https://rapidjson.org/zh-cn/md_doc_pointer_8zh-cn.html
下载地址
https://github.com/Tencent/rapidjson/
安装
RapidJSON 是只有头文件的 C++ 库。只需把 include/rapidjson 目录复制至系统或项目的 include 目录中。或者如果是用vs可以设置包含目录
Value 及 Document
每个 JSON 值都储存为 Value 类,而 Document 类则表示整个 DOM,它存储了一个 DOM 树的根 Value。
RapidJSON 的所有公开类型及函数都在 rapidjson 命名空间中。
查询 Value
- 头文件和命名空间
#include "rapidjson/document.h"
using namespace rapidjson;
- json字符串
{
"hello": "world",
"t": true ,
"f": false,
"n": null,
"i": 123,
"pi": 3.1416,
"a": [1, 2, 3, 4]
}
- 代码
将JSON字符串,解析至document 中,成为一棵 DOM 树
#include <iostream>
#include "rapidjson/document.h"
using namespace std;
using namespace rapidjson;
int main()
{
string json = "{ \"hello\": \"world\", \"t\": true, \"f\": false, \"n\": null, \"i\": 123, \"pi\": 3.1416, \"a\": [1, 2, 3, 4] }";
Document document;
document.Parse(json.c_str());
cin.get();
return 0;
}
- DOM树
- 判断根是不是 Object
assert(document.IsObject());
assert 是一个判断语句。参数为false时,会导致程序终止。在生产环境中,要使用其他方法来处理这种情况,例如通过返回错误代码或抛出异常。
- 获取成员值
- 让我们查询一下根 Object 中有没有 “hello” 成员。
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());
assert(document["pi"].IsNumber());
assert(document["i"].IsInt());
printf("i = %d\n", document["i"].GetInt());
assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble());
整型123、浮点型3.1416使用
IsNumber()
判断都是true
。
输出:
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
注意,RapidJSON 并不自动转换各种 JSON 类型。例如,对一个 String 的 Value 调用 GetInt() 是非法的,其行为是未定义的.
查询 Array
SizeType 是 unsigned int 的别名。在多数系统中,Array 最多能存储 2^32-1 个元素。
Array 与 std::vector 相似,除了使用索引,也可使用迭代器来访问所有元素。
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf("%d ", itr->GetInt());
当使用 C++11 功能时,你可使用范围 for 循环去访问 Array 内的所有元素。
for (auto& v : a.GetArray())
printf("%d ", v.GetInt());
查询 Object
用迭代器去访问所有 Object 成员:
vector<string> kTypeNames = {"Null", "False", "True", "Object", "Array", "String", "Number"};
for (Value::ConstMemberIterator itr = document.MemberBegin();
itr != document.MemberEnd(); ++itr)
{
printf("Type of member %s is %s\n",itr->name.GetString(), kTypeNames[itr->value.GetType()].c_str());
}
输出:
Type of member hello is String
Type of member t is True
Type of member f is False
Type of member n is Null
Type of member i is Number
Type of member pi is Number
Type of member a is Array
当使用 C++11 功能时,你可使用范围 for 循环去访问 Object 内的所有成员。
for (auto& m : document.GetObject())
printf("Type of member %s is %s\n",
m.name.GetString(), kTypeNames[m.value.GetType()]);
判断对象是否存在
HasMember()
方法,会导致两次查找:
if(document.HasMember("hello"))
printf("%s\n", document["hello"].GetString());
FindMember()
方法,更好:
Value::ConstMemberIterator itr = document.FindMember("hello");
if (itr != document.MemberEnd())
printf("%s\n", itr->value.GetString());
查询 Number
|
|
|
---|---|---|
bool IsUint() | unsigned GetUint() | 32 位无符号整数 |
bool IsInt() | int GetInt() | 32 位有符号整数 |
bool IsUint64() | uint64_t GetUint64() | 64 位无符号整数 |
bool IsInt64() | int64_t GetInt64() | 64 位有符号整数 |
bool IsDouble() | double GetDouble() | 64 位双精度浮点数 |
注意,一个整数可能用几种类型来提取,而无需转换。例如,一个名为 x 的 Value 包含 123,那么 x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true
。但如果一个名为 y 的 Value 包含 -3000000000,那么仅会令 x.IsInt64() == true
。
当要提取 Number 类型,GetDouble() 是会把内部整数的表示转换成 double。注意 int 和 unsigned 可以安全地转换至 double,但 int64_t 及 uint64_t 可能会丧失精度( int64_t 最大值有19 位有效数字,uint64_t最大值有 20 位有效数字,都超过了 double 15位有效数字的限制)。
查询 String
c++string字符串把 '\0'
作为结束符号,如果json的值中带有这个字符,则需要用GetStringLength()
获取正确的长度。
if (document.HasMember("hello") && document["hello"].IsString())
{
SizeType len = document["hello"].GetStringLength();
string str(document["hello"].GetString(), len);
printf("%s %d\n", str.c_str(), len);
}
输出:
world 5
比较两个 Value
直接使用 == 及 != 比较两个 Value。当两个 Value 的类型及内容相同,它们才当作相等。也可以比较 Value 和它的原生类型值。例子:
if (document["hello"] == document["n"]) /*...*/; // 比较两个值
if (document["hello"] == "world") /*...*/; // 与字符串字面量作比较
if (document["i"] != 123) /*...*/; // 与整数作比较
if (document["pi"] != 3.14) /*...*/; // 与 double 作比较
Array/Object 顺序以它们的元素/成员作比较。当且仅当它们的整个子树相等,它们才当作相等。
另外需要注意的是若一个 Object 含有重复命名的成员,它与任何 Object 作比较都总会返回 false。