rapidjson使用

簡介

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串:

  1. 通過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; 
} 

  1. 通過構造一個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;
}
  1. 使用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 函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章