C++ Rapidjson 完全指南 - 高效 JSON 解析与性能优化
Rapidjson 是一款 C++ 的 json
库. 支持处理 json
格式的文档. 其设计风格是头文件库, 包含头文件即可使用, 小巧轻便并且性能强悍. 本文结合样例来介绍 Rapidjson 一些常见的用法.
环境要求
有如何的几种方法可以将 Rapidjson 集成到您的项目中.
Vcpkg
安装: 使用vcpkg install rapidjson
即可. 如果不熟悉 vcpkg 请参考我的文章: C++包管理工具-Vcpkg 简介.CMake
的FetchContent_Declare
方法.源码安装: 下载源码并将其路径加入
include
目录列表中:gcc -I /path/to/rapidjson
基础用法
解析 json
访问元素
检查并获取
HasMember
查询 key 是否存在, 然后使用Is
方法来判断类型是否兼容, 最后用Get
方法来获取对应的值.
使用FindMember
减少查询开销
上述示例中, doc["name"]
被使用了两次, 相当于创建了两个临时变量. 使用FindMember
方法则可以减少这种额外开销.
访问对象(Object)
查询方法与前面的基础类型相似. 需要注意的是, GetObject()
方法返回的是一个const
引用.
Rapidjson 为了提高效率, 接口的设计上避免使用对象拷贝.
访问数组(Array)
我们用IsArray()
和GetArray()
来判断和获取对应的数据.
需要注意的是: json 中的数组是允许多个不同类型的, 如下是一个合法的 json:
但是 C++ 的数组或者容器vector
仅支持相同的元素, 所以我们在获取数组元素时需要注意判断元素类型.
由于 rapidjson 支持range based for
, 我们可以这样写:
生成 json 对象
基础类型
对于基础类型(整型, 布尔值, 浮点数)我们可以直接使用AddMember
添加, 需要注意的是接口中需要指定一个Allocator
.
此时doc
的内容为:
为了减少对GetAllocator()
的调用, 可以使用一个变量保存该结果, 见后续代码.
添加对象
一个 Object 对象可以用rapidjson::Value
表示. 其添加成员的方法是AddMember
(rapidjson::Document
是rapidjson::Value
的衍生类).
对于特殊值null
, 我们可以使用SetNull()
方法或者在构造函数中指定rapidjson::kNullType
来实现.
此时的doc
为:
添加数组
Array 类型的创建和添加如下所示.
此时doc
为:
序列化 json 对象
进阶用法
使用函数模板简化解析
从前面解析的例子我们可以看到, 对每一个字段都要解析代码, 这样会存在很多的代码冗余.
可以通过模板函数来实现一个解析代码. 我们用std::variant
来存储不同的解析类型, 比如:int*
, double*
, std::string*
等.
接着我们用std::visit
来访问std::variant
, 针对不同类型做不同的解析, 对目前尚不支持的类型则报错.
如何使用呢? 此处以解析一个结构体为例:
完整示例请参考仓库代码: parse.cpp
处理多重嵌套
在工作中我们有时候会遇到嵌套很深的 json 文档. 比如给定这样一个 json 文档, 现在我们要获取/data/avatar/image/thumbnail
如何操作?
如果按照之前的写法层层解析, 那么必然是个很深的嵌套. 但是现在有个更好的解决办法, 就是JSONPath
, 在 rapidjson 里面就是 Pointer
类, 参考如下写法:
完整的代码请参考: jsonpath.cpp
总结
本文通过示例介绍了一些 rapidjson 的使用方法, 包括解析,生成,以及如何做代码优化. 希望能给读者带来一些帮助.
如果您觉得有用, 希望您点赞收藏关注, 感激不尽.
源码链接
Tags: