目录

Boost的1.75版本新库

12月11日,Boost社区发布了1.75版本,相比较于原定的12月9日,推迟了两天。这次更新带来了三个新库:JSONLEAFPFR

其中JSON自然是json格式的解析库,来自Vinnie FalcoKrystian Stasiowski

LEAF是一个轻量的异常处理库,来自Emil Dotchevski

PFR是一个基础的反射库,不需要用户使用宏和样版代码(由于还未仔细阅读此库,可能翻译有一些不准确),来自Antony Polukhin

JSON库简介

其实在之前,Boost就已经有能够解析JSON的库了,名字叫做Boost.PropertyTreeBoost.PropertyTree不仅仅能够解析JSON,还能解析XMLINIINFO格式的文件。但是由于成文较早及需要兼容其他的数据格式,相比较于其他的C++解析库,其显得比较笨重,使用的时候有很多的不方便。

Boost.JSON相对于Boost.PropertyTree来所,其只能支持JSON格式的解析,但是其使用方法更为简便,直接。华丽胡哨的东西也更多了。

JSON的简单使用

有两种方法使用Boost.JSON,一种是动态链接库,此时引入头文件boost/json.hpp,同时链接对应的动态库;第二种是使用header only模式,此时只需要引入头文件boost/json/src.hpp即可。两种方法各有优缺点,酌情使用。

编码

最通用的方法

我们要构造的json如下,包含了各种类型。

  1. {
  2. "a_string" : "test_string",
  3. "a_number" : 123,
  4. "a_null" : null,
  5. "a_array" : [1, "2", {"123" : "123"}],
  6. "a_object" : {
  7. "a_name": "a_data"
  8. },
  9. "a_bool" : true
  10. }

构造的方法也很简单:

  1. boost::json::object val;
  2. val["a_string"] = "test_string";
  3. val["a_number"] = 123;
  4. val["a_null"] = nullptr;
  5. val["a_array"] = {
  6. 1, "2", boost::json::object({{"123", "123"}})
  7. };
  8. val["a_object"].emplace_object()["a_name"] = "a_data";
  9. val["a_bool"] = true;

首先定义一个object,然后往里面塞东西就好。其中有一个emplace_object这个比较重要,后面会提到。

结果:

使用std::initializer_list

Boost.JSON支持使用std::initializer_list来构造自己的对象。所以也可以这样使用:

  1. boost::json::value val2 = {
  2. {"a_string", "test_string"},
  3. {"a_number", 123},
  4. {"a_null", nullptr},
  5. {"a_array", {1, "2", {{"123", "123"}}}},
  6. {"a_object", {{"a_name", "a_data"}}},
  7. {"a_bool", true}
  8. };

结果如下:

json对象的输出

生成了json对象以后,就可以使用serialize对对象进行序列化了。

  1. std::cout << boost::json::serialize(val2) << std::endl;

结果如前两图。

除了直接把整个对象直接输出,Boost.JSON还支持分部分进行流输出,这种方法在数据量较大时,可以有效降低内存占用。

  1. boost::json::serializer ser;
  2. ser.reset(&val);
  3. char temp_buff[6];
  4. while (!ser.done()) {
  5. std::memset(temp_buff, 0, sizeof(char) * 6);
  6. ser.read(temp_buff, 5);
  7. std::cout << temp_buff << std::endl;
  8. }

结果:

如果缓存变量是数组,还可以直接使用ser.read(temp_buff)

需要注意的是,ser.read并不会默认在字符串末尾加\0,所以如果需要直接输出,在输入时对缓存置0,同时为\0空余一个字符。

也可以直接使用输出的boost::string_view

两种对比

这两种方法对比的话,各有各的优点。前一种方法比较时候边运行边生成,后者适合一开始就需要直接生成的情形,而且相对来说,后者显得比较的直观。

但是第二种方法有一个容易出现问题的地方。比如以下两个json对象:

  1. // json1
  2. [["data", "value"]]
  3. //json2
  4. {"data": "value"}

如果使用第二种方法进行构建,如果一不小心的话,就有可能写出一样的代码:

  1. boost::json::value confused_json1 = {{"data", "value"}};
  2. boost::json::value confused_json2 = {{"data", "value"}};
  3. std::cout << "confused_json1: " << boost::json::serialize(confused_json1) << std::endl;
  4. std::cout << "confused_json2: " << boost::json::serialize(confused_json2) << std::endl;

而得到的结果,自然也是一样的:

如果需要消除这一歧义,可以直接使用Boost.JSON提供的对象构建有可能产生歧义的地方:

  1. boost::json::value no_confused_json1 = {boost::json::array({"data", "value"})};
  2. boost::json::value no_confused_json2 = boost::json::object({{"data", "value"}});

结果为:

解码

JSON的解码也比较简单。

简单的解码

  1. auto decode_val = boost::json::parse("{\"123\": [1, 2, 3]}");

直接使用boost::json::parse,输入相应的字符串就行了。

增加错误处理

  1. boost::json::error_code ec;
  2. boost::json::parse("{\"123\": [1, 2, 3]}", ec);
  3. std::cout << ec.message() << std::endl;
  4. boost::json::parse("{\"123\": [1, 2, 3}", ec);
  5. std::cout << ec.message() << std::endl;

结果:

非严格模式

在这个模式下,Boost.JSON可以选择性的对一些不那么严重的错误进行忽略。

  1. unsigned char buf[4096];
  2. boost::json::static_resource mr(buf);
  3. boost::json::parse_options opt;
  4. opt.allow_comments = true; // 允许注释
  5. opt.allow_trailing_commas = true; // 允许最后的逗号
  6. boost::json::parse("[1, 2, 3, ] // comment test", ec, &mr, opt);
  7. std::cout << ec.message() << std::endl;
  8. boost::json::parse("[1, 2, 3, ] // comment test", ec, &mr);
  9. std::cout << ec.message() << std::endl;

结果如下:

可以看到,增加了选项的解释器成功的解析了结果。

流输入

和输出一样,输入也有流模式。

  1. boost::json::stream_parser p;
  2. p.reset();
  3. p.write("[1, 2,");
  4. p.write("3]");
  5. p.finish();
  6. std::cout << boost::json::serialize(p.release()) << std::endl;

结果:

进阶应用

对象序列化

有时候我们需要将对象转换为JSON,对对象进行序列化然后保存。Boost.JSON提供了一个非常简单的方法,能够使我们非常简单的将一个我们自己定义的对象转化为JSON对象。

我们只需要在需要序列化的类的命名空间中,定义一个重载函数tag_invoke。注意,是类所在的命名空间,而不是在类里面定义。

使用示例:

  1. namespace MyNameSpace {
  2. class MyClass {
  3. public:
  4. int a;
  5. int b;
  6. MyClass (int a = 0, int b = 1):
  7. a(a), b(b) {}
  8. };
  9. void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, MyClass const &c) {
  10. auto & jo = jv.emplace_object();
  11. jo["a"] = c.a;
  12. jo["b"] = c.b;
  13. }
  14. }

其中,boost::json::value_from_tag是作为标签存在的,方便Boost.JSON分辨序列化函数的。jv是输出的JSON对象,c是输入的对象。

  1. boost::json::value_from(MyObj)

使用的话,直接调用value_from函数即可。

结果:

序列化还有一个好处就是,可以在使用std::initializer_list初始化JSON对象时,直接使用自定义对象。譬如:

  1. boost::json::value val = {MyObj};

注意,这里的val是一个数组,里面包含了一个对象MyObj

反序列化

有序列化,自然就会有反序列化。操作和序列化的方法差不多,也是定义一个tag_invoke函数,不过其参数并不一致。

  1. MyClass tag_invoke(boost::json::value_to_tag<MyClass>, boost::json::value const &jv) {
  2. auto &jo = jv.as_object();
  3. return MyClass(jo.at("a").as_int64(), jo.at("b").as_int64());
  4. }

需要注意的是,由于传入的jv是被const修饰的,所以不能类似于jv["a"]使用。

使用也和上面的类似,提供了一个value_to<>模板函数。

  1. auto MyObj = boost::json::value_to<MyNameSpace::MyClass>(vj);

无论是序列化还是反序列化,对于标准库中的容器,Boost.JSON都可以直接使用。

Boost.JSON的类型

array

数组类型,用于储存JSON中的数组。实际使用的时候类似于std::vector<boost::json::value>,差异极小。

object

对象类型,用于储存JSON中的对象。实际使用时类似于std::map<std::string, boost::json::value>,但是相对来说,它们之间的差异较大。

string

字符串类型,用于储存JSON中的字符串。实际使用时和std::basic_string类似,不过其只支持UTF-8编码,如果需要支持其他编码,在解码时候需要修改option中相应的选项。

value

可以储存任意类型,也可以变换为各种类型。其中有一些特色的函数比如as_objectget_arrayemplace_int64之类的。它们的工作都类似,将boost::json::value对象转化为对应的类型。但是他们之间也有一定的区别。

  • as_xxx 返回一个引用,如果类型不符合,会抛出异常
  • get_xxx 返回一个引用,不检查类型,如果类型不符合,可能导致未定义行为
  • is_xxx 判断是否为xxx类型
  • if_xxx 返回指针,如果类型不匹配则返回nullptr
  • emplace_xxx 返回一个引用,可以直接改变其类型和内容。

总结

大致的使用方法就这些了。如果还要更进一步的话,就是涉及到其内存管理了。

纵观整个库的话,感觉其对于模板的使用相当克制,能不使用就不使用,这在一定程度上也提高了编译的速度。

引用

  1. https://www.boost.org/doc/libs/1_75_0/libs/json/doc/html/index.html

博客原文:https://www.cnblogs.com/ink19/p/Boost_JSON.html

Boost.JSON Boost的JSON解析库(1.75首发)的更多相关文章

  1. C++的Json解析库:jsoncpp和boost

    C++的Json解析库:jsoncpp和boost - hzyong_c的专栏 - 博客频道 - CSDN.NET C++的Json解析库:jsoncpp和boost 分类: 网络编程 开源库 201 ...

  2. C++的Json解析库:jsoncpp和boost(转)

    原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...

  3. [转]C++的Json解析库:jsoncpp和boost

    JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...

  4. Tomjson - 一个"短小精悍"的 json 解析库

    Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...

  5. fastjson是阿里巴巴的开源JSON解析库

    fastjson的API十分简洁. String text = JSON.toJSONString(obj); //序列化 VO vo = JSON.parseObject("{...}&q ...

  6. iOS开源JSON解析库MJExtension

    iOS中JSON与NSObject互转有两种方式:1.iOS自带类NSJSONSerialization 2.第三方开源库SBJSON.JSONKit.MJExtension.项目中一直用MJExte ...

  7. python 中的json解析库

    当一个json 数据很大的时候.load起来是很耗时的.python中常见的json解析库有cjson,simplesjson,json, 初步比较了一下, 对于loads来讲 simplejson ...

  8. Tomjson - json 解析库

    Tomjson - 一个"短小精悍"的 json 解析库 Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把 ...

  9. 开源解析库 - JSON

    Json及其实现 JSON作为一种轻量级的数据交换格式,多被用于跨语言通信(比如CPP与PHP之间的数据交互). 至于何为JSON,其详细解释参考 官网. 既然是一种格式,那便必然有相应的编码实现.在 ...

随机推荐

  1. 【ACwing 98】分形之城——分形

    (题面来自ACwing) 城市的规划在城市建设中是个大问题. 不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现. 而这座名为 Fractal 的城市设想了 ...

  2. [GIT]获取git最新的tag

    背景 公司前端项目在Jenkins中打包,每次打包需要将新tag回推到仓库中.但是打包失败后如果不删除tag的话下次打包就会失败,需要手动删除,所以在Jenkinsfile中就需要在打包失败时自动删除 ...

  3. shardingsphere与分布式事务

    rt https://blog.csdn.net/l1028386804/article/details/79769043 https://blog.csdn.net/qq_20387013/arti ...

  4. java导出excel并且压缩成zip上传到oss,并下载,使用字节流去存储,不用文件流保存文件到本地

    最近项目上要求实现导出excel并根据条数做分割,然后将分割后的多个excel打包成压缩包上传到oss服务器上,然后提供下载方法,具体代码如下:这里只展示部分代码,获取数据的代码就不展示了 ByteA ...

  5. B. Irreducible Anagrams【CF 1290B】

    思路: 设tx为t类别字符的个数. ①对于长度小于2的t明显是"YES"②对于字符类别只有1个的t明显是"YES"③对于字符类别有2个的t,如左上图:如果str ...

  6. 微信支付万亿日志在Hermes中的实践

    导语 | 微信支付日志系统利用 Hermes 来实现日志的全文检索功能,自从接入以来,日志量持续增长.目前单日入库日志量已经突破万亿级,单集群日入库规模也已经突破了万亿,存储规模达 PB 级.本文将介 ...

  7. day3(使用axios实现登录成功)

    1.创建一个login.vue页面 1.1写页面components/Login.vue 在 src/components 下创建 Login.vue 页面 <template>   &l ...

  8. 区块链学习7:超级账本项目Hyperledger与Fabric以及二者的关系

    ☞ ░ 前往老猿Python博文目录 ░ 一.超级账本(hyperledger) 超级账本(hyperledger)是Linux基金会于2015年发起的推进区块链数字技术和交易验证的开源项目,成员包括 ...

  9. Python中字符串使用单引号、双引号标识和三引号标识,什么是三引号?什么情况下用哪种标识?

    一.三引号是指三个单引号或者三个双引号: 二.Python中字符串如果以单引号.双引号标识和三引号标识开头,则字符串结尾也必须是对应的标识,不能变更: 三.三者的异同: 1.三者都是字符串,大部分情况 ...

  10. 第14.11节 Python中使用BeautifulSoup解析http报文:使用查找方法快速定位内容

    一. 引言 在<第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问>介绍了BeautifulSoup对象的主要属性,通过这些属性可以访 ...