使用rapidJson C++庫生成JSON字元串

前言

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更加方便。

參考資料