现代C++ JSON解析库

概述

  • C++17 标准
  • 仅标准库,跨平台
  • 代码不到1000行,轻量
  • 性能较好
  • 操作非常简单
  • 序列化、反序列化、美化、增删改查
  • 移动语义与异常处理支持
  • 支持从vcpkg安装库

文档

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
C++Doxygen文档
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

应用示例

0. 导入库与头文件

你可以直接下载srcinclude中的两个代码文件,放到项目中使用。

也可以作为第三方库导入(默认静态库),方式如下:

# 请先使用 'git pull' 更新vcpkg端口文件
# 全局模式
vcpkg install mysvac-jsonlib

# 清单模式
vcpkg add port mysvac-jsonlib
# CmakeLists.txt
find_package(mysvac-jsonlib CONFIG REQUIRED)
target_link_libraries(main PRIVATE mysvac::jsonlib)
// C++代码 导入头文件
#include "mysvac/jsonlib.h"
// 导入命名空间简化代码,可选
using namespace Jsonlib;

1. 基本类型介绍

三种可操作类型和六种JSON数据类型:

// 广义的“值类型”,包含 对象 数组 等全部6种JSON数据类型。
class JsonValue;

// 对象类型,本质是 std::map<std::string, JsonValue>
class JsonObject;

// 数组类型,本质是 std::vector<JsonValue>
class JsonArray;

// 使用 JsonValue.type() 函数,获取内部JSON数据类型
enum class JsonType{
    OBJECT, /**< JSON 对象类型 */
    ARRAY,/**< JSON 数组类型 */
    STRING, /**< JSON 字符串类型 */
    NUMBER, /**< JSON 数值类型 */
    BOOL, /**< JSON 布尔类型 */
    ISNULL, /**< JSON null类型 */
};

2. 列表初始化

需要注意,既然存在列表初始化函数,就要谨慎使用{ }运算符进行初始化。
因为{ }( )初始化器会带来不同的行为。

参考代码:

JsonValue json1 = {
    { "key", nullptr },
    { 1, 2, 3, 4, 5 },
    "string",
    true,
    false,
    1234.5
};

生成规则:

  1. 如果初始化器为空,则生成ISNULL类型对象。
  2. 如果初始化器只有2个元素,且第1个元素是字符串,则生成OBJECT。
  3. 其他情况则生成ARRAY类型对象。

注意规则3,{}运算符构造,内部只有1个元素,依然只会生成ARRAY类型对象。
()运算符构造,等同赋值语句,根据参数类型生成不同类型的对象。

注意规则2,有的时候需要ARRAY对象,却会被此规则生成OBJECT对象。
所以我更推荐你在类型模糊时,使用如下方式创建:

// JsonObject本质是std::map<std::string, JsonValue>,必须套双重括号进行列表初始化
JsonValue json1 = JsonArray{
    JsonObject { {"key", nullptr} },
    JsonArray{ 1, 2, 3, 4, 5 },
    "string",
    true,
    false,
    1234.5
};

3. 反序列化与序列化

使用deserialize()函数进行反序列化。
使用对象.serialize()成员函数进行序列化。
使用对象.serialize_pretty()函数函数进行美化序列化,可指定缩进长度。

参考代码:

JsonValue json = deserialize(R"(
    {
        "语法": ["C++", "原始字符串", false ],
        "key": "支持\t中文\\\n与\"转义字符",
        "na\"\\me": [ 114,514 , null ],
        "map": [ {} , [ [ "嵌套" ] , {} ] ]
    }
    )");

// serialize序列化 不保留无效空格
std::cout << json.serialize() << std::endl;
// serialize_pretty序列化 带空格和换行,默认一次缩进2空格,可指定
std::cout << json.serialize_pretty() << std::endl;

4. 增删改查

需要注意的是,数组类型本质是std::vector,所以中间插入和删除元素是O(m)的,修改是正常O(1)。
无特殊情况,尽量使用push_back()pop_back()在末尾修改。

而对象类型的本质是std::map,操作都是O(log m)级别。

参考代码:

// json变量是上面【3. 反序列...】中的json变量
json.erase("na\"\\me"); // 删除
json["map"][1].clear(); // 清空
json["语法"] = 114514; // 修改
json["add"] = deserialize("[[[]]]"); //增加
json["add"].push_back(1); 

std::cout << json.serialize() << std::endl;
std::cout << json["key"].as_string() << std::endl; // 获取字符串并转义

可能的输出:

{"add":[[[]],1],"key":"支持\t中文\\\n与\"转义字符","map":[{},[]],"语法":114514}
支持    中文\
与"转义字符

5.使用is检测类型,使用as获取内容

参考代码:

JsonValue value = 123456789012345ll;
// is保证不会抛出异常
value.is_array(); // false
value.is_object(); // false
value.is_double(); // false 内部没有小数点
value.is_number(); // true int64和double都算number
// as 转换失败时抛出异常
value.as_int64(); // 123456789012345ll
value.as_double(); // 1.23457e+14 能够转化,但可能丢失精度
value.as_array(); // 抛出异常 Jsonlib::JsonTypeException

6. 迭代器与移动语义支持

需要注意的是,JsonValue类型不支持迭代器,因为内部类型不确定。

但是可以通过as_array()as_object()获取内部元素的引用,然后使用迭代器。
因为JsonArray本质是std::vector<JsonArray>,而JsonObject是std::map<std::string, JsonValue>

移动语义当然是完全支持的,且JsonArray和JsonObject对象可以赋值/移动给JsonValue,必然成功,不会抛出异常。

参考代码:

JsonValue my_obj = { "key1", { nullptr, 666 } };

JsonValue my_arr = JsonArray { true, JsonObject{} };

// 字符串构造,不会解析内部数据,不会报错,注意使用()而不是{}
JsonValue my_val ("[ {} this is string ]");

// as_array()和as_object()返回引用,其他的as返回副本
for(auto& it: my_arr.as_array()){ 
    // it 的类型是 Jsonlib::JsonValue&
    // 具体操作...
}

// 支持移动,被移动的对象变成JsonType::ISNULL类型,不会删除
my_arr.insert(1, std::move(my_obj["key"]));
my_arr.push_back(my_val);

std::cout << my_arr.serialize_pretty() << std::endl;

可能的输出:

[
  true,
  [
    null,
    666
  ],
  { },
  "[ {} this is string ]"
]

提醒:

不推荐的写法:

// 标准库容器不保证被移动后变回初始状态。
B = std::move(A.as_object()); // ❌ 总是可行,但是不推荐这样写。

推荐的写法:

// 本库的JsonValue类型,保证被移动后重置为ISNULL状态,可以正常使用。
B = std::move(A); // ✅ A会被重置为初始状态。
B = std::move(A["xxx"]); // ✅ 这样访问子元素,得到的类型是JsonValue&,所以也是安全的。

7. 自定义类型的序列化

你可以通过重载类型转换运算符,实现自定义类型的JSON格式化。

参考代码:

struct A{
    std::string name;
    int value;
    bool check;
    // 自行判断是否添加 explicit
    operator JsonValue() const {
        JsonValue result(JsonType::OBJECT);
        result["name"] = name;
        result["value"] = value;
        result["check"] = check;
        return result;
    };
};

需要的的时候,通过类型转换进行序列化,甚至直接赋值:

A a {"XX", 1, true};
std::cout << JsonValue(a).serialize(); // ✅
JsonValue json = a; // ✅ 如果声明了explicit,或许要显示转换

或者尝试写一个宏:

#define Field(name) result[#name] = name;
#define Serializable(...) \
    operator Jsonlib::JsonValue(){ \
        Jsonlib::JsonValue result(Jsonlib::JsonType::OBJECT);    \
        __VA_ARGS__    \
        return result;    \
    }

然后可以通过宏进行注册,实现一样的效果:

struct A{
    std::string name;
    int value;
    bool check;
    Serializable(
        Field(name)
        Field(value)
        Field(check)
    );
};

这样的宏还可以实现类型的嵌套,只要成员变量能隐式转换成JsonValue类型。

库头文件中并没有提供这样的宏,作者认为宏的导入会污染代码。
如果需要,你可以将上述宏函数代码赋值到自己的项目中使用。

8. 异常处理

本库使用了三种自定义异常和一种标准:

  1. JsonException : 继承自std::runtime_runtime_error,没有地方抛出此异常。
  2. JsonTypeException : 继承自JsonException,表示类型错误,比如as_xxx()函数。
  3. JsonStructureException : 继承自JsonException,表示JSON结构错误,导致反序列化失败。
  4. std::out_of_range : 使用at()严格访问子元素,元素不存在或越界时抛出,

参考代码:

try{
    JsonValue json = deserialize("[ {}} ]");
}
catch(const JsonStructureException& e){
    std::cerr << "JsonStructureException: " << e.what() << std::endl;
}
catch(const JsonException& e){
    std::cerr << "JsonException: " << e.what() << std::endl;
}
catch(...){ std::cerr << "other" << std::endl; }

可能的输出:

JsonStructureException: Unknown Json Structure.

注意

赋值/拷贝/移动/序列化/is/type/size…等操作保证不会抛出异常。

只有deserialze()反序列化函数,或者as类型转换失败,访问越界时可能抛出异常。

性能概述

时间复杂度其实没什么用,看看就好,后面都是常数优化。

  • N : JSON文本长度。
  • m : 子元素个数。
  • 下面提供最坏情况的时空复杂度(虽然没什么用,后面都是常数优化。):
  • 序列化:时间复杂度O(N),空间复杂度O(N)。
  • 反序列化: 时间复杂度O(N),空间复杂度O(N)。
  • 键值对-增删改查: O(log m)。
  • 数组-增删: 末尾操作O(1),其余位置平均O(m)。
  • 数组-改查: O(1)。

评论

  1. 博主
    7 天前
    2025-4-12 19:14:46

    性能对比测试参考:https://github.com/Mysvac/cpp-json-test

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇