ZetJsonCpp - 从/到 JSON 字符串或文件进行反序列化/序列化
一个解析 Json 字符串或文件并绑定到 C 结构的库
也可以从 Github 下载。
引言
如今,JSON 结构已成为 Web 应用程序中最常用的数据交换方式。这是因为 JSON 是最简单、最易于人类阅读的格式,因此使用起来更友好。本文旨在介绍如何在 C++ 中使用 zetjsoncpp
库从/到 JSON 字符串或文件进行反序列化/序列化。
1. 反序列化
使用 zetjsoncpp::deserialize
来序列化 JSON 变量。Zet JsonCpp 支持反序列化以下类型:
- 布尔值
- 布尔值向量
- 布尔值映射
- 数字
- 数字向量
- 数字映射
- 字符串
- 字符串向量
- 字符串映射
- 对象
- 对象向量
- 对象映射
2.1 布尔值
反序列化 JSON 布尔值是通过 JsonVarBoolean
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarBoolean<>>("true");
2.2 布尔值向量
JSON 布尔值向量可能是这样的:
[true,false,true]
反序列化 JSON 布尔值向量是通过 JsonVarVectorBoolean
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarVectorBoolean<>>(
"["
"true"
",false"
",true"
"]");
2.3 布尔值映射
JSON 布尔值映射可能是这样的:
{
"id1":true
,"id2":false
,"id3":true
}
反序列化 JSON 布尔值映射是通过 JsonVarMapBoolean
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapBoolean<>>(
"{"
"\"id1\":true"
",\"id2\":false"
",\"id3\":true"
"}");
2.4 数字
JSON 数字可能是这样的:
- -1
- 2.5
- 3.7e+2
反序列化 JSON 数字是通过 JsonVarNumber
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarNumber<>>("1");
2.5 数字向量
JSON 数字向量可能是这样的:
[1,3.7e+2,-3]
反序列化 JSON 数字向量是通过 JsonVarVectorNumber
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarVectorNumber<>>(
"["
"1"
",3.7e+2"
",-3"
"]");
2.6 数字映射
JSON 数字映射可能是这样的:
{
"id1":1
,"id2":3.7e+2
,"id3":-3
}
反序列化 JSON 数字映射是通过 JsonVarMapNumber
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapNumber<>>(
"{"
"\"id1\":1"
",\"id2\":3.7e+2"
",\"id3\":-3"
"}");
2.7 字符串
反序列化 JSON 字符串
是通过 JsonVarString
完成的,如下所示:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarString<>>("\"my_string\"")
2.8 字符串向量
JSON 字符串
向量可能是这样的:
["string_1","string_2","string_3"]
反序列化 字符串
向量是通过 JsonVarVectorString
完成的,如下所示:
zetjsoncpp::deserialize<JsonVarVectorString<>>(
"["
"\"string_1\""
",\"string_2\""
",\"string_3\""
"]");
2.9 字符串映射
JSON 字符串
映射可能是这样的:
{
"id1":"string_1"
,"id2":"string_2"
,"id3":"string_3"
}
反序列化 字符串
映射是通过 JsonVarMapString
完成的,如下所示:
JsonVarMapString<> *m3=zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapString<>>(
"{"
"\"id1\":\"string_1\""
",\"id2\":\"string_2\""
",\"id3\":\"string_3\""
"}");
2.10 对象
到目前为止,我们已经了解了如何序列化易于理解的原始类型和结构化类型。现在,我们介绍一种需要一些设置的 JSON 对象反序列化方法。JSON 对象类似于 JSON 映射,但其值的类型不同。
JSON 对象可能是这样的:
{
"encoding":"UTF-8"
,"length":1000
,"use_space":false
}
以列表 2.1 的示例为例,在 zetjsoncpp
中,使用 C 结构来定义 JSON 对象,如下所示:
typedef struct{
zetjsoncpp::JsonVarString<ZJ_CONST_CHAR("encoding")> encoding;
zetjsoncpp::JsonVarNumber<ZJ_CONST_CHAR("length")> length;
zetjsoncpp::JsonVarBoolean<ZJ_CONST_CHAR("use_space")> use_space;
}JsonSample;
注意:
您可能已经注意到
ZJ_CONST_CHAR(s)
。这是一个技巧,用于逐个字符地通过可变参数模板传递字符串字面量,以便模板不接受(例如const char *
)作为参数。
最后,反序列化 JSON 对象是通过 JsonVarObject
完成的,它传递了在列表 2.2 中看到的用于反序列化的结构类型。
auto json_object=zetjsoncpp::deserialize<zetjsoncpp::JsonVarObject<JsonSample>>(
"{"
"\"encoding\":\"UTF-8\""
",\"length\":1000"
",\"use_space\":false"
"}");
如果任何变量未被反序列化,因为它们不存在于字符串/文件中,或者它们与 JSON 属性名与 C++ 结构中定义的属性名不匹配,则必须使用 isDeserialized()
来检查变量是否已被反序列化。
例如
if(json_object->encoding.isDeserialized()){
// value deserialized ok. do something...
}
默认情况下,任何未反序列化的变量,字符串将被设置为空,数字和布尔值将分别设置为 0
和 false
。
2.11 对象向量
JSON 对象向量可能如下所示:
[{
"encoding":"UTF-8"
,"length":1000
,"use_space":false
},{
"encoding":"ANSII"
,"length":1500
,"use_space":true
}]
反序列化对象向量是通过 JsonVarVectorObject
完成的,它传递了在列表 2.2 中看到的用于反序列化的结构类型。
zetjsoncpp::deserialize<zetjsoncpp::JsonVarVectorObject<JsonSample>>(
"[{"
"\"encoding\":\"UTF-8\""
",\"length\":1000"
",\"use_space\":false"
"},{"
"\"encoding\":\"ANSII\""
",\"length\":1500"
",\"use_space\":true"
"}]");
2.12 对象映射
JSON 对象映射可能是这样的:
{
"id1":{
"encoding":"UTF-8"
,"length":1000
,"use_space":false
}
,"id2":{
"encoding":"ANSII"
,"length":1500
,"use_space":true
}
}
反序列化对象映射是通过 JsonVarMapObject
完成的,它传递了在列表 2.2 中看到的用于反序列化的结构类型。
zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapObject<JsonSample>>(
"{"
"\"id1\":{"
"\"encoding\":\"UTF-8\""
",\"length\":1000"
",\"use_space\":false"
"}"
",\"id2\":{"
"\"encoding\":\"ANSII\""
",\"length\":1500"
",\"use_space\":true"
"}"
"}");
2. 序列化
使用 zetjsoncpp::serialize
来序列化 JSON 变量。
例如
// parse json var number
auto json_number=zetjsoncpp::deserialize<zetjsoncpp::JsonVarNumber<>>("2");
// change it by 3.5
json_number=3.5;
std::cout << zetjsoncpp::serialize(json_var); << std::enl;
// it outputs 3.5
3. 示例
在本节中,我们将看到一个反序列化第 2 节中提到的大部分类型的示例。假设我们有一个名为 sample.json 的文件,其内容如下:
// Configuration options
{
// Default encoding for text
"encoding" : "UTF-8",
"number": 3.34E-5,
// Plug-ins loaded at start-up
"plug-ins" : [
"python",
"c++",
"ruby"
],
// Tab indent size
"indent" : { "length" : 3, "use_space": true },
// set of languages
"languages":[{
"code" : "en",
"general_texts": {
"general.hello_word":"Hello world!"
,"general.yes":"Yes"
,"general.no":"No"
}
},{
"code" : "es",
"general_texts": {
"general.hello_word":"Hola mundo!"
,"general.yes":"Si"
,"general.no":"No"
}
},{
"code" : "zh-CN",
"general_texts": {
"general.hello_word":"你好词"
,"general.yes":"是"
,"general.no":"没有"
}
}]
// set of interpolators
,"interpolations":{
"id_1":{
"type":"material"
,"channels":"rgb"
,"data":[
// r g b t
//---- --- --- ----
0.0,1.0,0.0,1000
,0.0,0.0,0.0,0
]
},"id_2":{
"type":"transform"
,"channels":"xyz"
,"data":[
// x y z t
//---- --- --- ----
0.0,1.0,0.0,1000
,0.0,0.0,0.0,0
]
}
}
}
我们可以将列表 3.1 中的 JSON 结构与以下带有 JSON 变量的 C 结构相关联:
#include "zetjsoncpp.h"
using zetjsoncpp::JsonVarNumber;
using zetjsoncpp::JsonVarBoolean;
using zetjsoncpp::JsonVarString;
using zetjsoncpp::JsonVarMapString;
using zetjsoncpp::JsonVarVectorNumber;
using zetjsoncpp::JsonVarVectorString;
using zetjsoncpp::JsonVarObject;
using zetjsoncpp::JsonVarVectorObject;
using zetjsoncpp::JsonVarMapObject;
typedef struct{
// Number length
JsonVarNumber<ZJ_CONST_CHAR("length")> length;
// Boolean use_space
JsonVarBoolean<ZJ_CONST_CHAR("use_space")> use_space;
}Ident;
typedef struct{
// String code
JsonVarString<ZJ_CONST_CHAR("code")> code;
// Map of strings general_texts
JsonVarMapString<ZJ_CONST_CHAR("general_texts")> general_texts;
}Language;
typedef struct{
// String type
JsonVarString<ZJ_CONST_CHAR("type")> type;
// String channels
JsonVarString<ZJ_CONST_CHAR("channels")> channels;
// Vector of numbers data
JsonVarVectorNumber<ZJ_CONST_CHAR("data")> data;
}Interpolation;
typedef struct
{
// String encoding
JsonVarString<ZJ_CONST_CHAR("encoding")> encoding;
// Number number
JsonVarNumber<ZJ_CONST_CHAR("number")> number;
// Vector of strings plug-ins
JsonVarVectorString<ZJ_CONST_CHAR("plug-ins")> plugins;
// Object indent
JsonVarObject<Ident,ZJ_CONST_CHAR("indent")> indent;
// Object languages
JsonVarVectorObject<Language,ZJ_CONST_CHAR("languages")> languages;
// Map of objects interpolations
JsonVarMapObject<Interpolation,ZJ_CONST_CHAR("interpolations")> interpolations;
}SampleJson;
下面,您可以看到一个反序列化、加载的 JSON 对象的数据操作,最后序列化以反映所做更改的示例:
int main(int argc, char *argv[]){
try{
auto json_object=zetjsoncpp::deserialize_file<JsonVarObject<SampleJson>>("sample.json");
// the values before modifications.
std::cout << "---------------------------------------------------" << std::endl;
std::cout << " Before modifications:"<< std::endl;
std::cout << zetjsoncpp::serialize(json_object);
// From here we can operate with loaded data in our program using c++ operators
// put m_use_space to false...
json_object->indent.use_space = false;
// iterate of all plugins and replace with random strings...
for(unsigned i = 0; i < json_object->plugins.size(); i++) {
json_object->plugins[i] =
"my_randomstring"+zetjsoncpp::zj_strutils::int_to_str(i+1);
}
// iterate of all interpolations and replace its data values...
for(auto it_map = json_object->interpolations.begin();
it_map != json_object->interpolations.end(); it_map++) {
for(auto it = it_map->second->data.begin();
it != it_map->second->data.end(); it++) {
*it = rand();
}
}
std::cout << "--------------------------------------------------" << std::endl;
std::cout << " After modifications:"<< std::endl;
std::cout << zetjsoncpp::serialize(json_object);
// destroy json_object
delete json_object;
}catch(std::exception & ex){
std::cerr << "Error:" << ex.what() << std::endl;
}
}
执行后,输出显示了在 **粗体** 中标记的更改之前和之后的序列化 JSON:
---------------------------------------------------
Before modifications:
{
"encoding":"UTF-8",
"number":0.000033,
"plug-ins":
[
"python","c++","ruby"
],
"indent":
{
"length":3.000000,
"use_space":true
},
"languages":
[{
"code":"en",
"general_texts":
{
"general.hello_word":"Hello world!"
,"general.no":"No"
,"general.yes":"Yes"
}
},{
"code":"es",
"general_texts":
{
"general.hello_word":"Hola mundo!"
,"general.no":"No"
,"general.yes":"Si"
}
},{
"code":"zh-CN",
"general_texts":
{
"general.hello_word":"你好词"
,"general.no":"没有"
,"general.yes":"是"
}
}],
"interpolations":
{
"id_1":{
"type":"material",
"channels":"rgb",
"data":
[
0.000000,1.000000,0.000000,1000.000000,0.000000,0.000000,0.000000,0.000000
]
}
,"id_2":{
"type":"transform",
"channels":"xyz",
"data":
[
0.000000,1.000000,0.000000,1000.000000,0.000000,0.000000,0.000000,0.000000
]
}
}
}--------------------------------------------------
After modifications:
{
"encoding":"UTF-8",
"number":0.000033,
"plug-ins":
[
"my_randomstring1","my_randomstring2","my_randomstring3"
],
"indent":
{
"length":3.000000,
"use_space":false
},
"languages":
[{
"code":"en",
"general_texts":
{
"general.hello_word":"Hello world!"
,"general.no":"No"
,"general.yes":"Yes"
}
},{
"code":"es",
"general_texts":
{
"general.hello_word":"Hola mundo!"
,"general.no":"No"
,"general.yes":"Si"
}
},{
"code":"zh-CN",
"general_texts":
{
"general.hello_word":"你好词"
,"general.no":"没有"
,"general.yes":"是"
}
}],
"interpolations":
{
"id_1":{
"type":"material",
"channels":"rgb",
"data":
[
41.000000,18467.000000,6334.000000,26500.000000,19169.000000,
15724.000000,11478.000000,29358.000000
]
}
,"id_2":{
"type":"transform",
"channels":"xyz",
"data":
[
26962.000000,24464.000000,5705.000000,28145.000000,
23281.000000,16827.000000,9961.000000,491.000000
]
}
}
}
4. 编译
要编译源代码,您需要 cmake
工具来创建其 Makefile 或 Visual Studio 解决方案,然后编译项目。
cmake -H. -Bbuild
编译后,除了生成 zetjsoncpp
库之外,还将分别生成名为 test 和 test_file 的可执行文件。名为 test 的可执行文件执行基本操作以检查其完整性,而 test_file 读取第 3 节中看到的 JSON 文件。
5. 结论
本文介绍了一种通过一行代码从字符串或文件中反序列化 JSON 内容的简单方法。结果对生产非常优化,并且因为它绑定在 C 结构中,用户可以轻松了解每个字段,因此易于处理。希望您发现此工具有用。
历史
2021-04-7 ZetJsonCpp 2.0.1
- 修复当 jsonvar c++ 值与读取值不匹配时的错误
2021-02-15 ZetJsonCpp 2.0.0
- 添加了对映射/字典元素的支持
- 大规模的代码组织和清理
- 支持带 bom 的 utf-8 文件
- 支持反序列化任何 JSON 类型(例如,数字/字符串/布尔值/对象,元素向量或映射)
2018-05-15 ZetJsonCpp 1.3.0
- 将版本历史记录审查为新格式(
MAJOR.MINOR.PATCH
) - 错误/警告的行为通过回调函数
setFunctionOnError
、setFunctionOnWarning
进行。如果未设置这些函数,则消息将使用fprintf
(stderr
)打印。 - 添加了内存泄漏检测(仅限 GNU 工具链)。它需要
memmanager https://github.com/jespa007/memmanager
并在cmake
上传递-DMEMMANAGER
参数。 - 修复了 MSVC 平台上的
compile test_json
共享库 - 改进了
cmake
消息打印
2018-05-10 ZetJsonCpp 1.2.0
- 项目通过
cmake
构建 - MSVC 支持(v141 Tools 或 MSVC++ 2015)
- 添加了
zetjsoncpp 命名空间
- 将
fastjsoncpp
重命名为zetjsoncpp
- 添加了检测数组类型的特性
- 将 GPL3 许可证更改为 MIT
2015-08-29 ZetJsonCpp 1.1.0
- 添加了支持数字科学计数法(例如 2.1E-10)的特性
- 添加了检测属性组或属性组数组的特性
- 修复了适用于 Windows 的回车换行符兼容性
2014-08-08 ZetJsonCpp 1.0.0
- 首次发布