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

参考资料