使用rapidJson C++庫生成JSON字元串
- 2020 年 3 月 4 日
- 筆記
前言
RapidJSON 是一個 C++ 的 JSON 解析器及生成器,它是騰訊公司開發的一款高效的 C++ JSON 解析/生成器,提供 SAX 及 DOM 風格 API,中文官網地址為:http://rapidjson.org/zh-cn/,從這裡可以看到它的詳細說明文檔;對應的Github地址為:https://github.com/Tencent/rapidjson,從rapidjson-github上面獲取它的最新的源程式碼,然後把include目錄下的rapidjson目錄放在自己指定項目下或者自己項目工程對應的include等目錄下,使用時包含rapid目錄下對應的頭文件就可以了,無需編譯成靜態庫文件。它的靈感來自 RapidXml。
- RapidJSON 小而全。它同時支援 SAX 和 DOM 風格的 API。SAX 解析器只有約 500 行程式碼。
- RapidJSON 快。它的性能可與 strlen() 相比。可支援 SSE2/SSE4.2 加速。
- RapidJSON 獨立。它不依賴於 BOOST 等外部庫。它甚至不依賴於 STL。
- RapidJSON 對記憶體友好。在大部分 32/64 位機器上,每個 JSON 值只佔 16 位元組(除字元串外)。它預設
- 使用一個快速的記憶體分配器,令分析器可以緊湊地分配記憶體。
- RapidJSON 對 Unicode 友好。它支援 UTF-8、UTF-16、UTF-32 (大端序/小端序),並內部支援這些編碼的檢測、校驗及轉碼。例如,RapidJSON 可以在分析一個 UTF-8 文件至 DOM 時,把當中的 JSON 字元串轉碼至 UTF-16。它也支援代理對(surrogate pair)及 「u0000」(空字元)。
可以在Linux發行版CentOS7下使用git clone https://github.com/Tencent/rapidjson命令從github上面下載對應的rapidjson的最新程式碼,以下是我在我的騰訊雲主機上下載rapidjson的程式碼,以及rapidjson項目的目錄結構,如下圖所示:

從上圖rapidjson項目的目錄中可以看出,include文件包含的rapidjson文件就是我們使用rapidjson進行json字元串操作時所需要引入的頭文件,example是一些程式碼示例,可供參考。
運行官方的simpledom.cpp示常式序
// simpledom.cpp
// JSON simple example // This example does not handle errors. #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" #include <iostream> using namespace rapidjson; int main() { // 1. Parse a JSON string into DOM. const char* json = "{"project":"rapidjson","stars":10}"; Document d; d.Parse(json); // 2. Modify it by DOM. Value& s = d["stars"]; s.SetInt(s.GetInt() + 1); // 3. Stringify the DOM StringBuffer buffer; Writer<StringBuffer> writer(buffer); d.Accept(writer); // Output {"project":"rapidjson","stars":11} std::cout << buffer.GetString() << std::endl; return 0; }
在我的騰訊雲CentOs7.5主機上的運行截圖如下:

應用場景
之前使用過rapidjson讀取過光學雷達的數據,最近在實際C++項目開發過程中需要將從設備客戶端發送的HJ212報警數據解析後生成指定的JSON格式,如下所示:
{ "Stcode": "SS1311054", "Timestamp": "2020-02-26 13:50:41", "Alarm": [{ "paramCode": "EP111", "value": 1.0, "mark": "N" }, { "paramCode": "EP113", "value": 0.0, "mark": "N" }, { "paramCode": "", "value": 0.0, "mark": "N" }, { "paramCode": "", "value": 0.0, "mark": "N" }, { "paramCode": "", "value": 0.0, "mark": "N" }, { "paramCode": "", "value": 0.0, "mark": "N" }, { "paramCode": "EP112", "value": 1.0, "mark": "N" }, { "paramCode": "EP110", "value": 0.0, "mark": "N" }, { "paramCode": "", "value": 0.0, "mark": "N" }, { "paramCode": "EP120", "value": 21.2, "mark": "N" }, { "paramCode": "EP121", "value": 46.2, "mark": "N" }, { "paramCode": "EP122", "value": 26.5, "mark": "N" }, { "paramCode": "EP123", "value": 41.6, "mark": "N" }, { "paramCode": "EP124", "value": 2.297, "mark": "N" }, { "paramCode": "EP125", "value": 3.6, "mark": "N" }, { "paramCode": "EP126", "value": 4.313, "mark": "N" }, { "paramCode": "EP114", "value": 236.18, "mark": "N" }, { "paramCode": "EP115", "value": 238.15, "mark": "N" }, { "paramCode": "EP116", "value": 236.2, "mark": "N" }, { "paramCode": "EP118", "value": 0.52, "mark": "N" }] }
上面的json字元串格式其實蠻簡單的,Stcode表示站點編碼,Timestamp表示數據時間,Alarm元素是一個數組,其中paramCode表示報警監測因子編碼,value表示報警值,mark表示標記位,N表示正常,B表示異常。
使用rapidjson生成json字元串的兩種方式
通常rapidjson生成json有兩種方式,如下:
方式1: 使用rapidjson::Document和rapidjson::Document::AllocatorType分配器
使用rapidjson生成上面類似的C++程式碼如下:
#include <iostream> #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" #include <iostream> void test2() { rapidjson::Document document; document.SetObject(); rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); rapidjson::Value object1(rapidjson::kObjectType); document.AddMember("StCode", "SS1211054", allocator); document.AddMember("Timestamp", "2020-02-24 13:50:41", allocator); // 數組 rapidjson::Value alarmArray(rapidjson::kArrayType); for (int i = 0 ; i < 10; i++) { char strParamCode[128] = { 0 }; sprintf(strParamCode, "param%d", i + 1); rapidjson::Value objectTemp(rapidjson::kObjectType); rapidjson::Value valueParamCode(strParamCode, document.GetAllocator()); objectTemp.AddMember("paramCode", valueParamCode, allocator); objectTemp.AddMember("value", i + 10, allocator); objectTemp.AddMember("mark", "N", allocator); alarmArray.PushBack(objectTemp, allocator); } document.AddMember("Alarm", alarmArray, allocator); StringBuffer buffer; rapidjson::Writer<StringBuffer> writer(buffer); document.Accept(writer); std::string jsonStr2 = buffer.GetString(); // 列印生成的json字元串 std::cout << "test2(), strJson2為: " << jsonStr2.c_str() << std::endl; } int main(int argc, char* argv[]) { test2(); return 0; }
在VS2017中的程式運行截圖如下:

方式2:使用rapidjson::Writer寫入json
使用rapidjson生成上面類似的C++程式碼如下:
#include <iostream> #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" #include <iostream> void test3() { rapidjson::StringBuffer s; rapidjson::Writer<rapidjson::StringBuffer> writer(s); writer.StartObject(); // Stcode部分 writer.Key("Stcode"); writer.String("SS1211054"); // 構造Timestamp writer.Key("Timestamp"); writer.String("2020-02-27 23:50:41"); writer.Key("Alarm"); writer.StartArray(); // 報警監測數據數組列表 for (int i = 0; i < 5; i++) { char strParamCode[128] = { 0 }; sprintf(strParamCode, "param%d", i); writer.StartObject(); writer.Key("paramCode"); writer.String(strParamCode); writer.Key("value"); writer.Double(i*10 + 3.14); writer.Key("mark"); writer.String("N"); writer.EndObject(); } writer.EndArray(); writer.EndObject(); std::string strJson3 = s.GetString(); // 列印生成的json字元串 std::cout << "test3(), strJson3為: " << strJson3.c_str() << std::endl; } int main(int argc, char* argv[]) { test2(); return 0; }
在VS2017中的程式運行截圖如下:

從使用上來說,個人覺得第二種方式:使用rapidjson::Writer寫入json更加方便。
參考資料
- rapidjson創建型
- RapidJSON 中文官方文檔
- rapidjson常見使用示例
- github地址 A fast JSON parser/generator for C++ with both SAX/DOM style API http://rapidjson.org/
- 使用rapidjson構建生成複雜的json串
- 在線JSON校驗格式化工具(Be JSON): https://www.bejson.com