rapidjson常見使用示例
目錄
11. 示例5: 以Writer構造一個json,然後修改它,最後轉成字串 8
12. 示例6: 以Document構造一個json,然後修改它,最後轉成字串 9
13. 示例7: 以Document構造一個json,然後修改它,最後轉成字串 11
1. 前言
rapidjson相比jsoncpp效能高出太多,使用介面一樣的簡單的。官方中文幫助文件:http://rapidjson.org/zh-cn/。
2. 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為了最大化效能,大量使用了淺拷貝,使用之前一定要了解清楚。如果採用了淺拷貝,特別要注意區域性物件的使用,以防止物件已被析構了,卻還在被使用。
3. rapidjson::Document
特別注意rapidjson::Document可以為object、array、number、string、boolean和null中任意一種型別。只有為object時才可以呼叫HasMember等與object有關的方法。
#include <rapidjson/document.h> #include <rapidjson/error/en.h> #include <rapidjson/stringbuffer.h> #include <rapidjson/writer.h> #include <stdio.h>
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; } |
4. 成員迭代器MemberIterator
成員迭代器rapidjson::Value::MemberIterator實際指向GenericMember:
template <typename Encoding, typename Allocator> struct GenericMember { // 成員名,只能為string值 GenericValue<Encoding, Allocator> name; // 成員值,可為各類型別,如字串、陣列、子物件等 GenericValue<Encoding, Allocator> value; };
typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; class GenericMemberIterator { typedef GenericMember<Encoding,Allocator> PlainType; typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; typedef std::iterator<std::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_; } }; |
5. 陣列迭代器ValueIterator
陣列迭代器ValueIterator實際為GenericValue指標:
typedef GenericValue* ValueIterator; typedef const GenericValue* ConstValueIterator; |
6. #include標頭檔案
// 需要#include的標頭檔案: #include <rapidjson/document.h> #include <rapidjson/error/en.h> #include <rapidjson/stringbuffer.h> #include <rapidjson/writer.h> |
其中en為english的簡寫,定義了取出錯資訊的函式GetParseError_En(errcode)。
7. 示例1:解析一個字串
1) 執行輸出結果
count=2 name=zhangsan name=wangwu |
2) 示例程式碼
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<names_json.Size(); ++i) { std::string name = names_json[i].GetString(); printf("name=%s\n", name.c_str()); } } } } |
8. 示例2:構造一個json並轉成字串
1) 執行輸出結果
{"count":2,"names":[{"name":"zhangsan"},{"name":"wangwu"}]} |
2) 示例程式碼
void x2() { rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::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()); } |
9. 示例3:修改一個已有的json字串
1) 執行輸出結果
{"name":"wangwu","age":22} |
2) 示例程式碼
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::Writer<rapidjson::StringBuffer> writer(buffer); document.Accept(writer); printf("%s\n", buffer.GetString()); } |
10. 示例4:讀陣列
1) 執行輸出結果
zhangsan wangwu |
2) 示例程式碼
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<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"); } } |
11. 示例5: 以Writer構造一個json,然後修改它,最後轉成字串
1) 執行輸出結果
{"count":2} {"count":8} |
2) 示例程式碼
void x5() { rapidjson::StringBuffer buffer1; rapidjson::Writer<rapidjson::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::Writer<rapidjson::StringBuffer> writer2(buffer2);
document.Accept(writer2); printf("%s\n", buffer2.GetString()); } |
12. 示例6: 以Document構造一個json,然後修改它,最後轉成字串
1) 執行輸出結果
{"count":3,"names":[{"id":1,"name":"zhangsan"}]} {"count":9,"names":[{"id":1,"name":"zhangsan"}]} |
2) 示例程式碼
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::Writer<rapidjson::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::Writer<rapidjson::StringBuffer> writer2(buffer2); document.Accept(writer2); printf("%s\n", buffer2.GetString()); } |
13. 示例7: 以Document構造一個json,然後修改它,最後轉成字串
1) 執行輸出結果(不轉義就輸出)
x7=> {"title":"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"} |
2) 示例程式碼
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::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<> > writer(buffer); // 如果上面一句改成普通的: // rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); // 則輸出將變成: // x7=> // 貧困孤兒助養
document.Accept(writer); printf("x7=>\n%s\n", buffer.GetString()); } |
14. 示例8:構造空物件和陣列
1) 執行輸出結果
{"age":{},"times":{},"names":[],"urls":[],"books":[]} {"age":6,"times":{},"names":[],"urls":[],"books":[]} |
2) 示例程式碼
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::Writer<rapidjson::StringBuffer> writer1(buffer1); document.Accept(writer1); printf("%s\n", buffer1.GetString());
rapidjson::Value& age = document["age"]; age.SetInt(6);
rapidjson::StringBuffer buffer2; rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2); document.Accept(writer2); printf("%s\n", buffer2.GetString()); } |
15. 示例9:刪除陣列元素
1) 執行輸出結果
{ "names": [ {"name":"zhangsan","age":100}, {"name":"wangwu","age":90}, {"name":"xiaozhang","age":20} ]} {"names":[{"name":"zhangsan","age":100},{"name":"wangwu","age":90}]} |
2) 示例程式碼
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::Writer<rapidjson::StringBuffer> writer(buffer); document.Accept(writer);
printf("%s\n", str.c_str()); printf("%s\n", buffer.GetString()); } |
16. 示例10:不轉義中文
1) 執行輸出結果
{"title":"貧困孤兒助養"} {"title":"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"} |
2) 示例程式碼
//g++ -g -o b b.cpp -I/usr/local/thirdparty/rapidjson/include #include <rapidjson/document.h> #include <rapidjson/stringbuffer.h> #include <rapidjson/writer.h> #include <string> #include <stdio.h>
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::Writer<rapidjson::StringBuffer> writer1(buffer1); document.Accept(writer1); printf("%s\n", buffer1.GetString());
rapidjson::StringBuffer buffer2; rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<> > writer2(buffer2); document.Accept(writer2); printf("%s\n", buffer2.GetString());
return 0; } |
17. 示例11:schema使用示例
json的schema用來檢驗json資料,它也採用了json格式。
1) 示例程式碼
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()); } } } |
2) 示例json
{ "id": 1, "name": "A green door", "price": 12.50, "tags": ["home", "green"] } |
3) 上段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》。
18. 示例12:schema完整示例
#include <rapidjson/document.h> #include <rapidjson/schema.h> #include <rapidjson/stringbuffer.h>
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; } |
19. FindMember整數值
int age; const rapidjson::Value::ConstMemberIterator iter = doc.FindMember("age"); if (iter!=doc.MemberEnd() && iter->value.IsInt()) age = iter->value.GetInt(); |
20. FindMember字串值
std::string name; const rapidjson::Value::ConstMemberIterator iter = doc.FindMember("name"); if (iter!=doc.MemberEnd() && iter->value.IsString()) name.assign(iter->value.GetString(), iter->value.GetStringLength()); |
21. 遍歷成員
rapidjson::Value value; 。。。 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()); } |
22. 遍歷陣列1:字串陣列
// 示例陣列: // {"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()); } |
23. 遍歷陣列2:一級物件陣列
// 陣列示例: // {"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; } } |
24. 遍歷陣列3:兩級物件陣列
// 陣列示例: // {"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 } } } |
25. 輔助函式1:任意型別都以字串返回
// 如果不存在,或者為陣列則返回空字串。 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 <inttypes.h>, // 同時編譯時需要定義巨集__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; } |
26. 輔助函式2:取int32_t值
當為int32_t值或字串實際為int32_t值時,返回對應的int32_t值,其它情況返回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; } |
27. 輔助函式3:取int64_t值
當為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; } |
28. 輔助函式4:取uint32_t值
當為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; } |
29. 輔助函式5:取uint64_t值
當為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; } |
30. 輔助函式6:物件轉字串
std::string& to_string(const rapidjson::Value& value, std::string* str) { rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::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 } |
31. 輔助函式7:字串轉物件
bool to_rapidjson(const std::string& str, rapidjson::Document* doc) { 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("{}"); } |
32. rapidjson的“坑”
使用不當,則會掉進“坑”裡。下列程式碼在valgrind中執行時,會報大量錯誤,而且如果sub是在一個迴圈中被AddMember,則無法得到預期的結果。
從現象看像是sub析構後仍在被使用,為驗證這個推測,改成:rapidjson::Document* sub = new rapidjson::Document;,然後再使用不但valgrind不報錯,而且迴圈使用也沒問題,那麼可以肯定AddMember是淺拷貝,這樣一來使用就不方便了,除非還有深拷貝的呼叫方式。
#include <rapidjson/schema.h> #include <rapidjson/document.h> #include <rapidjson/stringbuffer.h> #include <rapidjson/writer.h> #include <string> #include <vector>
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::Writer<rapidjson::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<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::IsString() const (document.h:947) ==30425== by 0x8051632: bool rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Accept<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u> >(rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, 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<rapidjson::CrtAllocator>::Clear() (allocators.h:148) ==30425== by 0x804BE2E: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::~MemoryPoolAllocator() (allocators.h:140) ==30425== by 0x804BE5F: rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::Destroy() (document.h:2382) ==30425== by 0x804BE7E: rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::~GenericDocument() (document.h:2064) |
正確可以使用的寫法:
#include <rapidjson/schema.h> #include <rapidjson/document.h> #include <rapidjson/stringbuffer.h> #include <rapidjson/writer.h> #include <string> #include <vector>
int main() { std::vector<rapidjson::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::Writer<rapidjson::StringBuffer> writer(buffer); doc.Accept(writer); printf("%s\n", buffer.GetString());
for (std::vector<rapidjson::Document*>::size_type i=0; i<subs.size(); ++i) { rapidjson::Document *sub_ptr = subs[i]; delete sub_ptr; } subs.clear();
return 0; } |
相關文章
- golang reflect 常見示例Golang
- Python常見工廠函式用法示例Python函式
- Swap函式的寫法及其常見錯誤示例函式
- 常見的PID的演算法及程式碼示例演算法
- MQ 常見的使用場景MQ
- U-boot常見命令使用boot
- 使用 CocoaPods 時常見錯誤
- markdown編輯器常見使用
- 常見網路測試命令使用
- composer使用常見問題記錄
- 使用 Grid 進行常見佈局
- RxJava 入門和常見使用方式RxJava
- 【常見錯誤】--Nltk使用錯誤
- 使用python繪出常見函式Python函式
- 四種常見NLP框架使用總結框架
- C語言常見使用問題2C語言
- Firefox 使用常見問題和解決方法Firefox
- Redis常見的16個使用場景Redis
- rocketmq常見問題及使用 新手篇MQ
- 使用HTTP代理失敗的常見原因HTTP
- axios常見的使用方法(精選)iOS
- Go常見錯誤第15篇:interface使用的常見錯誤和最佳實踐Go
- 使用IDEA模擬git命令使用的常見場景IdeaGit
- Flutter 常見異常分析Flutter
- linux使用者和組管理常見命令Linux
- 使用代理IP常見的三大誤區
- 使用代理IP的三個常見場景
- jQuery中$.each()常見使用方法有哪些jQuery
- python re模組常見使用方法整理Python
- C++中使用sort對常見容器排序C++排序
- 使用Python時常見的9個錯誤Python
- Emacs基礎使用教程及常見命令整理Mac
- 資料中心代理的常見使用場景
- keepalived 1.3.5常見配置以及常見問題解決
- python語言幾個常見函式的使用Python函式
- iOS FTPManager的簡單使用及常見問題iOSFTP
- KVM簡介,安裝及常見使用詳解
- 關於PaddleSharp GPU使用 常見問題記錄GPU