C++ JSON
Contents
前言
在 C++ 中有许多第三方库可以解析 JSON,但是都不是很好用,不能像 Java 中的 gson 、 fastjson 一样直接把 JSON 直接转成对象。
找了许多库,找到了nlohmann/json: JSON for Modern C++使用起来比较方便,也踩了坑,来了解一下。
JSON 转对象
#include <string>
#include "nlohmann/json.hpp"
struct Person
{
std::string name;
int age;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Person, name, age)
};
std::string data = R"({"name":"json", "age": 18})"_json;
nlohmann::json j = nlohmann::json::parse(data.c_str());
auto p = j.get<Person>();
在 nlohmann/json 中,如果需要一个对象可以被解析需要实现 to_json 和 from_json 这两个方法。如果每个类都要写一遍那就很麻烦,所以提供了 NLOHMANN_DEFINE_TYPE_INTRUSIVE 这个宏来简化代码,但是这里有个坑,下文会说。
有了这个准备就可以使用 json::parse 把 JSON 字符串转成 json 对象,然后实用 json.get<T> 来把 JSON 转成对应的对象,这里需要传入要转换的模板。
对象转 JSON
Pserson p = {"json", 20};
nlohmann::json j = p;
std::string json = j.dump();
std::cout << json << std::endl;
要把对象转 JSON 字符串,可以通过 json.dump() 把对象转字符串。
处理没有 key 的情况
上面这样使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE 宏来生成 to_json 和 from_json 方法非常方便,但是却有坑,它不能处理 key 不存在的情况,会直接抛异常。
这时候我们就需要自定义转换的逻辑了,也就是要写 to_json 和 from_json 两个方法
struct Person
{
std::string name;
int age;
};
void to_json(nlohmann::json& j, const Person& p) {
j = nlohmann::json{{"name", p.name}, {"age", p.age}};
}
void from_json(const nlohmann::json& j, Person& p) {
try {
if (j.contains("name")) {
j.at("name").get_to(p.name);
}
if (j.contains("age")) {
j.at("age").get_to(p.age);
}
} catch(const nlohmann::json::exception& e) {
std::cout << e.what() << std::endl;
}
}
我们在 from_json 中对每个 key 先判断存不存在,存在才去获取 value ,这样就不会说 key 找不到了。
总结
C++ 中使用nlohmann/json: JSON for Modern C++来解析 JSON 相对其它库还是比较方便的,不用每次使用的时候都手动解析,但是和其它语言里的相比还是差了不少。
这里需要注意使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE 的时候, key 如果不存在会直接抛异常。
解决这个问题可以自定义 from_json 和 to_json 来进行灵活的控制。