目录
目录 1
前言 2
Move语意 2
rapidjson::Document 2
成员迭代器MemberIterator 3
数组迭代器ValueIterator 4
#include头文件 4
示例1:解析一个字符串 4
示例2:构造一个json并转成字符串 6
示例3:修改一个已有的json字符串 7
示例4:读数组 8
示例5: 以Writer构造一个json,然后修改它,最后转成字符串 8
示例6: 以Document构造一个json,然后修改它,最后转成字符串 9
示例7: 以Document构造一个json,然后修改它,最后转成字符串 11
示例8:构造空对象和数组 12
示例9:删除数组元素 13
示例10:不转义中文 13
示例11:schema使用示例 14
示例12:schema完整示例 16
FindMember整数值 17
FindMember字符串值 17
遍历成员 18
遍历数组1:字符串数组 18
遍历数组2:一级对象数组 18
遍历数组3:两级对象数组 19
辅助函数1:任意类型都以字符串返回 20
辅助函数2:取int32_t值 21
辅助函数3:取int64_t值 21
辅助函数4:取uint32_t值 22
辅助函数5:取uint64_t值 23
辅助函数6:对象转字符串 23
辅助函数7:字符串转对象 24
rapidjson的“坑” 24
前言
rapidjson相比jsoncpp性能高出太多,使用接口一样的简单的。官方中文帮助文档:http://rapidjson.org/zh-cn/。
Move语意
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为了最大化性能,大量使用了浅拷贝,使用之前一定要了解清楚。如果采用了浅拷贝,特别要注意局部对象的使用,以防止对象已被析构了,却还在被使用。
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
std::string str;
rapidjson::Document doc;
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”);
else
{
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;
}
template
struct GenericMember {
// 成员名,只能为string值
GenericValue
// 成员值,可为各类类型,如字符串、数组、子对象等
GenericValue
};
typedef typename GenericMemberIterator
class GenericMemberIterator {
typedef GenericMember
typedef typename internal::MaybeAddConst
typedef std::iteratorstd::random_access_iterator_tag,ValueType BaseType;
typedef GenericMemberIterator Iterator;
// Pointer to (const) GenericMember
typedef typename BaseType::pointer Pointer;
Pointer ptr_; // raw pointer
Pointer operator->() const { return ptr_; }
};
typedef GenericValue* ValueIterator;
typedef const GenericValue* ConstValueIterator;
#include
#include
#include
#include
其中en为english的简写,定义了取出错信息的函数GetParseError_En(errcode)。
count=2
name=zhangsan
name=wangwu
void x1()
{
rapidjson::Document document; // 定义一个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()));
}
else
{
// 判断某成员是否存在
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 { std::string name = names_json[i].GetString(); printf(“name=%s\n”, name.c_str()); } } } } {“count”:2,“names”:[{“name”:“zhangsan”},{“name”:“wangwu”}]} void x2() { rapidjson::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer 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()); } {“name”:“wangwu”,“age”:22} void x3() { rapidjson::Document document; 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::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); document.Accept(writer); printf("%s\n", buffer.GetString()); } zhangsan wangwu void x4() { rapidjson::Document document; 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()); } else { rapidjson::Value& names_json = document[“names”]; for (rapidjson::SizeType i=0; i { if (names_json[i].HasMember(“name”)) { rapidjson::Value& name_json = names_json[i][“name”]; printf("%s ", name_json.GetString()); } } printf("\n"); } } {“count”:2} {“count”:8} void x5() { rapidjson::StringBuffer buffer1; rapidjson::Writerrapidjson::StringBuffer writer1(buffer1); writer1.StartObject(); writer1.Key(“count”); writer1.Int(2); writer1.EndObject(); printf("%s\n", buffer1.GetString()); // 转成Document对象 rapidjson::Document document; document.Parse(buffer1.GetString()); // 修改 rapidjson::Value& count_json = document[“count”]; count_json.SetInt(8); // 转成字符串 rapidjson::StringBuffer buffer2; rapidjson::Writerrapidjson::StringBuffer writer2(buffer2); document.Accept(writer2); printf("%s\n", buffer2.GetString()); } {“count”:3,“names”:[{“id”:1,“name”:“zhangsan”}]} {“count”:9,“names”:[{“id”:1,“name”:“zhangsan”}]} void x6() { rapidjson::Document document; 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::Writerrapidjson::StringBuffer writer1(buffer1); document.Accept(writer1); printf("%s\n", buffer1.GetString()); // 修改值 rapidjson::Value& count_json = document[“count”]; count_json.SetInt(9); // 再次输出 rapidjson::StringBuffer buffer2; rapidjson::Writerrapidjson::StringBuffer writer2(buffer2); document.Accept(writer2); printf("%s\n", buffer2.GetString()); } x7=> {“title”:"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"} void x7() { std::string root = “{}”; rapidjson::Document document; 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::StringBuffer buffer; rapidjson::Writer // 如果上面一句改成普通的: // rapidjson::Writerrapidjson::StringBuffer writer(buffer); // 则输出将变成: // x7=> // 贫困孤儿助养 document.Accept(writer); printf(“x7=>\n%s\n”, buffer.GetString()); } {“age”:{},“times”:{},“names”:[],“urls”:[],“books”:[]} {“age”:6,“times”:{},“names”:[],“urls”:[],“books”:[]} void x8() { rapidjson::Document document; 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::Writerrapidjson::StringBuffer writer1(buffer1); document.Accept(writer1); printf("%s\n", buffer1.GetString()); rapidjson::Value& age = document[“age”]; age.SetInt(6); rapidjson::StringBuffer buffer2; rapidjson::Writerrapidjson::StringBuffer 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}]} void x9() { std::string str = “{ “names”: [ {“name”:“zhangsan”,“age”:100}, {“name”:“wangwu”,“age”:90}, {“name”:“xiaozhang”,“age”:20} ]}”; rapidjson::Document document; 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 ++iter; } rapidjson::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); document.Accept(writer); printf("%s\n", str.c_str()); printf("%s\n", buffer.GetString()); } {“title”:“贫困孤儿助养”} {“title”:"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"} //g++ -g -o b b.cpp -I/usr/local/thirdparty/rapidjson/include #include #include #include #include #include int main() { std::string str = “{“title”:”\u8d2b\u56f0\u5b64\u513f\u52a9\u517b"}"; rapidjson::Document document; document.Parse(str.c_str()); if (document.HasParseError()) { printf(“parse %s failed\n”, str.c_str()); exit(1); } rapidjson::StringBuffer buffer1; rapidjson::Writerrapidjson::StringBuffer writer1(buffer1); document.Accept(writer1); printf("%s\n", buffer1.GetString()); rapidjson::StringBuffer buffer2; rapidjson::Writer document.Accept(writer2); printf("%s\n", buffer2.GetString()); return 0; } rapidjson::Document schema_document; schema_document.Parse(schema.c_str()); if (!schema_document.HasParseError()) { rapidjson::Document document; document.Parse(str.c_str()); if (!document.HasParseError()) { SchemaDocument schema(schema_document); SchemaValidator validator(schema); if (!document.Accept(validator)) { // 检验出错,输出错误信息 StringBuffer sb; 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()); } } } { “id”: 1, “name”: “A green door”, “price”: 12.50, “tags”: [“home”, “green”] } { “$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》。 #include #include int main() { std::string str = “{“aaa”:111,“aaa”:222}”; // “{“aaa”:111,“a”:222}” #if 0 std::string schema_str = “{“type”:“object”,“properties”:{“aaa”:{“type”:“integer”},“bbb”:{“type”:“string”}},“required”:[“aaa”,“bbb”]}”; #else std::string schema_str = “{“type”:“object”,“properties”:{“aaa”:{“type”:“integer”},“bbb”:{“type”:“integer”}},“required”:[“aaa”,“bbb”]}”; #endif printf("%s\n", str.c_str()); printf("%s\n", schema_str.c_str()); rapidjson::Document doc; rapidjson::Document schema_doc; 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”); } else { rapidjson::StringBuffer sb; 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; } const rapidjson::Value::ConstMemberIterator iter = doc.FindMember(“age”); if (iter!=doc.MemberEnd() && iter->value.IsInt()) age = iter->value.GetInt(); const rapidjson::Value::ConstMemberIterator iter = doc.FindMember(“name”); if (iter!=doc.MemberEnd() && iter->value.IsString()) name.assign(iter->value.GetString(), iter->value.GetStringLength()); 。。。 for (rapidjson::Value::ConstMemberIterator iter=value.MemberBegin(); iter!=value.MemberEnd(); ++iter) { const rapidjson::Value& name_json = iter->name; // 这个必是字符串 const rapidjson::Value& value_json = iter->value; // 这个可以为对象、数组等 printf("%s\n", name_json.GetString()); } // {“k”:[“k1”,“k2”,“k3”]} rapidjson::Document doc; 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) { // k1 // k2 // k3 printf("%s\n", (*v_iter).GetString()); } // {“h”:[{“k1”:“f1”},{“k2”:“f2”}]} rapidjson::Document doc; 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_iter; 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); break; } } // {“h”:[{“k1”:[“f1”,“f2”]},{“k2”:[“f1”,“f2”]}]} rapidjson::Document doc; 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_iter; // 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->value; // 遍历第二级数组 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 } } } 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”); } else { str[0] = ‘\0’; } return str; } // 当为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 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; } 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; } 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; } { rapidjson::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); value.Accept(writer); str->assign(buffer.GetString(), buffer.GetSize()); return *str; } std::string to_string(const rapidjson::Value& value) { std::string str; to_string(value, &str); #if __cplusplus < 201103L return str; #else return std::move(str); #endif // __cplusplus < 201103L } { doc->Parse(str.c_str()); return !doc->HasParseError(); } void to_rapidjson(const std::string& str, rapidjson::Document& doc) { doc.Parse(str.c_str()); if (doc.HasParseError()) doc.Parse("{}"); } 从现象看像是sub析构后仍在被使用,为验证这个推测,改成:rapidjson::Document* sub = new rapidjson::Document;,然后再使用不但valgrind不报错,而且循环使用也没问题,那么可以肯定AddMember是浅拷贝,这样一来使用就不方便了,除非还有深拷贝的调用方式。 #include #include #include #include #include #include int main() { rapidjson::Document doc; doc.Parse("{}"); { // 目的是让sub在printf时已无效 rapidjson::Document sub; sub.Parse("{“name”:“tom”}"); doc.AddMember(“sub”, sub, doc.GetAllocator()); } rapidjson::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); doc.Accept(writer); printf("%s\n", buffer.GetString()); return 0; } 上述代码在valgrind中跑,会报错大量如下这样的错误: 30425 Invalid read of size 2 30425 at 0x804B008: rapidjson::GenericValue 30425 by 0x8051632: bool rapidjson::GenericValue 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::MemoryPoolAllocatorrapidjson::CrtAllocator::Clear() (allocators.h:148) 30425 by 0x804BE2E: rapidjson::MemoryPoolAllocatorrapidjson::CrtAllocator::~MemoryPoolAllocator() (allocators.h:140) 30425 by 0x804BE5F: rapidjson::GenericDocument 30425 by 0x804BE7E: rapidjson::GenericDocument 正确可以使用的写法: #include #include #include #include #include #include int main() { std::vectorrapidjson::Document* subs; rapidjson::Document doc; 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::StringBuffer buffer; rapidjson::Writerrapidjson::StringBuffer writer(buffer); doc.Accept(writer); printf("%s\n", buffer.GetString()); for (std::vectorrapidjson::Document*::size_type i=0; i { rapidjson::Document *sub_ptr = subs[i]; delete sub_ptr; } subs.clear(); return 0; }
json的schema用来检验json数据,它也采用了json格式。
#include
int age;
std::string name;
rapidjson::Value value;
// 示例数组:
// 数组示例:
// 数组示例:
// 如果不存在,或者为数组则返回空字符串。
当为int32_t值或字符串实际为int32_t值时,返回对应的int32_t值,其它情况返回0。
当为int64_t值,或字符串实际为int64_t值时,返回对应的int64_t值,其它情况返回0。
当为uin32_t值,或字符串实际为uin32_t值时,返回对应的uin32_t值,其它情况返回0。
当为uin64_t值,或字符串实际为uin64_t值时,返回对应的uin64_t值,其它情况返回0。
std::string& to_string(const rapidjson::Value& value, std::string* str)
bool to_rapidjson(const std::string& str, rapidjson::Document* doc)
使用不当,则会掉进“坑”里。下列代码在valgrind中运行时,会报大量错误,而且如果sub是在一个循环中被AddMember,则无法得到预期的结果。