c++ boost::json

news2024/11/16 5:31:13

Boost社区12月11日发布了1.75版本,在之前,​​Boost使用Boost.PropertyTree解析​​JSON​​​,​​XML​​​,​​INI​​​和​​INFO​​​格式的文件。但是由于成文较早及需要兼容其他的数据格式,相比较于其他的​​C++​​解析库,使用时不方便。

​Boost.JSON​​​相对于​​Boost.PropertyTree​​​来所,其只能支持​​JSON​​格式的解析,但是其使用方法更为简便,直接。

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

​数据类型

array

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

object

object是JSON键值对的容器,对象类型,用于储存​​JSON​​​中的对象。实际使用时类似于​​std::map<std::string, boost::json::value>​​,但是相对来说,它们之间的差异较大。定义在<boost/json/object.hpp>

项目Value
at(key)获取指定Key对应的元素的引用(不存在时会抛出out_of_range异常)
begin/end获取iterator
capacity容量
cbegin/cend获取const iterator
clearErase all elements.
contains(key)判断Key是否存在
count(key)返回Key的数量
emplaceConstruct an element in-place.
empty是否为空
erase(it/key)根据key或iterator移除元素
find(key)返回指定key的iterator或end()。
if_contains(key)返回key对应value的指针,或null(不存在时)。
insert插入元素
insert_or_assign插入或赋值(若key已存在)
operator=Copy assignment.Move assignment.Assignment.
operator[]存在返回对应引用,若不存在则插入null value,并返回
reserve增加容量(若指定值小于现有容量,则什么也不做)
size大小
swapSwap two objects.
max_size静态成员,返回object能保存元素的最大数量。

string

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

value

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

构造json

{
    "a_string" : "test_string",
    "a_number" : 123,
    "a_null"   : null,
    "a_array"  : [1, "2", {"123" : "123"}],
    "a_object" : {
        "a_name": "a_data"
    },
    "a_bool"   : true
}

构造的方法也很简单:定义一个object,然后设定各个value即可

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

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

boost::json::value val2 = {
    {"a_string", "test_string"},
    {"a_number", 123},
    {"a_null", nullptr},
    {"a_array", {1, "2", {{"123", "123"}}}},
    {"a_object", {{"a_name", "a_data"}}},
    {"a_bool", true}
};

但是使用initializer_list构造时,有时很难区分是数组还是对象,可以明确指定

// 构造[["data", "value"]]
boost::json::value jsonAry = {boost::json::array({"data", "value"})};

// 构造{"data": "value"}
boost::json::value jsonObj = boost::json::object({{"data", "value"}});

序列化

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

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

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

boost::json::serializer ser;
ser.reset(&val);

char temp_buff[6];
while (!ser.done()) {
    std::memset(temp_buff, 0, sizeof(char) * 6);
    ser.read(temp_buff, 5);
    std::cout << temp_buff << std::endl;
}

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

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

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

对象序列化

对象转换为JSON,Boost.JSON提供了一个非常简单的方法:只需要在需要序列化的类的命名空间中,定义一个重载函数tag_invoke(是类所在的命名空间,而不是在类里面定义),然后通过value_from即可方便地序列化对象了:

namespace NSJsonTest {
	class MyClass {
	public:
		int a;
		int b;
		MyClass (int a = 0, int b = 1):
		a(a), b(b) {}
	};

	void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, MyClass const &c) {
		auto & jo = jv.emplace_object();
		jo["a"] = c.a;
		jo["b"] = c.b;
	}
	
	MyClass myObj;
	auto jv = boost::json::value_from(myObj)
}

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

boost::json::value_from(MyObj)

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

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

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

反序列化

使用​​boost::json::parse​​

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

增加错误处理

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

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

对象反序列化

与对象序列化对应的是对象反序列化;也是在命名空间中定义个tag_invoke函数,然后即可通过value_to把JSON对象反序列化为类对象了:

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

// jv为前面序列化时的对象
auto myObj = boost::json::value_to<MyClass>(jv);

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

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

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

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

流输入

通过stream_parser可以流的方式读入要解析的字符串

boost::json::stream_parser p;
p.reset();

p.write("[1, 2,");
p.write("3]");
p.finish();

std::cout << boost::json::serialize(p.release()) << std::endl;

示例

json文件:
在这里插入图片描述

#include <boost/json.hpp>
#include <boost/json/src.hpp>
#include <iostream>
#include <iterator>
#include <fstream>
namespace json = boost::json;

struct Rec {
    int64_t number;
    std::string string;

    friend Rec tag_invoke(json::value_to_tag<Rec>, json::value const& v) {
        auto& o = v.as_object();
        return {
                o.at("number").as_int64(),
                boost::json::value_to<std::string>(o.at("string")),
        };
    }

    friend void tag_invoke(json::value_from_tag, json::value& v, Rec const& rec)
    {
        v = json::object{
                {"number", rec.number},
                {"string", rec.string},
        };
    }
};

int main() {
    std::ifstream ifs("../input.json");
    std::string   input(std::istreambuf_iterator<char>(ifs), {});

    using Recs = std::vector<Rec>;
    Recs recs  = boost::json::value_to<std::vector<Rec>>(json::parse(input));

    for (auto& [n, s] : recs) {
        std::cout << "Rec { " << n << ", " << std::quoted(s) << " }\n";

        // some frivolous changes:
        n *= 2;
        reverse(begin(s), end(s));
    }

    std::cout << "Modified json: " << json::value_from(recs) << "\n";
}

参考
Boost.JSON Boost的JSON解析库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/947697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么自学嵌入式?

嵌入式开发&#xff0c;简直就是一个无穷无尽的知识海洋&#xff01;你永远都学不够&#xff01;当然啦&#xff0c;这并不意味着你得花个三五年才能掌握。如果你只是想找嵌入式开发的工作&#xff0c;其实只需花三五个月有针对性地学习&#xff0c;就可以完全hold住。本文就给…

MybatisPlus核心功能

文章目录 一、前言二、核心功能2.1、条件构造器2.1.1、基础查询条件2.1.2、复杂查询条件2.1.3、动态查询条件2.1.4、查询结果排序2.1.5、执行查询 2.2、主键策略2.2.1、自增主键策略2.2.2、UUID 主键策略2.2.3、雪花算法主键策略2.2.4、自定义 ID 生成策略 三、总结 一、前言 …

学习node之——如何在项目中使用MySQL、前后端的身份认证

上一篇文章只写了一丢丢&#xff0c;这篇才是正片&#xff0c;look look look 一、使用mysql模块操作数据库 1、查询数据 这里连接数据库的用户和密码都是我们在安装mysql时配置的密码。每个人的users表格里面数据不同&#xff0c;结果也会不一样哟&#xff01; // 导入mys…

使用Spring Boot和Kafka实现消息发送和订阅

文章目录 一&#xff0c;新建Spring Boot1&#xff0c;Maven配置2&#xff0c;无法识别为SpringBoot项目3&#xff0c;无效的源发行版4&#xff0c;无法访问SpringApplication5&#xff0c;运行直接Finish6&#xff0c;服务运行成功 二&#xff0c;安装启动Kafka1&#xff0c;下…

从零开始学习 Java:简单易懂的入门指南之查找算法及排序算法(二十)

查找算法及排序算法 常见的七种查找算法&#xff1a;1. 基本查找2. 二分查找3. 插值查找4. 斐波那契查找5. 分块查找6. 哈希查找7. 树表查找 四种排序算法&#xff1a;1. 冒泡排序1.1 算法步骤1.2 动图演示1.3 代码示例 2. 选择排序2.1 算法步骤2.2 动图演示 3. 插入排序3.1 算…

基于ETLCloud的自定义规则调用第三方jar包实现繁体中文转为简体中文

背景 前面曾体验过通过零代码、可视化、拖拉拽的方式快速完成了从 MySQL 到 ClickHouse 的数据迁移&#xff0c;但是在实际生产环境&#xff0c;我们在迁移到目标库之前还需要做一些过滤和转换工作&#xff1b;比如&#xff0c;在诗词数据迁移后&#xff0c;发现原来 MySQL 中…

部署问题集合(二十二)Linux设置定时任务,并设置系统时间

前言 因为项目中经常用到定时任务&#xff0c;特此总结记录一下 步骤 大部分虚拟机创建后就自带定时服务&#xff0c;直接用命令就好编辑定时任务&#xff1a;crontab -e&#xff0c;在该文件下添加如下内容开机自启&#xff1a;reboot /home/autoRun.sh定时执行&#xff1a…

基于java+springboot+vue的交流互动系统-lw

​ 系统介绍&#xff1a; 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多企业的之中&#xff0c;随之就产生了“交流互动系统”&#xff0c;这样就让交流互动系统更加方便简单。 对于本交流互动系统的设计来说&a…

字节一面:你能讲一下跨域吗

前言 最近博主在字节面试中遇到这样一个面试题&#xff0c;这个问题也是前端面试的高频问题&#xff0c;作为一名前端开发工程师&#xff0c;我们日常开发中与后端联调时一定会遇到跨域的问题&#xff0c;只有处理好了跨域才能够与后端交互完成需求&#xff0c;所以深入学习跨域…

STM32F103驱动oled显示屏

STM32F103驱动oled显示屏 一.了解oled显示屏二.IIC协议驱动oled显示屏2.1 oled.c2.2 oled.h 三.效果展示 一.了解oled显示屏 oled显示屏和其他显示屏类似&#xff0c;不过他只有0.96英寸&#xff0c;屏幕较小&#xff0c;但是使用起来比较方便。有二种驱动方式&#xff0c;分别…

Python学习笔记——从面试题出发学习Python

Python学习笔记——从面试题出发学习Python Python学习笔记——从面试题出发学习Python1. 可变数据类型与不可变数据类型&#xff0c;深拷贝与浅拷贝&#xff0c;函数参数的传递机制1.1 变量与对象1.2 可变数据类型与不可变数据类型1.3 深拷贝与浅拷贝1.4 函数参数的传递机制1.…

SIP对讲求助终端,带功放输出

SV-7011TP SIP对讲求助终端&#xff0c;带功放输出 一、描述 网络对讲终端SV-7011TP&#xff0c;SV-7011TP能处理tcp/ip网络音频流&#xff0c;并驱动扬声器进行播音的终端&#xff0c;主要用于公共数字广播&#xff0c;媒体教学&#xff0c;报警等需要数字音频的领域。 SV-…

LinearAlgebraMIT_12_Graph

x.1 用Incidence matrix关联矩阵表示图 矩阵将图的关系数学表达了出来&#xff0c;如下&#xff0c; x.2 图的性质 如果一个数据结构是图&#xff0c;则意味着其组成关联矩阵的向量组是线性相关的&#xff0c;如果数据结构是树则线性无关。 通过对图的了解&#xff0c;我们可…

激活函数总结(二十四):激活函数补充(SquaredReLU、ModReLU)

激活函数总结&#xff08;二十四&#xff09;&#xff1a;激活函数补充 1 引言2 激活函数2.1 SquaredReLU激活函数2.2 ModReLU激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Leaky ReLU、PReLU、Swish、ELU、SELU、GELU、Soft…

【iOS】折叠cell

文章目录 前言一、实现效果二、折叠cell的实现原理三、实现折叠cell的高度变化四、实现选中点击的单元格总结 前言 在暑假的3GShare中用到了折叠cell控件&#xff0c;特此总结博客记录 一、实现效果 二、折叠cell的实现原理 首先我们需要知道ScrollView的是TableView的父类&a…

c++11 标准模板(STL)(std::basic_ostringstream)(四)

定义于头文件 <sstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_ostringstream;(C11 前)template< class CharT, class Traits std::char_traits<CharT>, class Allocator std::allo…

Anaconda Prompt输入jupyter lab无反应

问题&#xff1a;Anaconda Prompt界面输入指令无反应 原因&#xff1a;公司电脑勒索病毒防御工具阻止了进程 解决&#xff1a;找到黑名单恢复进程

Modahub魔搭社区:星环向量数据库Transwarp Hippo团队的详细介绍

目录 团队概况 团队特色 团队实践 未来展望 团队概况 星环向量数据库团队,这是一个在星环内部颇具特色的团队。我们的特色在于,我们不仅专注于数据库领域,而且还涵盖了数据应用以及人工智能领域。这种跨领域的合作让我们能够提供更全面、更深入的服务。 我们团队的一个重…

Android Activity启动流程一:从Intent到Activity创建

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、概览二、应用内启动源码流程 (startActivity)2.1 startActivit…

Facebook message tag 使用攻略

Messenger 讯息传不出去&#xff1f;无法发送FB 讯息给非好友&#xff1f; 2020年3月&#xff0c;Facebook 为了防止用户被过多的推广或垃圾讯息困扰而更新使用条款&#xff0c;现在商家要用FB传讯息给所有人&#xff08;包括非好友&#xff09;&#xff0c;应该使用 Facebook …