簡介
Rapidjson is a fast JSON parser/generator for C++ with both SAX/DOM style API.
其所有源代碼都包含在源碼包的include/rapidjson/include目錄下,使用時只需要include相應的頭文件即可。
詳細的介紹見rapid官方文檔
使用rapidjson解析json串
先看下rapidjson中的value有哪些類型, rapidjson中定義的類型的先後順序爲:
“Null”, “False”, “True”, “Object”, “Array”, “String”, “Number”
其中Number類型包含int, uint, int64, uint64, double
Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
bool IsNull() const { return data_.f.flags == kNullFlag; }
bool IsFalse() const { return data_.f.flags == kFalseFlag; }
bool IsTrue() const { return data_.f.flags == kTrueFlag; }
bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
bool IsObject() const { return data_.f.flags == kObjectFlag; }
bool IsArray() const { return data_.f.flags == kArrayFlag; }
bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
有了這個後,我們就可以根據dom節點的類型來解析出對應的value,僞代碼如下如下:
#define ERROR -1
#define OK 0
string jsonstr = {"key":value, ...};
Document document;
if(document.Parse(jsonstr.c_str()).HasParseError())
{
return ERROR;
}
const rapidjson::Value& value = document["key"]; //use [] operator to get node value
/** use FindMember function
auto var = document.FindMember("key");
if(var != document.MemberEnd())
{
rapidjson::Value& value = var->value;
}
*/
if(value.IsNull())
{
...
}
else if(value.IsObject())
{
//continue to parse
...
}else if(value.isString())
{
cout << value.GetString();
}else if(value.isNumber())
{
if(value.isInt())
{...
}else if(value.isUint())
{...
}else ...
}
...
另外,我們也可以實現一個打印json串內容的函數:
int printJsonString(string& jsonstr)
{
Document document;
if(document.Parse(json).HasParseError())
{
return -1;
}
static const char* kTypeNames[] =
{ "Null", "False", "True", "Object", "Array", "String", "Number" };
for (auto& m : document.GetObject())
{
printf("Type of member %s is %s\n",
m.name.GetString(), kTypeNames[m.value.GetType()]);
if(m.value.isNull())
{
printf("key = %s, value = %s\n", m.name.GetString(), "null");
}else if(m.value.isString())
{
printf("key = %s, value = %s\n", m.name.GetString(), m.value.GetString());
}else if(...)
...
}
return 0;
}
上述解析的json串是通過string or char字符串輸入的,如果json串來源於文件的話,就需要使用如下的方法調用Parse方法(詳細使用說明參考rapidjson文件流):
#include "rapidjson/filereadstream.h"
#include <cstdio>
using namespace rapidjson;
FILE* fp = fopen("big.json", "rb"); // 非 Windows 平臺使用 "r"
char readBuffer[65536];
FileReadStream is(fp, readBuffer, sizeof(readBuffer));
Document d;
d.ParseStream(is);
fclose(fp);
使用rapidjson構造json串
有幾種方法可用於構造json串:
- 通過rapidjson::Writer<rapidjson::StringBuffer>對象的’StartObject/EndObject’ Method.
int constructJsonStr1(string& outputStr)
{
rapidjson::StringBuffer json_str_buf;
rapidjson::Writer<rapidjson::StringBuffer> json_writer(json_str_buf);
json_writer.StartObject();
json_writer.String("id");
json_writer.Uint(0);
json_writer.String("name");
json_writer.String("zhangsan");
json_writer.String("data");
json_writer.StartObject();
json_writer.String("age");
json_writer.Uint(20);
json_writer.String("province");
json_writer.String("guangdong");
json_writer.EndObject();
json_writer.EndObject();
outputStr = json_str_buf.GetString();
cout << outputStr << endl;
return 0;
}
- 通過構造一個rapidjson::Document對象,使用rapidjson::Document及rapidjson::Value的’AddMember’ Method.
int constructJsonStr2()
{
rapidjson::Document document;
document.SetObject();
rapidjson::Document::AllocatorType & allocator = document.GetAllocator();
document.AddMember("id", 0, allocator);
document.AddMember("name", rapidjson::StringRef("zhangsan"), allocator);
rapidjson::Value data_obj(rapidjson::kObjectType);
data_obj.AddMember("age", 20, allocator);
data_obj.AddMember("province", rapidjson::StringRef("guangdong"), allocator);
document.AddMember("data", data_obj, allocator);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
cout << buffer.GetString() << endl;
return 0;
}
- 使用Document + Pointer
Document d;
// 使用 Set() 創建 DOM
Pointer("/project").Set(d, "RapidJSON");
Pointer("/stars").Set(d, 10);
// { "project" : "RapidJSON", "stars" : 10 }
p.s.:
- PushBack及AddMember中使用了轉移語義
- copy-string與const-string
當我們把一個 copy-string 賦值時, 調用含有 allocator 的 SetString() 重載函數.
Document document;
Value author;
char buffer[10];
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // 動態創建的字符串。
author.SetString(buffer, len, document.GetAllocator());
memset(buffer, 0, sizeof(buffer));
// 清空 buffer 後 author.GetString() 仍然包含 "Milo Yip"
對於字符串字面量或有安全生命週期的字符串,可以使用 const-string 版本的 SetString(),它沒有 allocator 參數。對於字符串字面量(或字符數組常量),只需簡單地傳遞字面量,又安全又高效:
Value s;
s.SetString("rapidjson"); // 可包含空字符,長度在編譯萁推導
s = "rapidjson";
對於字符指針,RapidJSON 需要作一個標記,代表它不復制也是安全的。可以使用 StringRef 函數