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());
}
=====================================================================