用RapidJSON 的SAX解析器处理influxDB的查询结果

  • RapidJSON是一个C++的JSON解析器及生成器。它的灵感来自RapidXml
  • RapidJSON小而全。它同时支持SAX和DOM风格的API。SAX解析器只有约500行代码
  • RapidJSON快。它的性能可与strlen()相比。可支持SSE2/SSE4.1加速
  • RapidJSON独立。它不依赖于BOOST等外部库。它甚至不依赖于STL
  • RapidJSON对内存友好。在大部分32/64位机器上,每个JSON值只占16或20字节(除字符串外)。它预设使用一个快速的内存分配器,令分析器可以紧凑地分配内存
  • RapidJSON对Unicode友好。它支持UTF-8、UTF-16、UTF-32 (大端序/小端序),并内部支持这些编码的检测、校验及转码。例如,RapidJSON可以在分析一个UTF-8文件至DOM时,把当中的JSON字符串转码至UTF-16。它也支持代理对(surrogate pair)及"\\u0000"(空字符)

官网地址:

http://rapidjson.org/zh-cn/

"SAX" 此术语源于 Simple API for XML

DOM方式较为简单,但是效率较低。SAX适用于已知结构的Json,但是文档较少,例子较少。我研究了一下,在我的应用中用到了,现在把基本实现写出来供大家借鉴。

要实现的是对influxDB查询到的数据的解析,influxDB返回的结果是Json,且为固定格式,用SAX格式,最好不过了。先前用的是DOM方式,但是效率有点低。

{
    "results": [
        {
            "statement_id": 0,
            "series": [
                {
                    "name": "WEMW",
                    "columns": [
                        "time",
                        "sample",
                        "iGenPower",
                        "trubId"
                    ],
                    "values": [
                        [
                            "2018-08-31T00:18:23Z",
                            "2.48",
                            "0",
                            null
                        ],
                        [
                            "2018-08-31T08:25:18Z",
                            "3.08",
                            "40",
                            null
                        ],
                        [
                            "2018-08-31T22:15:32Z",
                            "2.37",
                            "0",
                            null
                        ],
                        [
                            "2018-09-01T08:09:17Z",
                            "2.23",
                            "0",
                            null
                        ],
                        [
                            "2018-09-01T15:22:43Z",
                            "2.67",
                            "52",
                            null
                        ],
                        [
                            "2018-09-01T21:34:03Z",
                            "2.72",
                            "0",
                            null
                        ]
                    ]
                }
            ]
        }
    ]
}

上代码 。

读取columns这一行的数据。

struct columnReader {
	bool inColArray = false;
	std::vector<std::string> columns;

	bool Key(const char *str, SizeType length, bool copy) {
		if (strncmp(str, "columns", length) == 0) inColArray = true;
		return true;
	}
	bool String(const char *str, SizeType length, bool copy) {
		if (inColArray) columns.emplace_back(str);
		return true;
	}
	bool EndArray(SizeType elementCount) { return !inColArray; /*stop after column array*/ }
	bool Null() { return true; }
	bool Bool(bool b) { return true; }
	bool Int(int i) { return true; }
	bool Uint(unsigned u) { return true; }
	bool Int64(int64_t i) { return true; }
	bool Uint64(uint64_t u) { return true; }
	bool Double(double d) { return true; }
	bool RawNumber(const char *str, SizeType length, bool copy) { return true; }
	bool StartObject() { return true; }
	bool EndObject(SizeType memberCount) { return true; }
	bool StartArray() { return true; }
};

读取具体的values

struct valuesReader {
	bool isInValueArray = false;
	int numRow = 0;
	int numColumn = 0;
	int inValueArray = 0;//1进入values,2进入某一行


	vector<vector<string>  > valueList;
	vector<string>	value;

	int row = 0;
	bool Key(const char *str, SizeType length, bool copy) {
		//if (strncmp(str, "series", length) == 0) inSeriesArray = true;
		if (strncmp(str, "values", length) == 0) {
			isInValueArray = true;
			inValueArray++;
		}
		return true;
	}
	bool StartArray() {
		if (isInValueArray){
			if (inValueArray == 0)
			{
				inValueArray++;
				numRow++;
			}
			else if (inValueArray == 1)
			{
				inValueArray++;
				numRow++;
			}

		}
		return true;
	}


	bool String(const char *str, SizeType length, bool copy) {
		if (inValueArray == 2) value.emplace_back(str);
		return true;
	}
	bool Null() {
		if (inValueArray == 2) value.push_back("");
		return true;
	}
	bool EndArray(SizeType elementCount) {
		if (inValueArray == 2) {
			--inValueArray;
			numColumn = 0;
			valueList.emplace_back(std::move(value));
		}
		else if (inValueArray == 1) {
			--inValueArray;
		}
		return true;
	}


	bool Bool(bool b) { return true; }
	bool Int(int i) { return true; }
	bool Uint(unsigned u) { return true; }
	bool Int64(int64_t i) { return true; }
	bool Uint64(uint64_t u) { return true; }
	bool Double(double d) { return true; }
	bool RawNumber(const char *str, SizeType length, bool copy) { 
		if (inValueArray == 2) value.emplace_back(std::string{ str, length }); 
		return true;
	}
	bool StartObject() { return true; }
	bool EndObject(SizeType memberCount) { return true; }

};

最后是调用2种Handler进行测试:

void f1()
{
	Reader reader;
	StringStream ss(json);

	ifstream fin("result1000.json");
	//创建字符串流对象
	stringstream sin;
	//把文件流中的字符输入到字符串流中
	sin << fin.rdbuf();
	//获取字符串流中的字符串
	string str = sin.str();
	fin.close();
	fin.clear();
	rapidjson::StringStream ss1(str.c_str());

	columnReader columnHandler;
	//reader.Parse(ss1, handler);
	//reader.Parse(ss1, columnHandler);
	valuesReader valuesHandler;

	reader.Parse<kParseNumbersAsStringsFlag>(ss1, valuesHandler);

}
void main() {
	
	char c;
	do{
		for (int i = 0; i < 10;i++)
			f1();
		c = getchar();
	} while (c);

}

kParseNumbersAsStringsFlag是这样用的:

reader.Parse<kParseNumbersAsStringsFlag>(ss1, valuesHandler);

经测试,比DOM方式快了许多。

代码参考了https://github.com/f4bsch/influxdb-hp的实现,在此注明。

猜你喜欢

转载自blog.csdn.net/v6543210/article/details/82597062