如何将 rapidjson:Value 转化为string转化成json类型

Json 和 RapidJson
定义:是数据格式。相较于XML,小、读写快、易解析。
语法规则:
&名称&:&值& 值可以是:数字、字符串(&&)、逻辑值、数组([])、对象({})、null 数据有逗号隔开。!最后一个数据不加逗号
定义: 是一个 C++ 的 JSON 解析器及生成器。
基本类型:
Value:可以理解为int,或者是bool型变量等其他数据类型。对于定义Value value,只是一个定义,还没有决定其数据类型,如果明确value的值,则其相应的数据类型也就确定了 Write:将Value数据编码成json合适数据格式 Reader:是将json格式数据解析成一个Value值
// rapidjson/example/simpledom/simpledom.cpp`
#include &rapidjson/document.h&
#include &rapidjson/writer.h&
#include &rapidjson/stringbuffer.h&
int main() {
// 1. 把 JSON 解析至 DOM。
const char* json = &{\&project\&:\&rapidjson\&,\&stars\&:10}&;
d.Parse(json);
// 2. 利用 DOM 作出修改。
Value& s = d[&stars&];
s.SetInt(s.GetInt() + 1);
// 3. 把 DOM 转换(stringify)成 JSON。
Writer writer(buffer);
d.Accept(writer);
// Output {&project&:&rapidjson&,&stars&:11}
std::cout && buffer.GetString() && std::
注意一点就是一定要对解析出来的document(JSON解析出来以xml dom形式存在)进行判断本教程简介文件对象模型(Document Object Model, DOM)API。
中所示,可以解析一个 JSON 至 DOM,然后就可以轻松查询及修改 DOM,并最终转换回 JSON。
Value 及 Document
每个 JSON 值都储存为 Value 类,而 Document 类则表示整个 DOM,它存储了一个 DOM 树的根 Value。RapidJSON 的所有公开类型及函数都在 rapidjson 命名空间中。
查询 Value
在本节中,我们会使用到 example/tutorial/tutorial.cpp 中的代码片段。
假设我们用 C 语言的字符串储存一个 JSON(const char* json): {
&hello&: &world&,
&t&: true ,
&f&: false,
&n&: null,
&pi&: 3.1416,
&a&: [1, 2, 3, 4]}把它解析至一个 Document: #include &&using namespace ;document.(json);那么现在该 JSON 就会被解析至 document 中,成为一棵 *DOM 树 *:
教程中的 DOM
自从 RFC 7159 作出更新,合法 JSON 文件的根可以是任何类型的 JSON 值。而在较早的 RFC 4627 中,根值只允许是 Object 或 Array。而在上述例子中,根是一个 Object。 assert(document.IsObject());让我们查询一下根 Object 中有没有 "hello" 成员。由于一个 Value 可包含不同类型的值,我们可能需要验证它的类型,并使用合适的 API 去获取其值。在此例中,"hello" 成员关联到一个 JSON String。 assert(document.(&hello&));assert(document[&hello&].IsString());printf(&hello = %s\n&, document[&hello&].GetString());worldJSON True/False 值是以 bool 表示的。 assert(document[&t&].IsBool());printf(&t = %s\n&, document[&t&].GetBool() ? &true& : &false&);trueJSON Null 值可用 IsNull() 查询。 printf(&n = %s\n&, document[&n&].IsNull() ? &null& : &?&);nullJSON Number 类型表示所有数值。然而,C++ 需要使用更专门的类型。
assert(document[&i&].IsNumber());assert(document[&i&].IsInt());
printf(&i = %d\n&, document[&i&].GetInt());assert(document[&pi&].IsNumber());assert(document[&pi&].IsDouble());printf(&pi = %g\n&, document[&pi&].GetDouble());i = 123pi = 3.1416JSON Array 包含一些元素。 const & a = document[&a&];assert(a.IsArray());for ( i = 0; i & a.Size(); i++)
printf(&a[%d] = %d\n&, i, a[i].GetInt());a[0] = 1a[1] = 2a[2] = 3a[3] = 4注意,RapidJSON 并不自动转换各种 JSON 类型。例如,对一个 String 的 Value 调用 GetInt() 是非法的。在调试模式下,它会被断言失败。在发布模式下,其行为是未定义的。
以下将会讨论有关查询各类型的细节。
查询 Array
缺省情况下,SizeType 是 unsigned 的 typedef。在多数系统中,Array 最多能存储 2^32-1 个元素。
你可以用整数字面量访问元素,如 a[0]、a[1]、a[2]。
Array 与 std::vector 相似,除了使用索引,也可使用迭代器来访问所有元素。 for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf(&%d &, itr-&GetInt());还有一些熟悉的查询函数:
SizeType Capacity() const
bool Empty() const
范围 for 循环 (v1.1.0 中的新功能)
当使用 C++11 功能时,你可使用范围 for 循环去访问 Array 内的所有元素。
for (auto& v : a.GetArray())
printf(&%d &, v.GetInt());
查询 Object
和 Array 相似,我们可以用迭代器去访问所有 Object 成员:
static const char* kTypeNames[] =
{ &Null&, &False&, &True&, &Object&, &Array&, &String&, &Number& };for (Value::ConstMemberIterator itr = document.();
itr != document.(); ++itr){
printf(&Type of member %s is %s\n&,
itr-&name.GetString(), kTypeNames[itr-&value.GetType()]);}Type of member hello is StringType of member t is TrueType of member f is FalseType of member n is NullType of member i is NumberType of member pi is NumberType of member a is Array注意,当 operator[](const char*) 找不到成员,它会断言失败。
若我们不确定一个成员是否存在,便需要在调用 operator[](const char*) 前先调用 HasMember()。然而,这会导致两次查找。更好的做法是调用 FindMember(),它能同时检查成员是否存在并返回它的 Value:
Value::ConstMemberIterator itr = document.(&hello&);if (itr != document.())
printf(&%s\n&, itr-&value.GetString());范围 for 循环 (v1.1.0 中的新功能)
当使用 C++11 功能时,你可使用范围 for 循环去访问 Object 内的所有成员。
for (auto& m : document.GetObject())
printf(&Type of member %s is %s\n&,
m.name.GetString(), kTypeNames[m.value.GetType()]);
查询 Number
JSON 只提供一种数值类型──Number。数字可以是整数或实数。RFC 4627 规定数字的范围由解析器指定。
由于 C++ 提供多种整数及浮点数类型,DOM 尝试尽量提供最广的范围及良好性能。
当解析一个 Number 时, 它会被存储在 DOM 之中,成为下列其中一个类型:
unsigned 32 位无号整数
int 32 位有号整数
uint64_t 64 位无号整数
int64_t 64 位有号整数
double 64 位双精度浮点数
当查询一个 Number 时, 你可以检查该数字是否能以目标类型来提取:
bool IsNumber() 不适用
bool IsUint() unsigned GetUint()
bool IsInt() int GetInt()
bool IsUint64() uint64_t GetUint64()
bool IsInt64() int64_t GetInt64()
bool IsDouble() double GetDouble()
注意,一个整数可能用几种类型来提取,而无需转换。例如,一个名为 x 的 Value 包含 123,那么 x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true。但如果一个名为 y 的 Value 包含 -,那么仅会令 x.IsInt64() == true。
当要提取 Number 类型,GetDouble() 是会把内部整数的表示转换成 double。注意 int 和 unsigned 可以安全地转换至 double,但 int64_t 及 uint64_t 可能会丧失精度(因为 double 的尾数只有 52 位)。
查询 String
除了 GetString(),Value 类也有一个 GetStringLength()。这里会解释个中原因。
根据 RFC 4627,JSON String 可包含 Unicode 字符 U+0000,在 JSON 中会表示为 "\u0000"。问题是,C/C++ 通常使用空字符结尾字符串(null-terminated string),这种字符串把 `\0' 作为结束符号。
为了符合 RFC 4627,RapidJSON 支持包含 U+0000 的 String。若你需要处理这些 String,便可使用 GetStringLength() 去获得正确的字符串长度。
例如,当解析以下的 JSON 至 Document d 之后:
&a\u0000b& } "a\u0000b" 值的正确长度应该是 3。但 strlen() 会返回 1。
GetStringLength() 也可以提高性能,因为用户可能需要调用 strlen() 去分配缓冲。
此外,std::string 也支持这个构造函数:
string(const char* s, size_t count);此构造函数接受字符串长度作为参数。它支持在字符串中存储空字符,也应该会有更好的性能。
比较两个 Value
你可使用 == 及 != 去比较两个 Value。当且仅当两个 Value 的类型及内容相同,它们才当作相等。你也可以比较 Value 和它的原生类型值。以下是一个例子。
if (document[&hello&] == document[&n&]) ;
if (document[&hello&] == &world&) ;
if (document[&i&] != 123) ;
if (document[&pi&] != 3.14) ;
Array/Object 顺序以它们的元素/成员作比较。当且仅当它们的整个子树相等,它们才当作相等。
注意,现时若一个 Object 含有重复命名的成员,它与任何 Object 作比较都总会返回 false。
创建/修改值
有多种方法去创建值。 当一个 DOM 树被创建或修改后,可使用 Writer 再次存储为 JSON。
改变 Value 类型
当使用默认构造函数创建一个 Value 或 Document,它的类型便会是 Null。要改变其类型,需调用 SetXXX() 或赋值操作,例如:
d.SetObject();
v.SetInt(10);v = 10;
构造函数的各个重载
几个类型也有重载构造函数:
要重建空 Object 或 Array,可在默认构造函数后使用 SetObject()/SetArray(),或一次性使用 Value(Type):
转移语义(Move Semantics)
在设计 RapidJSON 时有一个非常特别的决定,就是 Value 赋值并不是把来源 Value 复制至目的 Value,而是把把来源 Value 转移(move)至目的 Value。例如:
a(123); b(456);b =
使用移动语义赋值。
为什么?此语义有何优点?
最简单的答案就是性能。对于固定大小的 JSON 类型(Number、True、False、Null),复制它们是简单快捷。然而,对于可变大小的 JSON 类型(String、Array、Object),复制它们会产生大量开销,而且这些开销常常不被察觉。尤其是当我们需要创建临时 Object,把它复制至另一变量,然后再析构它。
例如,若使用正常 * 复制 * 语义:
contacts();
o.AddMember(&contacts&, contacts, d.GetAllocator());
复制语义产生大量的复制操作。
那个 o Object 需要分配一个和 contacts 相同大小的缓冲区,对 conacts 做深度复制,并最终要析构 contacts。这样会产生大量无必要的内存分配/释放,以及内存复制。
有一些方案可避免实质地复制这些数据,例如引用计数(reference counting)、垃圾回收(garbage collection, GC)。
为了使 RapidJSON 简单及快速,我们选择了对赋值采用 * 转移 * 语义。这方法与 std::auto_ptr 相似,都是在赋值时转移拥有权。转移快得多简单得多,只需要析构原来的 Value,把来源 memcpy() 至目标,最后把来源设置为 Null 类型。
因此,使用转移语义后,上面的例子变成:
contacts();
o.AddMember(&contacts&, contacts, d.GetAllocator());
转移语义不需复制。
在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语义,其它修改型函数如 AddMember(), PushBack() 也采用转移语义。
转移语义及临时值
有时候,我们想直接构造一个 Value 并传递给一个“转移”函数(如 PushBack()、AddMember())。由于临时对象是不能转换为正常的 Value 引用,我们加入了一个方便的 Move() 函数:
a();Document::AllocatorType& allocator = document.();a.PushBack(().SetInt(42), allocator); a.PushBack((42).Move(), allocator);
创建 String
RapidJSON 提供两个 String 的存储策略。
copy-string: 分配缓冲区,然后把来源数据复制至它。
const-string: 简单地储存字符串的指针。
Copy-string 总是安全的,因为它拥有数据的克隆。Const-string 可用于存储字符串字面量,以及用于在 DOM 一节中将会提到的 in-situ 解析中。
为了让用户自定义内存分配方式,当一个操作可能需要内存分配时,RapidJSON 要求用户传递一个 allocator 实例作为 API 参数。此设计避免了在每个 Value 存储 allocator(或 document)的指针。
因此,当我们把一个 copy-string 赋值时, 调用含有 allocator 的 SetString() 重载函数:
char buffer[10];int len = sprintf(buffer, &%s %s&, &Milo&, &Yip&); author.SetString(buffer, len, document.GetAllocator());memset(buffer, 0, sizeof(buffer));在此例子中,我们使用 Document 实例的 allocator。这是使用 RapidJSON 时常用的惯用法。但你也可以用其他 allocator 实例。
另外,上面的 SetString() 需要长度参数。这个 API 能处理含有空字符的字符串。另一个 SetString() 重载函数没有长度参数,它假设输入是空字符结尾的,并会调用类似 strlen() 的函数去获取长度。
最后,对于字符串字面量或有安全生命周期的字符串,可以使用 const-string 版本的 SetString(),它没有 allocator 参数。对于字符串家面量(或字符数组常量),只需简单地传递字面量,又安全又高效:
s.SetString(&rapidjson&);
s = &rapidjson&;
对于字符指针,RapidJSON 需要作一个标记,代表它不复制也是安全的。可以使用 StringRef 函数:
const char * cstr = getenv(&USER&);size_t cstr_len = ...;
s.SetString((cstr));
s = (cstr);
s.SetString((cstr, cstr_len));s = (cstr, cstr_len);
修改 Array
Array 类型的 Value 提供与 std::vector 相似的 API。
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)
注意,Reserve(...) 及 PushBack(...) 可能会为数组元素分配内存,所以需要一个 allocator。
以下是 PushBack() 的例子:
a();Document::AllocatorType& allocator = document.GetAllocator();for (int i = 5; i &= 10; i++)
a.PushBack(i, allocator);
a.PushBack(&Lua&, allocator).PushBack(&Mio&, allocator);与 STL 不一样的是,PushBack()/PopBack() 返回 Array 本身的引用。这称为流畅接口(_fluent interface_)。
如果你想在 Array 中加入一个非常量字符串,或是一个没有足够生命周期的字符串(见 ),你需要使用 copy-string API 去创建一个 String。为了避免加入中间变量,可以就地使用一个 :
contact.PushBack((&copy&, document.GetAllocator()).Move(),
document.GetAllocator()); val(&key&, document.GetAllocator()); contact.PushBack(val, document.GetAllocator());
修改 Object
Object 是键值对的集合。每个键必须为 String。要修改 Object,方法是增加或移除成员。以下的 API 用来增加城员:
Value& AddMember(Value&, Value&, Allocator& allocator)
Value& AddMember(StringRefType, Value&, Allocator&)
template &typename T& Value& AddMember(StringRefType, T value, Allocator&)
以下是一个例子。
contact(kObject);contact.AddMember(&name&, &Milo&, document.GetAllocator());contact.AddMember(&married&, true, document.GetAllocator());使用 StringRefType 作为 name 参数的重载版本与字符串的 SetString 的接口相似。 这些重载是为了避免复制 name 字符串,因为 JSON object 中经常会使用常数键名。
如果你需要从非常数字符串或生命周期不足的字符串创建键名(见 ),你需要使用 copy-string API。为了避免中间变量,可以就地使用 :
contact.AddMember((&copy&, document.GetAllocator()).Move(),
().Move(),
document.GetAllocator()); key(&key&, document.GetAllocator());
contact.AddMember(key, val, document.GetAllocator());移除成员有几个选择:
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) 使用了“转移最后”手法来达成常数时间复杂度。基本上就是析构迭代器位置的成员,然后把最后的成员转移至迭代器位置。因此,成员的次序会被改变。
深复制 Value
若我们真的要复制一个 DOM 树,我们可使用两个 APIs 作深复制:含 allocator 的构造函数及 CopyFrom()。
Document::AllocatorType& a = d.GetAllocator(); v1(&foo&); v2(v1, a);
assert(v1.IsString());
d.SetArray().PushBack(v1, a).PushBack(v2, a);assert(v1.IsNull() && v2.IsNull());
v2.CopyFrom(d, a);
assert(d.IsArray() && d.Size() == 2); v1.SetObject().AddMember(&array&, v2, a);d.PushBack(v1, a);
交换 Value
RapidJSON 也提供 Swap()。
a(123); b(&Hello&);a.Swap(b);assert(a.IsString());assert(b.IsInt());无论两棵 DOM 树有多复杂,交换是很快的(常数时间)。
本教程展示了如何询查及修改 DOM 树。RapidJSON 还有一个重要概念:
是读写 JSON 的通道。流可以是内存字符串、文件流等。用户也可以自定义流。
定义在流或内存中使用的字符编码。RapidJSON 也在内部提供 Unicode 转换及校验功能。
的基本功能已在本教程里介绍。还有更高级的功能,如原位(*in situ*)解析、其他解析选项及高级用法。
是 RapidJSON 解析/生成功能的基础。学习使用 Reader/Writer 去实现更高性能的应用程序。也可以使用 PrettyWriter 去格式化 JSON。
展示一些我们做的及第三方的性能测试。
技术内幕 讲述一些 RapidJSON 内部的设计及技术。
你也可以参考 、API 文档、例子及单元测试。博客访问: 3856870
博文数量: 543
博客积分: 13065
博客等级: 上将
技术积分: 9056
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: C/C++
&names_json.size(); ++i)&names_json.size();="" ++i)&rapidjson::stringbuffer,="" rapidjson::document::encodingtype,="" rapidjson::ascii&rapidjson::stringbuffer,="" rapidjson::ascii&rapidjson::utf8&rapidjson::utf8&rapidjson::writer&rapidjson::genericstringbuffer&rapidjson::utf8&rapidjson::genericstringbuffer&rapidjson::utf8&rapidjson::utf8&rapidjson::utf8&subs.size();="" ++i)rapidjson相比jsoncpp性能高出太多,使用接口一样的简单的。官方中文帮助文档:http:="" rapidjson.org="" zh-cn="" 。&names_json.size();="" rapidjson::ascii&rapidjson::utf8,="" rapidjson::memorypoolallocator&rapidjson::utf8,="" rapidjson::memorypoolallocator&rapidjson::writer&rapidjson::genericstringbuffer&rapidjson::genericstringbuffer&rapidjson::utf8,="" rapidjson::memorypoolallocator&subs.size();="" 。="" &names_json.size();="" ++i)="" &="" {="" std::string="" name="names_json[i].GetString();&names_json.size(); ++i)=" "="" if="" (names_json[i].hasmember("name"))&rapidjson::stringbuffer,="" rapidjson::ascii="" 如果上面一句改成普通的:&rapidjson::writer&subs.size();="" rapidjson::document="" *sub_ptr="subs[i];rapidjson相比jsoncpp性能高出太多,使用接口一样的简单的。官方中文帮助文档:http://rapidjson.org/zh-cn/。
rapidjson的Move语意,请浏览http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#MoveSemantics,
rapidjson::Value a(123);
rapidjson::Value b(456);
b = // a变成Null,b变成数字123,这样的做法是基于性能考虑
除了上述示例的复制语句外,AddMember()和PushBack()也采用了Move语意。
深复制Value:
Value v1(" foo");="" value="" v2(v1);="" 不容许 Value v2(v1, a); // 制造一个克隆,v1不变
v2.CopyFrom(d, a); // 把整个document复制至v2,d不变
rapidjson为了最大化性能,大量使用了浅拷贝,使用之前一定要了解清楚。
如果采用了浅拷贝,特别要注意局部对象的使用,以防止对象已被析构了,却还在被使用。
// 需要#include的头文件:
// en为english的简写,定义了取出错信息的函数GetParseError_En(errcode)
// 示例1:解析一个字符串
// 运行输出结果:
// count=2
// name=zhangsan
// name=wangwu
& & rapidjson::D // 定义一个Document对象
& & std::string str = "{\"count\":2,\"names\":[\"zhangsan\",\"wangwu\"]}";
& & document.Parse(str.c_str()); // 解析,Parse()无返回值,也不会抛异常
& & if (document.HasParseError()) // 通过HasParseError()来判断解析是否成功
& & & & // 可通过GetParseError()取得出错代码,
& & & & // 注意GetParseError()返回的是一个rapidjson::ParseErrorCode类型的枚举值
& & & & // 使用函数rapidjson::GetParseError_En()得到错误码的字符串说明,这里的En为English简写
& & & & // 函数GetErrorOffset()返回出错发生的位置
& & & & printf("parse error: (%d:%d)%s\n", document.GetParseError(), document.GetErrorOffset(), rapidjson::GetParseError_En(document.GetParseError()));
& & & & // 判断某成员是否存在
& & & & if (!document.HasMember("count") || !document.HasMember("names"))
& & & & & & printf("invalid format: %s\n", str.c_str());
& & & & else
& & & & & & // 如果count不存在,则运行程序会挂,DEBUG模式下直接abort
& & & & & & rapidjson::Value& count_json = document["count"];
& & & & & &&
& & & & & & // 如果count不是整数类型,调用也会挂,DEBUG模式下直接abort
& & & & & & // GetInt()返回类型为int
& & & & & & // GetUint()返回类型为unsigned int
& & & & & & // GetInt64()返回类型为int64_t
& & & & & & // GetUint64()返回类型为uint64_t
& & & & & & // GetDouble()返回类型为double
& & & & & & // GetString()返回类型为char*
& & & & & & // GetBool()返回类型为bool
& & & & & & int count = count_json.GetInt();
& & & & & & printf("count=%d\n", count);
& & & & & &&
& & & & & & // 方法GetType()返回枚举值: kNullType,kFalseType,kTrueType,kObjectType,kArrayType,kStringType,kNumberType
& & & & & & // 可用IsArray()判断是否为数组,示例: { "a": [1, 2, 3, 4] }
& & & & & & // 用IsString()判断是否为字符串值
& & & & & & // 用IsDouble()判断是否为double类型的值,示例: { "pi": 3.1416 }
& & & & & & // 用IsInt()判断是否为int类型的值
& & & & & & // 用IsUint()判断是否为unsigned int类型的值
& & & & & & // 用IsInt64()判断是否为int64_t类型的值
& & & & & & // 用IsUint64()判断是否为uint64_t类型的值
& & & & & & // 用IsBool()判断是否为bool类型的值
& & & & & & // 用IsFalse()判断值是否为false,示例: { "t": true, "f": false }
& & & & & & // 用IsTrue()判断值是否为true
& & & & & & // 用IsNull()判断值是否为NULL,示例: { "n": null }
& & & & & & // 更多说明可浏览:
& & & & & & // https://miloyip.gitbooks.io/rapidjson/content/zh-cn/doc/tutorial.zh-cn.html
& & & & & & const rapidjson::Value& names_json = document["names"];
& & & & & & for (rapidjson::SizeType i=0; i&names_json.size(); ++i)="" &="" { & & & & & & & & std::string name = names_json[i].GetString();
& & & & & & & & printf("name=%s\n", name.c_str());
& & & & & & }
// 示例2:构造一个json并转成字符串
// 输出结果:
// {"count":2,"names":[{"name":"zhangsan"},{"name":"wangwu"}]}
& & rapidjson::StringB
& & rapidjson::Writer writer(buffer);
& & writer.StartObject();
& & // count
& & writer.Key("count");
& & writer.Int(2);
& & // 写4字节有符号整数: Int(int32_t x)
& & // 写4字节无符号整数: Uint(uint32_t x)
& & // 写8字节有符号整数: Int64(int64_t x)
& & // 写8字节无符号整数: Uint64(uint64_t x)
& & // 写double值: Double(double x)
& & // 写bool值: Bool(bool x)
& & // names
& & writer.Key("names");
& & writer.StartArray();
& & writer.StartObject();
& & writer.Key("name");
& & writer.String("zhangsan");
& & writer.EndObject();
& & writer.StartObject();
& & writer.Key("name");
& & writer.String("wangwu");
& & writer.EndObject();
& & writer.EndArray();
& & writer.EndObject();
& & // 以字符串形式打印输出
& & printf("%s\n", buffer.GetString());
// 示例3:修改一个已有的json字符串
// 运行输出结果:
// {"name":"wangwu","age":22}
& & rapidjson::D
& & std::string str = "{\"name\":\"zhangsan\",\"age\":20}";
& & document.Parse(str.c_str());
& & rapidjson::Value& name_json = document["name"];
& & rapidjson::Value& age_json = document["age"];
& & std::string new_name = "wangwu";
& & int new_age = 22;
& & // 注意第三个参数是document.GetAllocator(),相当于深拷贝,rapidjson会分配一块内存,然后复制new_name.c_str(),
& & // 如果不指定第三个参数,则是浅拷贝,也就是rapidjson不会分配一块内存,而是直接指向new_name.c_str(),省去复制提升了性能
& & // 官方说明:
& & // http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#CreateString
& & name_json.SetString(new_name.c_str(), new_name.size(), document.GetAllocator());
& & age_json.SetInt(new_age);
& & // 转成字符串输出
& & rapidjson::StringB
& & rapidjson::Writer writer(buffer);
& & document.Accept(writer);
& & printf("%s\n", buffer.GetString());
// 示例4:读数组
// 运行输出结果:
// zhangsan wangwu&
& & rapidjson::D
& & std::string str = "{\"count\":2,\"names\":[{\"name\":\"zhangsan\"},{\"name\":\"wangwu\"}]}";
& & document.Parse(str.c_str());
& & if (document.HasParseError())
& & & & printf("parse error: %d\n", document.GetParseError());
& & & & rapidjson::Value& names_json = document["names"];
& & & & for (rapidjson::SizeType i=0; i&names_json.size(); ++i)="" &="" { & & & & & & if (names_json[i].HasMember("name"))
& & & & & & {
& & & & & & & & rapidjson::Value& name_json = names_json[i]["name"];
& & & & & & & & printf("%s ", name_json.GetString());
& & & & & & }
& & & & printf("\n");
// 示例5: 以Writer构造一个json,然后修改它,最后转成字符串
// 运行输出结果:
// {"count":2}
// {"count":8}
& & rapidjson::StringBuffer buffer1;
& & rapidjson::Writer writer1(buffer1);
& & writer1.StartObject();
& & writer1.Key("count");
& & writer1.Int(2); & &
& & writer1.EndObject();
& & printf("%s\n", buffer1.GetString());
& & // 转成Document对象
& & rapidjson::D
& & document.Parse(buffer1.GetString());
& & // 修改
& & rapidjson::Value& count_json = document["count"];
& & count_json.SetInt(8);
& & // 转成字符串
& & rapidjson::StringBuffer buffer2;
& & rapidjson::Writer writer2(buffer2);
& & document.Accept(writer2);
& & printf("%s\n", buffer2.GetString());
// 示例6: 以Document构造一个json,然后修改它,最后转成字符串
// 运行输出结果:
// {"count":3,"names":[{"id":1,"name":"zhangsan"}]}
// {"count":9,"names":[{"id":1,"name":"zhangsan"}]}
& & rapidjson::D
& & std::string str = "{}"; // 这个是必须的,且不能为"",否则Parse出错
& & document.Parse(str.c_str());
& & // 新增成员count
& & // AddMember第一个参数可以为字符串常,如“str”,不能为“const char*”和“std::string”,
& & // 如果使用“const char*”,则需要使用StringRefType转换:StringRefType(str.c_str())
& & document.AddMember("count", 3, document.GetAllocator());
& & // 新增数组成员
& & rapidjson::Value array(rapidjson::kArrayType);
& & rapidjson::Value object(rapidjson::kObjectType); // 数组成员
& & object.AddMember("id", 1, document.GetAllocator());&
& & object.AddMember("name", "zhangsan", document.GetAllocator());&
& & // 如果数组添加无名字的成员,定义Value时应当改成相应的类型,如:
& & //rapidjson::Value value(rapidjson::kStringType);
& & //rapidjson::Value value(rapidjson::kNumberType);
& & //rapidjson::Value value(rapidjson::kFalseType);
& & //rapidjson::Value value(rapidjson::kTrueType);
& & //array.PushBack(value, document.GetAllocator());
& & //效果将是这样:'array':[1,2,3,4,5]
& & // 注意下面用法编译不过:
& & //std::string str1 = "hello";
& & //object.AddMember("name", str1.c_str(), document.GetAllocator());
& & //const char* str2 = "hello";
& & //object.AddMember("name", str2, document.GetAllocator());
& & // 下面这样可以:
& & //object.AddMember("name", "hello", document.GetAllocator());
& & //const char str3[] = "hello";
& & //object.AddMember("name", str3, document.GetAllocator());
& & // & &
& & //std::string str4 = "#####";
& & //rapidjson::Value v(str4.c_str(), document.GetAllocator());
& & //obj.AddMember("x", v, document.GetAllocator());
& & // 上面两行也可以写在一行:
& & //obj.AddMember("x", rapidjson::Value(str4.c_str(), document.GetAllocator()).Move(), document.GetAllocator());
& & // 添加到数组中
& & array.PushBack(object, document.GetAllocator());
& & // 添加到document中
& & document.AddMember("names", array, document.GetAllocator());
& & // 转成字符串输出
& & rapidjson::StringBuffer buffer1;
& & rapidjson::Writer writer1(buffer1);
& & document.Accept(writer1);
& & printf("%s\n", buffer1.GetString());
& & // 修改值
& & rapidjson::Value& count_json = document["count"];
& & count_json.SetInt(9);
& & // 再次输出
& & rapidjson::StringBuffer buffer2;
& & rapidjson::Writer writer2(buffer2);
& & document.Accept(writer2);
& & printf("%s\n", buffer2.GetString());
// 不转义就输出
// 示例7: 以Document构造一个json,然后修改它,最后转成字符串
// 运行输出结果:
// {"title":"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"}
& & std::string root = "{}";
& & rapidjson::D
& & document.Parse(root.c_str());
& & std::string title = "\u8D2B\u56F0\u5B64\u513F\u52A9\u517B";
& & document.AddMember("title", rapidjson::Value(title.c_str(), document.GetAllocator()).Move(), document.GetAllocator());
& & rapidjson::StringB
& & rapidjson::Writer writer(buffer);
& & // 如果上面一句改成普通的:
& & // rapidjson::Writer writer(buffer);
& & // 则输出将变成:
& & // x7=&
& & // 贫困孤儿助养
& & document.Accept(writer);
& & printf("x7=&\n%s\n", buffer.GetString());
// 示例8:构造空对象和数组&
// 运行输出结果:
// {"age":{},"times":{},"names":[],"urls":[],"books":[]}
// {"age":6,"times":{},"names":[],"urls":[],"books":[]}
& & rapidjson::D
& & document.Parse("{}"); // 这里换成document.SetObject()也可以
& & // 下面为2种构造空对象的方法
& & document.AddMember("age", rapidjson::Value(rapidjson::kObjectType).Move(), document.GetAllocator());
& & document.AddMember("times", rapidjson::Value().SetObject(), document.GetAllocator());
& & // 下面为2种构造空数组的方法
& & document.AddMember("names", rapidjson::Value(rapidjson::kArrayType).Move(), document.GetAllocator());
& & document.AddMember("urls", rapidjson::Value(rapidjson::kArrayType).Move(), document.GetAllocator());
& & document.AddMember("books", rapidjson::Value().SetArray(), document.GetAllocator());
& & rapidjson::StringBuffer buffer1;
& & rapidjson::Writer writer1(buffer1);
& & document.Accept(writer1);
& & printf("%s\n", buffer1.GetString());
& & rapidjson::Value& age = document["age"];
& & age.SetInt(6);
& & rapidjson::StringBuffer buffer2;
& & rapidjson::Writer writer2(buffer2);
& & document.Accept(writer2);
& & printf("%s\n", buffer2.GetString());
// 删除数组元素
// 示例运行输出:
// { "names": [ {"name":"zhangsan","age":100}, {"name":"wangwu","age":90}, {"name":"xiaozhang","age":20} ]}
// {"names":[{"name":"zhangsan","age":100},{"name":"wangwu","age":90}]}
& & std::string str = "{ \"names\": [ {\"name\":\"zhangsan\",\"age\":100}, {\"name\":\"wangwu\",\"age\":90}, {\"name\":\"xiaozhang\",\"age\":20} ]}";
& & rapidjson::D
& & document.Parse(str.c_str());
& & rapidjson::Value& names_json = document["names"];
& & for (rapidjson::Value::ValueIterator iter=names_json.Begin(); iter!=names_json.End();)
& & & & std::string name = (*iter)["name"].GetString();
& & & & // 不要小张了
& & & & if (name == "xiaozhang")
& & & & & & iter = names_json.Erase(iter);
& & & & else
& & & & & & ++
& & rapidjson::StringB
& & rapidjson::Writer writer(buffer);
& & document.Accept(writer);
& & printf("%s\n", str.c_str());
& & printf("%s\n", buffer.GetString());
int main()
& & return 0;
// 示例:不转义中文
// 运行输出结果:
//{"title":"贫困孤儿助养"}
//{"title":"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"}
//g++ -g -o b b.cpp -I/usr/local/thirdparty/rapidjson/include
int main()
& & std::string str = "{\"title\":\"\u8d2b\u56f0\u5b64\u513f\u52a9\u517b\"}";
& & rapidjson::D
& & document.Parse(str.c_str());
& & if (document.HasParseError())
& & & & printf("parse %s failed\n", str.c_str());
& & & & exit(1);
& & rapidjson::StringBuffer buffer1;
& & rapidjson::Writer writer1(buffer1);
& & document.Accept(writer1);
& & printf("%s\n", buffer1.GetString());
& & rapidjson::StringBuffer buffer2;
& & rapidjson::Writer writer2(buffer2);
& & document.Accept(writer2);
& & printf("%s\n", buffer2.GetString());
& & return 0;
// 辅助函数:任意类型都以字符串返回,
// 如果不存在,或者为数组则返回空字符串。
std::string rapidjson_string_value(rapidjson::Value& value, const std::string& name)
& & if (!value.HasMember(name.c_str()))
& & & & return std::string("");
& & const rapidjson::Value& child = value[name.c_str()];
& & if (child.IsString())
& & & & return child.GetString();
& & char str[100];
& & if (child.IsInt())
& & & & snprintf(str, sizeof(str), "%d", child.GetInt());
& & else if (child.IsInt64())
& & & & // 为使用PRId64,需要#include ,
& & & & // 同时编译时需要定义宏__STDC_FORMAT_MACROS
& & & & snprintf(str, sizeof(str), "%"PRId64, child.GetInt64());
& & else if (child.IsUint())
& & & & snprintf(str, sizeof(str), "%u", child.GetUint());
& & else if (child.IsUint64())
& & & & snprintf(str, sizeof(str), "%"PRIu64, child.GetUint64());
& & else if (child.IsDouble())
& & & & snprintf(str, sizeof(str), "%.2lf", child.GetDouble());
& & else if (child.IsBool())
& & & & if (child.IsTrue())
& & & & & & strcpy(str, "true");
& & & & else
& & & & & & strcpy(str, "false");
& & & & str[0] = '\0';
// 辅助函数:
// 当为int32_t值,或字符串实际为int32_t值时,返回对应的int32_t值,其它情况返回0
int32_t rapidjson_int32_value(rapidjson::Value& value, const std::string& name)
& & if (!value.HasMember(name.c_str()))
& & & & return 0;
& & const rapidjson::Value& child = value[name.c_str()];
& & if (child.IsInt())
& & & & return child.GetInt();
& & else if (child.IsString())
& & & & return atoi(child.GetString());
& & return 0;
// 辅助函数:
// 当为int64_t值,或字符串实际为int64_t值时,返回对应的int64_t值,其它情况返回0
int64_t rapidjson_int64_value(rapidjson::Value& value, const std::string& name)
& & if (!value.HasMember(name.c_str()))
& & & & return 0;
& & const rapidjson::Value& child = value[name.c_str()];
& & if (child.IsInt64())
& & & & return child.GetInt64();
& & else if (child.IsString())
& & & & return (int64_t)atoll(child.GetString());
& & return 0;
// 辅助函数:
// 当为uin32_t值,或字符串实际为uin32_t值时,返回对应的uin32_t值,其它情况返回0
uint32_t rapidjson_uint32_value(rapidjson::Value& value, const std::string& name)
& & if (!value.HasMember(name.c_str()))
& & & & return 0;
& & const rapidjson::Value& child = value[name.c_str()];
& & if (child.IsUint())
& & & & return child.GetUint();
& & else if (child.IsString())
& & & & return (uint32_t)atoll(child.GetString());
& & return 0;
// 辅助函数:
// 当为uin64_t值,或字符串实际为uin64_t值时,返回对应的uin64_t值,其它情况返回0
uint64_t rapidjson_uint64_value(rapidjson::Value& value, const std::string& name)
& & if (!value.HasMember(name.c_str()))
& & & & return 0;
& & const rapidjson::Value& child = value[name.c_str()];
& & if (child.IsUint64())
& & & & return child.GetUint64();
& & else if (child.IsString())
& & & & return (uint64_t)atoll(child.GetString());
& & return 0;
// schema使用示例:
json的schema用来检验json数据,它也采用了json格式。
rapidjson::Document schema_
schema_document.Parse(schema.c_str());
if (!schema_document.HasParseError())
& & rapidjson::D
& & document.Parse(str.c_str());
& & if (!document.HasParseError())
& & & & SchemaDocument schema(schema_document);
& & & & SchemaValidator validator(schema);
& & & & if (!document.Accept(validator))
& & & & & & &// 检验出错,输出错误信息
& & & & & & &StringB
& & & & & & &validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
& & & & & & &
& & & & & & &printf("Invalid schema: %s\n", sb.GetString());
& & & & & & &printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
& & & & & & &
& & & & & & &sb.Clear();
& & & & & & &validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
& & & & & & &printf("Invalid document: %s\n", sb.GetString());
示例json:
& & "id": 1,
& & "name": "A green door",
& & "price": 12.50,
& & "tags": ["home", "green"]
上段json对应的schema:
& & "$schema": "http://json-schema.org/draft-04/schema#",
& & "title": "Product",
& & "description": "A product from Acme's catalog",
& & "type": "object",
& & "properties": {
& & & & "id": {
& & & & & & "description": "The unique identifier for a product",
& & & & & & "type": "integer"
& & & & },
& & & & "name": {
& & & & & & "description": "Name of the product",
& & & & & & "type": "string"
& & & & },
& & & & "price": {
& & & & & & "type": "number",
& & & & & & "minimum": 0,
& & & & & & "exclusiveMinimum": true
& & & & },
& & & & "tags": {
& & & & & & "type": "array",
& & & & & & "items": {
& & & & & & & & "type": "string"
& & & & & & },
& & & & & & "minItems": 1,
& & & & & & "uniqueItems": true
& & "required": ["id", "name", "price"]
"title"和"description"是描述性的,可以不写。$schema也是可选的,依据的是《JSON Schema Draft v4》。
X1)rapidjson的“坑”
使用不当,则会掉进“坑”里。下列代码在valgrind中运行时,会报大量错误,而且如果sub是在一个循环中被AddMember,则无法得到预期的结果。
从现象看像是sub析构后仍在被使用,为验证这个推测,改成:rapidjson::Document* sub = new rapidjson::D,然后再使用不但valgrind不报错,而且循环使用也没问题,那么可以肯定AddMember是浅拷贝,这样一来使用就不方便了,除非还有深拷贝的调用方式。
int main()
& & rapidjson::D
& & doc.Parse("{}");
& & { // 目的是让sub在printf时已无效
& & & & rapidjson::D
& & & & sub.Parse("{\"name\":\"tom\"}");
& & & & doc.AddMember("sub", sub, doc.GetAllocator());
& & rapidjson::StringB
& & rapidjson::Writer writer(buffer);
& & doc.Accept(writer);
& & printf("%s\n", buffer.GetString());
& & return 0;
上述代码在valgrind中跑,会报错大量如下这样的错误:
==30425== Invalid read of size 2
==30425== & &at 0x804B008: rapidjson::GenericValue::IsString() const (document.h:947)
==30425== & &by 0x8051632: bool rapidjson::GenericValue::Accept&rapidjson::writer&rapidjson::genericstringbuffer, rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator, 0u& &(rapidjson::Writer&rapidjson::genericstringbuffer, rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator, 0u&&) const (document.h:1769)
==30425== & &by 0x80488CE: main (f.cpp:30)
==30425== &Address 0x428eb62 is 58 bytes inside a block of size 65,548 free'd
==30425== & &at 0x4023329: free (vg_replace_malloc.c:473)
==30425== & &by 0x804BC72: rapidjson::CrtAllocator::Free(void*) (allocators.h:79)
==30425== & &by 0x804BDD7: rapidjson::MemoryPoolAllocator::Clear() (allocators.h:148)
==30425== & &by 0x804BE2E: rapidjson::MemoryPoolAllocator::~MemoryPoolAllocator() (allocators.h:140)
==30425== & &by 0x804BE5F: rapidjson::GenericDocument::Destroy() (document.h:2382)
==30425== & &by 0x804BE7E: rapidjson::GenericDocument::~GenericDocument() (document.h:2064)
正确可以使用的写法:
int main()
& & rapidjson::D
& & doc.Parse("{}");
& & & & // 注意,下面没有使用Document的默认构造,
& & & & // 而是指定Allocator为其父的Allocator。
& & & & // 如果存在多级Document,一定要统一使用根Document的Allocator,
& & & & // 原因是Allocator分配的内存会随Document析构被释放掉!
& & & & //
& & & & // 如果不这样做,必须保证sub的生命在doc之后才结束。
& & & & rapidjson::Document sub(&doc.GetAllocator());
& & & & sub.Parse("{\"name\":\"tom\"}");
& & & & doc.AddMember("sub", sub, doc.GetAllocator());
& & rapidjson::StringB
& & rapidjson::Writer writer(buffer);
& & doc.Accept(writer);
& & printf("%s\n", buffer.GetString());
& & for (std::vector::size_type i=0; i&subs.size(); ++i)="" &="" { & & & & rapidjson::Document *sub_ptr = subs[i];
& & & & delete sub_
& & subs.clear();
& & return 0;
x2)rapidjson的schema特性使用示例
int main()
& & std::string str = "\{\"aaa\":111,\"aaa\":222}"; // "\{\"aaa\":111,\"a\":222}"
& & std::string schema_str = "{\"type\":\"object\",\"properties\":{\"aaa\":{\"type\":\"integer\"},\"bbb\":{\"type\":\"string\"}},\"required\":[\"aaa\",\"bbb\"]}";
& & std::string schema_str = "{\"type\":\"object\",\"properties\":{\"aaa\":{\"type\":\"integer\"},\"bbb\":{\"type\":\"integer\"}},\"required\":[\"aaa\",\"bbb\"]}";
& & printf("%s\n", str.c_str());
& & printf("%s\n", schema_str.c_str());
& & rapidjson::D
& & rapidjson::Document schema_
& & schema_doc.Parse(schema_str.c_str());
& & doc.Parse(str.c_str());
& & rapidjson::SchemaDocument schema(schema_doc);
& & rapidjson::SchemaValidator validator(schema);
& & if (doc.Accept(validator))
& & & & printf("data ok\n");
& & & & rapidjson::StringB
& & & & validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
& & & & printf("Invalid schema: %s\n", sb.GetString());
& & & & printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
& & & & sb.Clear();
& & & & validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
& & & & printf("Invalid document: %s\n", sb.GetString());
& & return 0;
*) 特别注意rapidjson::Document可以为object, array, number, string, boolean, null中任意一种类型
& &只有为object时才可以调用HasMember等与object有关的方法
int main(int argc, char* argv[])
& & rapidjson::D
& & doc.Parse(argv[1]);
& & if (doc.HasParseError())
& & & & printf("parse error\n");
& & // 注意doc可为object, array, number, string, boolean, null中任意一种类型
& & if (!doc.IsObject())
& & & & printf("not object\n");
& & & & printf("parse ok\n");
& & & & if (doc.IsNumber())
& & & & printf("%d\n", doc.GetInt());
& & & & // doc为object类型时,才能调用HasMember
& & & & if (doc.HasMember("x"))
& & & & & & printf("has x\n");
& & & & else
& & & & & & printf("without x\n");
& & return 0;
遍历成员:
rapidjson::V
for (rapidjson::Value::ConstMemberIterator iter = value.MemberBegin(); iter!=value.MemberEnd(); ++iter)
& & const rapidjson::Value& name_json = iter-& // 这个必须是字符串
& & const rapidjson::Value& value_json = iter-& // 这个可以为对象、数组等
& & printf("%s\n", name_json.GetString());
遍历数组1(字符串数组):
// {"k":["k1","k2","k3"]}
rapidjson::D
doc.Parse(str.c_str());
const rapidjson::Value& k = doc["k"];
for (rapidjson::Value::ConstValueIterator v_iter=k.Begin(); v_iter!=k.End(); ++v_iter) // 遍历数组
& & printf("%s\n", (*v_iter).GetString());
遍历数组2(对象数组):
// {"h":[{"k1":"f1"},{"k2":"f2"}]}
rapidjson::D
doc.Parse(str.c_str());
const rapidjson::Value& h = doc["h"];
for (rapidjson::Value::ConstValueIterator v_iter=h.Begin(); v_iter!=h.End(); ++v_iter) // 遍历数组
& & const rapidjson::Value& field = *v_
& & for (rapidjson::Value::ConstMemberIterator m_iter=field.MemberBegin(); m_iter!=field.MemberEnd(); ++m_iter) // kf对
& & & & // k1 =& f1
& & & & // k2 =& f2
& & & & const char* key = m_iter-&name.GetString();
& & & & const char* value = m_iter-&value.GetString();
& & & & printf("%s =& %s\n", key, value);
遍历数组3(对象数组):
// {"h":[{"k1":["f1","f2"]},{"k2":["f1","f2"]}]}
rapidjson::D
doc.Parse(str.c_str());
const rapidjson::Value& h = doc["h"];
for (rapidjson::Value::ConstValueIterator v1_iter=h.Begin(); v1_iter!=h.End(); ++v1_iter) // 遍历第一级数组
& & const rapidjson::Value& k = *v1_ // k1,k2,k3
& & for (rapidjson::Value::ConstMemberIterator m_iter=k.MemberBegin(); m_iter!=k.MemberEnd(); ++m_iter) // 成员遍历
& & & & const char* node_name = m_iter-&name.GetString();
& & & & printf("hk: %s\n", node_name);
& & & & & & & & & & & & & &&
& & & & const rapidjson::Value& node = m_iter-&
& & & & for (rapidjson::Value::ConstValueIterator v2_iter=node.Begin(); v2_iter!=node.End(); ++v2_iter) &// 遍历第二级数组
& & & & & & const char* field = (*v2_iter).GetString();
& & & & & & printf("field: %s\n", field); // f1,f2,f3
&/rapidjson::genericstringbuffer&/rapidjson::writer&rapidjson::genericstringbuffer
阅读(7538) | 评论(3) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
:AddMember的第一个参数为字符串时:http://blog.chinaunix.net/uid--id-5214135.html
AddMember第一个参数可以为字符串常,如“str”,不能为“const&char*”和“std::string”,如果使用“const&char*”,则需要使用StringRefType转换:StringRefType(str.c_str()) |
AddMember的第一个参数为字符串时:http://blog.chinaunix.net/uid--id-5214135.html
rapidjson的Move语意,请浏览http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#MoveSemantics,示例:rapidjson::Value&a(123);rapidjson::Value&b(456);b&=&a;&//&a变成Null,b变成数字123,这样的做法是基于性能考虑除了上述示例的复制语句外,AddMember()和PushBack()也采用了Move语意。深复制Value:Value&v1(\&foo\&);//&Value&v2(v1);&//&不容许Value&v2(v1,&a);&//&制造一个克隆,v1不变Document&d;v2.CopyFrom(d,&a);&//&把整个document复制至v2,d不变rapidjson为了最大化性能,大量使用了浅拷贝,使用之前一定要了解清楚。<b
请登录后评论。

我要回帖

更多关于 string转化为json 的文章

 

随机推荐