总结rapidjson的基本操作
rapidjson 基本操作
rapidjson中每个节点都是一个Value
, 可以表示7种基本数据类型:int32_t, uint32_t, int64_t, uint64_t, float, double, bool
, 以及string, array, object
, array
就相当于数组类型与std::vector
类似, object
相当于字典map类型, 它的key只能是string
, value可以是任意的Value
类。
1. 普通数据类型
1 | Value v; // Null |
- 访问元素修改元素
1
2
3
4
5
6
7
8
9
10
11if (d.HasMember("name")){
rapidjson::Value& v = d["name"]; // []访问需要加判断,赋值只能用引用方式
}
// 迭代器访问
rapidjson::Value::MemberIterator iter = d.FindMember("name");
if (iter != d.MemberEnd()) { iter->name; iter->value; }
for (rapidjson::Value::MemberIterator iter = d.MemberBegin(); iter != d.MemberEnd(); ++iter) { //... }
// c++11 支持
for (auto& m : d.GetObject())
printf("Type of member %s is %s\n", m.name.GetString(), kTypeNames[m.value.GetType()]);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// 添加int,bool,double
// d.AddMember("name", Value(1.0), d.GetAllocator()); // 官方文档说临时变量不能通过编译,但是我测了一下可以通过?
d.AddMember("name", Value(1.0).Move(), d.GetAllocator()); // 加Move返回引用
d.AddMember("name", Value().SetInt(1), d.GetAllocator());
// 添加string
d.AddMember("name", "value", d.GetAllocator());
d.AddMember("name", rapidjson::Value("123").Move(), d.GetAllocator());
std::string str = "123";
d.AddMember("name", rapidjson::Value(str.c_str(), str.size(), d.GetAllocator()).Move(), d.GetAllocator());
rapidjson::Value v("123", d.GetAllocator());
d.AddMember("name", v, d.GetAllocator()); // v变为NULL
d.AddMember(rapidjson::Value("name").Move(), v, d.GetAllocator()); // key 也为一个Value类型
// 删除元素
bool RemoveMember(const Ch* name):使用键名来移除成员(线性时间复杂度)。
bool RemoveMember(const Value& name):除了 name 是一个 Value,和上一行相同。
MemberIterator RemoveMember(MemberIterator):使用迭代器移除成员(_ 常数 _ 时间复杂度)。
MemberIterator EraseMember(MemberIterator):和上行相似但维持成员次序(线性时间复杂度)。
MemberIterator EraseMember(MemberIterator first, MemberIterator last):移除一个范围内的成员,维持次序(线性时间复杂度)。
MemberIterator RemoveMember(MemberIterator) 使用了“转移最后”手法来达成常数时间复杂度。基本上就是析构迭代器位置的成员,然后把最后的成员转移至迭代器位置。因此,成员的次序会被改变。
// 修改某个key value, 可以通过迭代器
rapidjson::Value::MemberIterator iter = d.FindMember("name");
if (iter != d.MemberEnd()){
iter->name.SetString("change_name");
}3. Array
访问1
2
3rapidjson::Document d;
d.SetArray();
rapidjson::Document d(rapidjson::kArrayType); // 同object修改1
2
3
4
5
6
7
8
9
10
11
12assert(d.IsArray());
// 索引访问
for (uint32_t i = 0; i < a.Size(); i++){ // 与std::vector不同,用的是unsigned int
rapidjson::Value& v = d[i];
}
// 迭代器访问
for (rapidjson::Value::ValueIterator iter = d.Begin(); iter != d.End(); ++iter){
iter->GetInt();
}
// c++11
for (auto& v : d.GetArray())
printf("%d ", v.GetInt());1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 基本与object相似, 大量使用move操作
// API与std::vector相似
Clear()
Reserve(SizeType, Allocator&)
Value& PushBack(Value&, Allocator&)
template <typename T> GenericValue& PushBack(T, Allocator&)
Value& PopBack()
ValueIterator Erase(ConstValueIterator pos)
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)
// 添加
d.PushBack(2, d.GetAllocator());
d.PushBack("value", d.GetAllocator());
std::string str = "value";
d.PushBack(rapidjson::Value(str.c_str(), str.size(), d.GetAllocator()).Move(), d.GetAllocator());
// 流畅接口(Fluent interface),因为返回的是本身的引用
d.PushBack("Lua", d.GetAllocator()).PushBack("Mio", d.GetAllocator());
4. Value 和 string转换
1 |
|
5. 关于 allocator, 拷贝操作,移动操作
rapidjson 给每个document分配了allocator, 当一个document析构时对应的allocator也析构了,而rapidjson基本都是移动操作,有时会出现问题,例如一个document(d1)里的部分Value(v1)是通过另一个document(d2)的allocator分配的,那么当d2析构时,分配的v1的内存随时可能被操作系统回收,就会出现空悬指针,可能导致coredump。
1 | rapidjson::Document* d1 = new rapidjson::Document(rapidjson::kTypeObject); |
因此一个document里的Value最好都用同一个allocator分配,实在不行的话,就要确保不同的document的生命周期一致。
比较省事的操作:
1 | rapidjson::Document d1; |
参考
官方文档:http://rapidjson.org/zh-cn/
github:https://github.com/Tencent/rapidjson
- 本文作者: JiXiaw
- 本文链接: http://jixiaw.github.io/2021/02/05/rapidjson/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!