企业建网站平台,设计英语,平顶山专业做网站公司,网站信息平台建设方案JSON指针和JSON补丁
该库支持JSON指针(RFC6901)来处理结构化值.而,JSONPatch(RFC6902)允许描述两个JSON值之间的差异,有效地允许Unix已知的补丁和差异操作.
//一个JSON值
json j_original R({baz: [one, two, three]…JSON指针和JSON补丁
该库支持JSON指针(RFC6901)来处理结构化值.而,JSONPatch(RFC6902)允许描述两个JSON值之间的差异,有效地允许Unix已知的补丁和差异操作.
//一个JSON值
json j_original R({baz: [one, two, three],foo: bar
})_json;
//使用JSON指针访问成员(RFC6901)
j_original[/baz/1_json_pointer];
//两个一个JSON修补程序(RFC6902)
json j_patch R([{ op: replace, path: /baz, value: boo },{ op: add, path: /hello, value: [world] },{ op: remove, path: /foo}
])_json;
//应用修补程序
json j_result j_original.patch(j_patch);
//{baz:boo,hello:[world]}从两个JSON值计算一个JSON补丁json::diff(j_result, j_original);//[{op:replace,path:/baz,value:[one,two,three]},{op:remove,path:/hello},{op:add,path:/foo,value:bar}]
JSON合并补丁
使用与正在修改文档类似语法来描述更改.
//一个JSON值
json j_document R({a: b,c: {d: e,f: g}
})_json;
//一个补丁
json j_patch R({a:z,c: {f: null}
})_json;
//应用修补程序
j_document.merge_patch(j_patch);
//{a:z,c:{d:e}}隐式转换
可隐式转换支持类型为JSON值. 建议不要使用JSON值的隐式转换.不推荐原因,你可通过在包含json.hpp头文件之前定义JSON_USE_IMPLICIT_CONVERSIONS为0来关闭隐式转换. 使用CMake时,还可通过设置选项JSON_ImplicitConversions为OFF来实现此目的.
//串
std::string s1 Hello, world!;
json js s1;
auto s2 js.template getstd::string();
//不推荐
std::string s3 js;
std::string s4;
s4 js;
//布尔值
bool b1 true;
json jb b1;
auto b2 jb.template getbool();
//不推荐
bool b3 jb;
bool b4;
b4 jb;
//数字
int i 42;
json jn i;
auto f jn.template getdouble();
//不推荐
double f2 jb;
double f3;
f3 jb;
//等.注意,char类型不会自动转换为JSON串,而是转换为整数.必须显式指定转换串:
char ch A; //ASCII值65存储整数65存储串A
json j_default ch; //
json j_string std::string(1, ch); //任意类型转换
每个类型都可在JSON中序化,而不仅是STL容器和标量类型.一般,你会按这些思路干活:
namespace ns {//对人建模的简单结构struct person {std::string name;std::string address;int age;};
}
ns::person p {Ned Flanders, 744 Evergreen Terrace, 60};
//转换为JSON:复制每个值到JSON对象中
json j;
j[name] p.name;
j[address] p.address;
j[age] p.age;
//...从JSON转换:从JSON对象复制每个值
ns::person p {j[name].template getstd::string(),j[address].template getstd::string(),j[age].template getint()
};它有效,但太多样板,幸好,有一个更好的方法:
//创建人员
ns::person p {Ned Flanders, 744 Evergreen Terrace, 60};
//转换:人-JSON
json j p;
std::cout j std::endl;//{地址:744常青露台,年龄:60,名:内德.弗兰德斯}转换:json-人
auto p2 j.template getns::person();
//就是这样
assert(p p2);
Basic usage只需要提供两个函数:
using json nlohmann::json;
namespace ns {void to_json(json j, const person p) {j json{{name, p.name}, {address, p.address}, {age, p.age}};}void from_json(const json j, person p) {j.at(name).get_to(p.name);j.at(address).get_to(p.address);j.at(age).get_to(p.age);}
} //名字空间ns就这样!用你的类型调用json构造器时,调用自动你的自定义to_json方法.同样,当调用模板getyour_type()或get_to(your_type)时,调用from_json方法.
重要:
1,这些方法必须在类型的名字空间(可为全局名字空间)中,否则库找无法到它们(此例中,在定义了person的ns名字空间中). 2,使用templategetyour_type()时,your_type必须是DefaultConstructible. 3,在函数from_json中,使用函数at()而不是操作符[]访问对象值.如果键不存在,则at会触发可处理的异常,而operator[]表现出未定义行为. 4,你不需要为STL类型(如std::vector)添加序化程序或反序化程序:库已实现了.
使用宏简化你的生活
如果你只想序化/反序化某些结构,则to_json/from_json函数可是很多样板. 有两个宏可让你的生活更轻松,只要你(1)想用JSON对象作为序化,并且(2)想用成员变量名作为该对象中的对象键: NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name,member1,member2,...)创建在要为其代码的类/结构的名字空间默认义. NLOHMANN_DEFINE_TYPE_INTRUSIVE(name,member1,member2,...)创建在要为其代码的类/结构中定义.此宏还可访问私有成员. 在这两个宏中,第一个参数是类/结构名,其余所有参数都是命名成员.
示例
可用以下命令创建上述人员结构的to_json/from_json函数:
namespace ns {NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}下面是需要NLOHMANN_DEFINE_TYPE_INTRUSIVE的私有成员的示例:
namespace ns {class address {private:std::string street;int housenumber;int postcode;public:NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)};
}转换第三方类型
首先,看看转换机制工作原理:
该库使用JSON序化程序转换类型为json.nlohmann::json的默认序化程序是nlohmann::adl_serializer(ADL表示参数依赖查找).是这样实现的(简化):
template typename T
struct adl_serializer {static void to_json(json j, const T value) {//调用T名字空间中的to_json方法}static void from_json(const json j, T value) {//一样的,但使用from_json方法}
};当你控制类型的名字空间时,此序化程序工作正常.但是,boost::optional或std::filesystem::path(C17)劫持boost名字空间是非常糟糕的,向std添加模板特化以外的内容是非法的.
要解决,你需要在nlohmann名字空间中添加adl_serializer的特化,下面是一例:
//部分特化(完全特化也有效)
namespace nlohmann {template typename Tstruct adl_serializerboost::optionalT {static void to_json(json j, const boost::optionalT opt) {if (opt boost::none) {j nullptr;} else {j *opt; //这调用adl_serializerT::to_json它找在T的名字空间中到to_json的自由函数!}}static void from_json(const json j, boost::optionalT opt) {if (j.is_null()) {opt boost::none;} else {opt j.template getT(); //与上述相同,但使用adl_serializerT::from_json}}};
}如何默认get()来取不可构造/不可复制类型
有一个方法,如果你的类型是MoveConstructible.你还需要特化adl_serializer,但有特殊的from_json重载:
struct move_only_type {move_only_type() delete;move_only_type(int ii): i(ii) {}move_only_type(const move_only_type) delete;move_only_type(move_only_type) default;int i;
};
namespace nlohmann {template struct adl_serializermove_only_type {//注意:返回类型不再是void,该方法只接受一个参数static move_only_type from_json(const json j) {return {j.template getint()};}//这就是问题所在!你必须提供to_json方法!否则,你转换无法将move_only_type为json,因为你完全特化adl_serializer该类型.static void to_json(json j, move_only_type t) {j t.i;}};
}可编写自己的序化程序吗(高级使用)
是的.你可能想看看测试包中的unit-udt.cpp,以查看一些示例. 如果编写自己的序化程序,则需要执行以下几项操作: 使用与nlohmann::JSON不同的basic_json别名(basic_json的最后模板参数是JSONSerializer) 在所有to_json/from_json方法中使用basic_json别名(或模板参数) 当你需要ADL时,请使用nlohmann::to_json和nlohmann::from_json 下面是一例,无需简化,它仅接受大小为32的类型,并使用ADL.
//如果不需要对T编译时检查,则应使用void作为第二个模板参数
templatetypename T, typename SFINAE typename std::enable_ifsizeof(T) 32::type
struct less_than_32_serializer {template typename BasicJsonTypestatic void to_json(BasicJsonType j, T value) {//想使用ADL,并调用正确的to_json重载此方法由adl_serializer调用,这就是神奇的地方using nlohmann::to_json; //to_json(j, value);}template typename BasicJsonTypestatic void from_json(const BasicJsonType j, T value) {//这里也是一样using nlohmann::from_json;from_json(j, value);}
};重新实现序化程序时要非常小心,如果不注意,可能会栈溢出:
template typename T, void
struct bad_serializer
{template typename BasicJsonTypestatic void to_json(BasicJsonType j, const T value) {//这调用BasicJsonType::json_serializerT::to_json(j,value);如果BasicJsonType::json_serializerbad_serializer...哎呀!j value;}template typename BasicJsonTypestatic void to_json(const BasicJsonType j, T value) {//这调用BasicJsonType::json_serializerT::from_json(j,value);如果BasicJsonType::json_serializerbad_serializer...哎呀!哎呀!value j.template getT(); //}
};特化枚举转换
默认,枚举值作为整数序化为JSON.有时候,会导致意外行为.如果在数据序化为JSON后修改或重排枚举,则稍后反序化的JSON数据可能未定义或枚举值与最初期望不同.
可更精确地指定给定枚举,如何映射到JSON及从JSON映射,如下:
//示例枚举类型声明
enum TaskState {TS_STOPPED,TS_RUNNING,TS_COMPLETED,TS_INVALID-1,
};
//映射任务状态值作为串到JSON
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {{TS_INVALID, nullptr},{TS_STOPPED, stopped},{TS_RUNNING, running},{TS_COMPLETED, completed},
})NLOHMANN_JSON_SERIALIZE_ENUM()宏为TaskState类型声明一组to_json()/from_json()函数,同时避免重复和样板序化代码. 用法:
//枚举到串JSON
json j TS_STOPPED;
assert(j stopped);
//JSON串到枚举
json j3 running;
assert(j3.template getTaskState() TS_RUNNING);
//枚举的未定义JSON值(其中上面的第一个映射项是默认值)
json jPi 3.14;
assert(jPi.template getTaskState() TS_INVALID );与上面的任意类型转换一样, NLOHMANN_JSON_SERIALIZE_ENUM()必须在枚举类型的名字空间(可是全局名字空间)中声明,否则库找无法到它,它默认为整数序化. 它必须在你使用转换的地方可用(如,必须包含正确的头文件).
其他要点:
使用模板getENUM_TYPE()时,未定义的JSON值默认为映射中指定的第一对.请仔细选择此默认对. 如果在映射中多次指定枚举或JSON值,则在转换为JSON或从JSON转换时,返回映射顶部的第一个匹配项. 二进制格式(BSON,CBOR,MessagePack,UBJSON和BJData) 虽然JSON是一个无处不在的数据格式,但它不是一个非常紧凑的格式,适合数据交换,如通过网络.因此,该库支持BSON(二进制JSON),CBOR(简洁二进制对象表示),MessagePack,UBJSON(通用二进制JSON规范)和BJData(二进制JData),以有效地编码JSON值为字节向量并解码此类向量.
//创建JSON值
json j R({compact: true, schema: 0})_json;
//序化为BSON
std::vectorstd::uint8_t v_bson json::to_bson(j);//0x1B,0x00,0x00,0x00,0x08,0x63,0x6F,0x6D,0x70,0x61,0x63,0x74,0x00,0x01,0x10,0x73,0x63,0x68,0x65,0x6D,0x61,0x00,0x00,0x00,0x00,0x00,0x00往返
json j_from_bson json::from_bson(v_bson);
//序化为CBOR
std::vectorstd::uint8_t v_cbor json::to_cbor(j);//0xA2,0x67,0x63,0x6F,0x6D,0x70,0x61,0x63,0x74,0xF5,0x66,0x73,0x63,0x68,0x65,0x6D,0x61,0x00往返
json j_from_cbor json::from_cbor(v_cbor);
//序化为消息包
std::vectorstd::uint8_t v_msgpack json::to_msgpack(j);//0x82,0xA7,0x63,0x6F,0x6D,0x70,0x61,0x63,0x74,0xC3,0xA6,0x73,0x63,0x68,0x65,0x6D,0x61,0x00往返
json j_from_msgpack json::from_msgpack(v_msgpack);
//序化为UBJSON
std::vectorstd::uint8_t v_ubjson json::to_ubjson(j);//0x7B,0x69,0x07,0x63,0x6F,0x6D,0x70,0x61,0x63,0x74,0x54,0x69,0x06,0x73,0x63,0x68,0x65,0x6D,0x61,0x69,0x000x7D往返
json j_from_ubjson json::from_ubjson(v_ubjson);该库还支持来自BSON,CBOR(字节串)和MessagePack(bin,ext,fixext)的二进制类型.默认,它们存储为std::vectorstd::uint8_t,以便在库外部处理.
//有有效负载0xCAFE的CBOR字节串
std::vectorstd::uint8_t v {0x42, 0xCA, 0xFE};
//读取值
json j json::from_cbor(v);
//JSON值的类型为binarytrue取对存储的二进制值的引用
j.is_binary(); //
//
auto binary j.get_binary();//二进制值没有子类型(CBOR没有二进制子类型)错误访问std::vectorstd::uint8_t成员函数20xCA0xFE设置子类型为0x10binary.has_subtype(); //
//
binary.size(); //
binary[0]; //
binary[1]; //
//
binary.set_subtype(0x10);
//序化为MessagePack0xD5(fixext2),0x10,0xCA0xFE
auto cbor json::to_msgpack(j); //