nlohmann::json是非常好用的一个json开源解析库.nlohmann/json
的源码是基于C++11标准写的,整个源码就是一个文件 nlohmann/json.hpp
,引用非常方便。
关于nlohmann/json
的基本使用官网(https://github.com/nlohmann/json)上有比较详细的介绍。这里不再赘述,本文主要是介绍在nlohmann/json
的基本使用之外一些我在使用 nlohmann/json
用到的一些扩展功能和重要但不太被了解的特性。
uri
ben-zen/uri-library是我在网上找到的一个C++11写的URI解析工具,用于URI字符串解析为一个uri
对象,只需要一个头文件uri.hh
,引用非常方便。
在我的项目中我使用uri
而不是普通的std::string
来保存一个URI地址,但是在将uri
对象保存到 nlohmann::json
时遇到了麻烦。
我当然希望如下就能简单的将一个uri对象保存到 nlohmann::json
nlohmann_json_test3.cpp
#include <iostream>
#include "uri/uri.hh"
#include "nlohmann/json.hpp"
int main()
{
nlohmann::json j ;
uri u = "http://baidu.com";
// 保存到json
j["uri"] = u;
// 从json中读取uri对象
uri u2 = j["uri"].get<uri>();
std::cout << "u2:" << u2.to_string() << std::endl;
}
实际上直接这样写是不行的,因为uri
是个第三方类型,并不是nlohmann::json
支持的基本数据类型,所以nlohmann::json
并不知道如何对它进行序列化和反序列化,所以编译就会报错。
如果你对nlohmann/json
略有了解就知道,按照nlohmann/json
官网的基本用法,对于nlohmann/json
不支持的自定义数据类型开发者需要自己实现to_json(BasicJsonType& j, const T& value)
和from_json(const BasicJsonType& j, T& value)
函数,nlohmann/json
才会知道怎么对这个类型进行序列化和反序列化。
那么我自己实现to_json(BasicJsonType& j, const uri& value)
和from_json(const BasicJsonType& j, uri& value)
不就可以了么?
void to_json(BasicJsonType& j, const uri& value)
{
j = value.to_string();
}
void from_json(const BasicJsonType& j, uri& value)
{
value = j.get<std::string>();
}
呵呵,也是不合适的,因为仔细查看源码uri/uri.hh
源码,发现uri
这个对象是没有默认构造函数的。
如果没有默认构造函数,也就无法有构造默认uri
对象,上面to_json(BasicJsonType& j, const uri& value)
的输入参数从何而来呢?
adl_serializer
再仔细看看nlohmann/json
官方文档,发现人家对于这种没有默认构造函数,也非用户自定义类型的第三方数据类型也提供了相应解决方案,就是 adl_serializer
模板类。
我们需要做的就是为uri
实现提供 nlohmann::adl_serializer
模板类的特例化实现:
上面代码nlohmann_json_test3.cpp中如下增加 adl_serializer<uri>
就可以正常编译运行了:
#include <iostream>
#include "uri/uri.hh"
#include "nlohmann/json.hpp"
namespace nlohmann {
// uri 没有默认构造函数,要采用下面的方式提供序列化和反序列化方法,否则json::get<uri>()不能调用
template <>
struct adl_serializer<uri> {
static uri from_json(const json& j) {
// 反序列化
// 从json中获取std::string,调用uri的构造函数
// uri(std::string const &uri_text, scheme_category category = scheme_category::Hierarchical,
// query_argument_separator separator = query_argument_separator::ampersand)
// 将std::string转为uri对象
return{
j.template get<std::string>() };
}
static void to_json(json& j, const uri &u) {
// 序列化
// 调用 uri::to_string()函数将uri对象转为std::string保存到json
j = u.to_string();
}
};
}
int main()
{
nlohmann::json j ;
uri u = "http://baidu.com";
// 保存到json
j["uri"] = u;
// 从json中读取uri对象
uri u2 = j["uri"].get<uri>();
std::cout << "u2:" << u2.to_string() << std::endl;
}