rapidjson踩坑之旅

xingyun86 2019-6-19 2639

rapidjson号称速度最快、内存占用最小的c++ json处理库。真正使用时却也有不少坑,接下来一起去看看踩过的坑。

1.parse坑

const char* json_str = "{\"seqno\":\"12345678\",\"cmd\":\"65\",\"data\": {"\"id\": 30}}";
rapidjson::Document doc;
doc.Parse(json_str);

上面貌似很平常的代码,却隐藏这杀机。解析是否成功,还不知道。

正确如下:

const char* json_str = "{\"seqno\":\"12345678\",\"cmd\":\"65\",\"data\": {"\"id\": 30}}";
rapidjson::Document doc;
doc.Parse(json_str);
if (doc.HasParseError())
{
	printf("[%s] HasParseError error(%d)\n", __func__, doc.GetParseError());
}

2.AddMember坑

rapidjson::Document doc;
rapidjson::Value v;
v.AddMember(str.c_str(), 0, doc.GetAllocator());

上面貌似很平常的代码,却连编译都过不了。

正确如下:

rapidjson::Document doc;
rapidjson::Value v;
rapidjson::Value key(str.c_str(), doc.GetAllocator());
v.AddMember(key, 0, doc.GetAllocator());

3.kArrayType坑

方法一:
rapidjson::Document doc;
rapidjson::Value array(rapidjson::kArrayType);
array.PushBack("20190618", doc.GetAllocator());
array.PushBack("20190619", doc.GetAllocator());
方法二:
doc.AddMember("time", {}, alloc);
doc["time"].SetArray();
doc["time"].PushBack("20190618", alloc);
doc["time"].PushBack("20190619", alloc);

4.PushBack坑

std::string s = "{\"fileno\":123,\"user\":\"test\"}";
rapidjson::Document doc;
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
rapidjson::Value resp;
resp.SetObject();
resp.AddMember("list", {}, allocator);
resp["list"].SetArray();
rapidjson::Value& item = doc.SetObject();
doc.Parse(s.c_str());
if (!doc.HasParseError())
{
	resp["list"].PushBack(item, allocator);
	printf("user=%s,fileno=%d\n", item["user"].GetString(), item["fileno"].GetInt());
}

上面貌似很平常的代码,编译也没问题,但是一旦运行,程序必然崩溃。

正确如下:

std::string s = "{\"fileno\":123,\"user\":\"test\"}";
rapidjson::Document doc;
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
rapidjson::Value resp;
resp.SetObject();
resp.AddMember("list", {}, allocator);
resp["list"].SetArray();
rapidjson::Value& item = doc.SetObject();
doc.Parse(s.c_str());
if (!doc.HasParseError())
{
	printf("user=%s,fileno=%d\n", item["user"].GetString(), item["fileno"].GetInt());
	resp["list"].PushBack(item, allocator);
}

5.for/while循环调用坑

std::map<std::string, std::string> ssmap = {
	{"1","{\"seqno\":\"1561357150\",\"cmd\":\"test\",\"status\":0,\"msg\":\"OK\",\"data\":{}}"},
	{"2","{\"seqno\":\"1561359832\",\"cmd\":\"test\",\"status\":0,\"msg\":\"OK\",\"data\":{}}"},
};
rapidjson::Document doc;
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
rapidjson::Value& resp = doc.SetObject();
resp.AddMember("data", {}, allocator);
resp["data"].SetObject();
resp["data"].AddMember("list", {}, allocator);
resp["data"]["list"].SetArray();
for (auto& it : ssmap)
{
	printf("key=%s,value=%s\n", it.first.c_str(), it.second.c_str());
	rapidjson::Document doc_item;
	rapidjson::Value& resp_item = doc_item.SetObject();
	doc_item.Parse(it.second.c_str());
	if (doc_item.HasParseError())
	{
		continue;
	}
	resp["data"]["list"].PushBack(resp_item, allocator);
}
printf("resp:%s\n", JSON_VALUE_2_STRING(resp).c_str());

上面貌似很平常的代码,可以编译过,却大概率出错崩溃。

正确如下:

std::map<std::string, std::string> ssmap = {
	{"1","{\"seqno\":\"1561357150\",\"cmd\":\"test\",\"status\":0,\"msg\":\"OK\",\"data\":{}}"},
	{"2","{\"seqno\":\"1561359832\",\"cmd\":\"test\",\"status\":0,\"msg\":\"OK\",\"data\":{}}"},
};
rapidjson::Value resp;
rapidjson::Document doc;
rapidjson::Document::AllocatorType& allocator = rapidjson::Document().GetAllocator();
resp.SetObject();
resp.AddMember("data", {}, allocator);
resp["data"].SetObject();
resp["data"].AddMember("list", {}, allocator);
resp["data"]["list"].SetArray();
for (auto& it : ssmap)
{
	printf("key=%s,value=%s\n", it.first.c_str(), it.second.c_str());
	rapidjson::Value& item = doc.SetObject();
	doc.Parse(it.second.c_str());
	if (doc.HasParseError())
	{
		continue;
	}
	printf("resp:%s\n", JSON_VALUE_2_STRING(item).c_str());
	resp["data"]["list"].PushBack(item, allocator);
}
printf("resp:%s\n", JSON_VALUE_2_STRING(resp).c_str());

6.FindMember数组查找坑({"array":["1234","5678"]})

    std::cout << "Hello World!\n";
    std::string json_str = "{\"int\":123,\"float\":10.0,\"string\":\"天天\"}";
    rapidjson::Document d_file;
    rapidjson::Value& v_file = d_file.SetObject();
    if (!d_file.Parse(json_str.c_str()).HasParseError())
    {
        v_file.AddMember("array", {}, d_file.GetAllocator());
        v_file["array"].SetArray();
        v_file["array"].PushBack("1234", d_file.GetAllocator());
        v_file["array"].PushBack("5678", d_file.GetAllocator());
        std::string find_str = "5678";
        // 遍历数组查找指定值
        rapidjson::Value& v_array = v_file["array"];
        rapidjson::Value::ConstValueIterator v_iter = v_array.FindMember(find_str.c_str());
        if (v_iter != v_array.End())
        {
            printf("find member\n");
        }
    }

上面貌似很平常的代码,可以编译过,却大概率出错崩溃。(针对)

正确如下:

    std::cout << "Hello World!\n";
    std::string json_str = "{\"int\":123,\"float\":10.0,\"string\":\"天天\"}";
    rapidjson::Document d_file;
    rapidjson::Value& v_file = d_file.SetObject();
    if (!d_file.Parse(json_str.c_str()).HasParseError())
    {
        v_file.AddMember("array", {}, d_file.GetAllocator());
        v_file["array"].SetArray();
        v_file["array"].PushBack("1234", d_file.GetAllocator());
        v_file["array"].PushBack("5678", d_file.GetAllocator());
        std::string find_str = "5678";
        // 遍历数组查找指定值
        rapidjson::Value& v_array = v_file["array"];
        rapidjson::Value::ConstValueIterator v_iter = nullptr;
        for (v_iter = v_array.Begin(); v_iter != v_array.End(); )
        {
            if (!find_str.compare((*v_iter).GetString()))
            {
                break;
            }
            else
            {
                v_iter++;
            }
        }
        if (v_iter != v_array.End())
        {
            printf("find member\n");
        }
    }

最佳实践

#pragma once

#include <rapidjson/reader.h>
#include <rapidjson/writer.h>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <iostream>
#include <functional>

#define CHECK_JSON_NUL(JSON, KEY)  (JSON.HasMember(KEY) && JSON[KEY].IsNull())
#define CHECK_JSON_INT(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsInt())
#define CHECK_JSON_BOL(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsBool())
#define CHECK_JSON_ARY(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsArray())
#define CHECK_JSON_FLT(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsFloat())
#define CHECK_JSON_I64(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsInt64())
#define CHECK_JSON_DBL(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsDouble())
#define CHECK_JSON_OBJ(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsObject())
#define CHECK_JSON_STR(JSON, KEY)  (JSON.HasMember(KEY) && !JSON[KEY].IsNull() && JSON[KEY].IsString())

__inline static
std::string JSON_VALUE_2_STRING(const rapidjson::Value& v)
{
	rapidjson::StringBuffer sb;
	rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
	return (v.Accept(writer) ? std::string(sb.GetString(), sb.GetSize()) : (""));
}
__inline static
const rapidjson::Value& STRING_2_JSON_VALUE(rapidjson::Document & d, const std::string& s)
{
	rapidjson::Value& v = d.SetObject();
	d.Parse(s.c_str(), s.size());
	return v;
}
__inline static
std::shared<rapidjson::Document> STRING_2_JSON_VALUE(const std::string& s)
{
	std::shared<rapidjson::Document> d = std::make_shared<rapidjson::Document>();
	d->Parse(s.c_str(), s.size());
	return (d);
}
=====================================================================
std::string s = "{\"test\":123}";
const rapidjson::Value& v = STRING_2_JSON_VALUE(s);
if (!v.ObjectEmpty())
{
	printf("%s\n", JSON_VALUE_2_STRING(v).c_str());
}
=====================================================================


×
打赏作者
最新回复 (0)
只看楼主
全部楼主
返回