当前位置: 首页 > 工具软件 > Boost > 使用案例 >

BOOST的JSON解析库Boost.JSON简介

尚景焕
2023-12-01


Boost很早就有了能解析JSON的库(Boost.PropertyTree)还能解析XML,INI和INFO等。但其笨重复杂。在1.75后引入了新的JSON解析库Boost.JSON。

JSON库基础

JSON中主要包括四种数据类型:object、value、array和string;要使用JSON功能,需要:

#include <boost/json.hpp>
using namespace boost::json;

从JSON字符串中获取键值(通过if_contains获取key对应value的指针,然后通过as_XXX获取实际值):

#include <boost/json.hpp>

auto obj = boost::json::parse(recvContent).as_object();
auto opType = obj.at("TYPE").as_string();
auto pValue = obj.if_contains("OP_STR");
if (pValue)
{
    if (pValue->as_string().empty())
    {
		// ...
    }
    else
    {
		auto pStr = std::make_shared<std::string>(pValue->as_string().c_str());
		// ...
    }
}

object

object是JSON键值对的容器,定义在<boost/json/object.hpp>,其主要的成员函数:

NameDescription
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能保存元素的最大数量。

value

表示JSON值的类型,主要的成员函数:

NameDescription
as_array若为数组,则返回对应的引用(array),否则抛出异常
as_bool
as_double
as_int64
as_object
as_string
as_uint64
类型匹配时,则返回对应的引用,否则抛出异常
at(key)
at(pos)
数组类型根据索引(从0开始),获取值引用;其他根据值返回引用;不存在时抛出异常
emplace_array
emplace_bool
emplace_double
emplace_int64
emplace_object
emplace_string
emplace_uint64
返回对应的引用,并修改value为对应类型(且赋为对应的默认值)
emplace_nullChange the kind to null, discarding the previous contents.
get_array
get_bool
get_double
get_int64
get_object
get_string
get_uint64
获取对应类型的引用(不做任何检查,速度快)
if_array
if_bool
if_double
if_int64
if_object
if_string
if_uint64
类型匹配,返回对应的指针;否则返回nullptr
is_array
is_bool
is_double
is_int64
is_object
is_string
is_uint64
类型匹配,返回true
is_nullReturns true if this is a null.
is_primitiveReturns true if this is not an array or object.
is_structuredReturns true if this is an array or object.
kind返回值对应的底层类型
swapSwap the given values.
to_numberReturn the stored number cast to an arithmetic type.

array

JSON值为数组的类型,主要成员函数:

NameDescription
at(pos)获取指定索引(从0开始)处值的引用,出错抛出out_of_range异常
back获取最后一个元素
begin/end
rbegin/rend
获取iterator
capacity获取容量
clear清空
data获取底层数组的指针
emplace(pos, Arg&&)在指定位置插入元素(构造)
emplace_back在尾部插入元素
emptyCheck if the array has no elements.
earse删除元素
front返回第一个元素
if_containsReturn a pointer to an element, or nullptr if the index is invalid.
insertInsert elements before the specified location.
operator=Copy assignment.Move assignment.Assignment.
operator[]Access an element.
pop_back删除最后一个元素
push_back在尾部添加元素
reserve增加容量(若指定值小于现有容量,则什么也不做)
resize修改元素数量(若比原来大则填充null value,否则删除多余元素)
shrink_to_fitRequest the removal of unused capacity.
sizeReturn the number of elements in the array.

string

字符串值类型,主要成员函数:

NameDescription
append追加字符(串)
assign赋值
at返回指定位置字符引用
back返回最后一个字符引用
begin/end返回iterator
c_strReturn the underlying character array directly.
clearClear the contents.
compareCompare a string with the string.
copyCopy a substring to another string.
dataReturn the underlying character array directly.
emptyCheck if the string has no characters.
ends_withReturn whether the string end with a string.Return whether the string ends with a character.
eraseErase characters from the string.Erase a character from the string.Erase a range from the string.
findFind the first occurrence of a string within the string.Find the first occurrence of a character within the string.
find_first_not_ofFind the first occurrence of any of the characters not within the string.Find the first occurrence of a character not equal to ch.
find_first_ofFind the first occurrence of any of the characters within the string.
find_last_not_ofFind the last occurrence of a character not within the string.Find the last occurrence of a character not equal to ch.
find_last_ofFind the last occurrence of any of the characters within the string.
frontReturn the first character.
growIncrease size without changing capacity.
insert插入
operator string_viewConvert to a string_view referring to the string.
operator+=Append characters from a string.Append a character.
operator=Copy assignment.Move assignment.Assign a value to the string.
operator[]Return a character without bounds checking.
pop_backRemove the last character.
push_backAppend a character.
replace替换
reserveIncrease the capacity to at least a certain amount.
resizeChange the size of the string.
rfindFind the last occurrence of a string within the string.Find the last occurrence of a character within the string.
shrink_to_fitRequest the removal of unused capacity.
sizeReturn the number of characters in the string.
starts_withReturn whether the string begins with a string.Return whether the string begins with a character.
subviewReturn a substring.

JSON使用

构造的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
}

构造JSON

构造一个JSON很简单:定义一个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 val = {
	{"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(val) << std::endl;

serializer还支持部分流输出(在数据量较大时,可以有效降低内存占用):

boost::json::serializer ser;
ser.reset(&val);
char temp_buff[10];
while (!ser.done()) {
	std::memset(temp_buff, 0, sizeof(char) * 10);
	ser.read(temp_buff, 9);
	std::cout << temp_buff << std::endl;
}

对象序列化

对象转换为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::parse可方便地把字符串反序列化为JSON结构。

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

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

unsigned char buf[4096];
boost::json::static_resource mr(buf);
boost::json::parse_options opt;
opt.allow_comments = true; 	// 允许注释
opt.allow_trailing_commas = true; 	// 允许尾部逗号
boost::json::parse("[1, 2, 3, ] // comment test", ec, &mr, opt);
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);

流输入

通过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;
 类似资料: