RapidJSON 完整学习指南

🚀 RapidJSON 完整学习指南

📚 目录

  1. 基础概念
  2. 创建JSON对象
  3. 操作JSON
  4. 读取JSON
  5. 序列化与反序列化
  6. 你的代码详解

🔑 基础概念

RapidJSON 的三个核心类

cpp 复制代码
// 1. Document - JSON文档的根(类似一个JSON对象容器)
rapidjson::Document document;

// 2. Value - JSON值(可以是对象、数组、字符串、数字等)
rapidjson::Value value;

// 3. Allocator - 内存分配器(RapidJSON需要它来分配内存)
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();

JSON 的5种类型

cpp 复制代码
kNullType       // null
kFalseType      // false
kTrueType       // true
kObjectType     // { "key": value }
kArrayType      // [ value, value, ... ]
kStringType     // "string"
kNumberType     // 123, 3.14

🛠 创建JSON对象

方式1:基础创建

cpp 复制代码
// 第1步:创建文档
rapidjson::Document document;

// 第2步:初始化为对象类型
document.SetObject();

// 第3步:获取分配器
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();

// 第4步:添加键值对
document.AddMember("name", "John", allocator);
document.AddMember("age", 30, allocator);
document.AddMember("active", true, allocator);

// 结果: {"name":"John","age":30,"active":true}

方式2:添加字符串(需要特殊处理)

cpp 复制代码
std::string myString = "Hello World";

// ❌ 错误方式(会导致内存问题)
// document.AddMember("msg", myString, allocator);

// ✅ 正确方式1:使用SetString
rapidjson::Value stringValue;
stringValue.SetString(myString.c_str(), myString.size(), allocator);
document.AddMember("msg", stringValue, allocator);

// ✅ 正确方式2:简洁写法
document.AddMember(
    "msg",
    rapidjson::Value().SetString(myString.c_str(), myString.size(), allocator),
    allocator
);

方式3:添加嵌套对象

cpp 复制代码
// 创建嵌套对象
rapidjson::Value personObj(rapidjson::kObjectType);
personObj.AddMember("firstName", "John", allocator);
personObj.AddMember("lastName", "Doe", allocator);

// 添加到主文档
document.AddMember("person", personObj, allocator);

/* 结果:
{
  "person": {
    "firstName": "John",
    "lastName": "Doe"
  }
}
*/

方式4:添加数组

cpp 复制代码
// 创建数组
rapidjson::Value arrayValue(rapidjson::kArrayType);

// 添加元素
arrayValue.PushBack(10, allocator);
arrayValue.PushBack(20, allocator);
arrayValue.PushBack(30, allocator);

// 添加到文档
document.AddMember("numbers", arrayValue, allocator);

/* 结果:
{
  "numbers": [10, 20, 30]
}
*/

方式5:数组中添加对象

cpp 复制代码
rapidjson::Value itemsArray(rapidjson::kArrayType);

// 创建第一个对象
rapidjson::Value item1(rapidjson::kObjectType);
item1.AddMember("id", 1, allocator);
item1.AddMember("name", "Item 1", allocator);
itemsArray.PushBack(item1, allocator);

// 创建第二个对象
rapidjson::Value item2(rapidjson::kObjectType);
item2.AddMember("id", 2, allocator);
item2.AddMember("name", "Item 2", allocator);
itemsArray.PushBack(item2, allocator);

document.AddMember("items", itemsArray, allocator);

/* 结果:
{
  "items": [
    {"id": 1, "name": "Item 1"},
    {"id": 2, "name": "Item 2"}
  ]
}
*/

📖 操作JSON

添加成员 - AddMember()

cpp 复制代码
// 基本用法
document.AddMember("key", value, allocator);

// 支持的数据类型
document.AddMember("string", "value", allocator);      // 字符串
document.AddMember("int", 42, allocator);              // 整数
document.AddMember("double", 3.14, allocator);         // 浮点数
document.AddMember("bool", true, allocator);           // 布尔值
document.AddMember("null", rapidjson::Value(), allocator);  // null值

检查成员是否存在 - HasMember()

cpp 复制代码
if (document.HasMember("name")) {
    std::cout << "name exists" << std::endl;
}

// 安全的获取值
if (document.HasMember("name") && document["name"].IsString()) {
    std::string name = document["name"].GetString();
}

删除成员 - RemoveMember()

cpp 复制代码
document.RemoveMember("oldField");

🔍 读取JSON

读取文本字段

cpp 复制代码
// 方式1:直接访问
std::string name = document["name"].GetString();

// 方式2:安全访问(检查存在性)
if (document.HasMember("name") && document["name"].IsString()) {
    std::string name = document["name"].GetString();
}

读取数字字段

cpp 复制代码
int age = document["age"].GetInt();          // 整数
double salary = document["salary"].GetDouble();  // 浮点数

读取布尔字段

cpp 复制代码
bool active = document["active"].GetBool();

读取对象字段

cpp 复制代码
// JSON: {"person": {"name": "John"}}
std::string personName = document["person"]["name"].GetString();

读取数组字段

cpp 复制代码
// 方式1:通过GetArray()
const rapidjson::Value& array = document["numbers"].GetArray();
for (const auto& item : array) {
    int num = item.GetInt();
    std::cout << num << std::endl;
}

// 方式2:直接遍历
for (const auto& item : document["numbers"].GetArray()) {
    std::cout << item.GetInt() << std::endl;
}

类型检查

cpp 复制代码
if (value.IsString()) { std::cout << "是字符串" << std::endl; }
if (value.IsInt()) { std::cout << "是整数" << std::endl; }
if (value.IsDouble()) { std::cout << "是浮点数" << std::endl; }
if (value.IsBool()) { std::cout << "是布尔值" << std::endl; }
if (value.IsArray()) { std::cout << "是数组" << std::endl; }
if (value.IsObject()) { std::cout << "是对象" << std::endl; }
if (value.IsNull()) { std::cout << "是null" << std::endl; }

🔄 序列化与反序列化

序列化(转换为字符串)

cpp 复制代码
// 步骤1:创建StringBuffer来存储结果
rapidjson::StringBuffer buffer;

// 步骤2:创建Writer并写入文档
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);

// 步骤3:获取JSON字符串
std::string jsonString = buffer.GetString();
std::cout << jsonString << std::endl;

反序列化(从字符串解析)

cpp 复制代码
std::string jsonString = R"({"name": "John", "age": 30})";

// 步骤1:创建新文档
rapidjson::Document doc;

// 步骤2:解析JSON字符串
doc.Parse(jsonString.c_str());

// 步骤3:检查是否解析成功
if (doc.HasParseError()) {
    std::cerr << "Parse error!" << std::endl;
    return;
}

// 步骤4:访问解析后的数据
std::string name = doc["name"].GetString();
int age = doc["age"].GetInt();

💡 你的代码详解

现在让我为你详细讲解你的 setImageList() 函数:

cpp 复制代码
void setImageList(std::string deviceId, std::list<image> list) {
    using namespace rapidjson;
    
    // ========== 第1步:创建文档 ==========
    Document document;
    document.SetObject();
    
    // ========== 第2步:设置消息头 ==========
    // address: 指定接收端处理该消息的处理器类型为 "imageplayer"
    document.AddMember("address", "imageplayer", document.GetAllocator());
    
    // action: 指定执行什么操作为 "setImageList"
    document.AddMember("action", "setImageList", document.GetAllocator());
    
    // ========== 第3步:创建数据对象 ==========
    Value data(kObjectType);
    
    // 添加目标设备ID
    data.AddMember(
        "to", 
        rapidjson::Value().SetString(
            deviceId.c_str(), 
            deviceId.size(), 
            document.GetAllocator()
        ), 
        document.GetAllocator()
    );
    
    // ========== 第4步:创建图片列表数组 ==========
    Value listValue(kArrayType);
    
    // 遍历输入的图片列表
    for (auto it : list) {
        // 为每个图片创建对象
        Value item(kObjectType);
        
        // 添加图片ID
        item.AddMember(
            "id", 
            rapidjson::Value().SetString(
                it.id.c_str(), 
                it.id.size(), 
                document.GetAllocator()
            ), 
            document.GetAllocator()
        );
        
        // 添加图片URL(文件路径)
        item.AddMember(
            "url", 
            rapidjson::Value().SetString(
                it.url.c_str(), 
                it.url.size(), 
                document.GetAllocator()
            ), 
            document.GetAllocator()
        );
        
        // 添加图片名称
        item.AddMember(
            "name", 
            rapidjson::Value().SetString(
                it.name.c_str(), 
                it.url.size(),  // ⚠️ 注意:这里可能是个BUG,应该是 it.name.size()
                document.GetAllocator()
            ), 
            document.GetAllocator()
        );
        
        // 将该图片对象添加到数组
        listValue.PushBack(item, document.GetAllocator());
    }
    
    // ========== 第5步:将列表添加到数据对象 ==========
    data.AddMember("list", listValue, document.GetAllocator());
    
    // ========== 第6步:将数据添加到文档 ==========
    document.AddMember("data", data, document.GetAllocator());
    
    // ========== 第7步:序列化为JSON字符串 ==========
    StringBuffer buffer;
    Writer<StringBuffer> writer(buffer);
    document.Accept(writer);
    std::string str = buffer.GetString();
    
    // ========== 第8步:发送消息 ==========
    HHCastServerCore::getInstance()->sendMessage(str);
}

输出示例

json 复制代码
{
  "address": "imageplayer",
  "action": "setImageList",
  "data": {
    "to": "device_123",
    "list": [
      {
        "id": "img_001",
        "url": "C:/images/photo1.jpg",
        "name": "photo1.jpg"
      },
      {
        "id": "img_002",
        "url": "C:/images/photo2.png",
        "name": "photo2.png"
      }
    ]
  }
}

🐛 你的代码中的问题

cpp 复制代码
// ❌ 问题:name字段的大小使用了错误的值
item.AddMember(
    "name", 
    rapidjson::Value().SetString(
        it.name.c_str(), 
        it.url.size(),  // ⚠️ 应该是 it.name.size()
        document.GetAllocator()
    ), 
    document.GetAllocator()
);

// ✅ 修正后:
item.AddMember(
    "name", 
    rapidjson::Value().SetString(
        it.name.c_str(), 
        it.name.size(),  // 使用正确的size
        document.GetAllocator()
    ), 
    document.GetAllocator()
);

📋 常用操作速查表

操作 代码示例 说明
创建文档 Document doc; doc.SetObject(); 初始化空对象
添加键值对 doc.AddMember("key", value, allocator); 添加成员
获取字符串 doc["key"].GetString() 读取字符串值
获取整数 doc["key"].GetInt() 读取整数值
创建数组 Value arr(kArrayType); 创建空数组
添加到数组 arr.PushBack(value, allocator); 向数组添加元素
遍历数组 for(auto& item : doc["arr"].GetArray()) 循环遍历
序列化 StringBuffer buf; Writer w(buf); doc.Accept(w); 转JSON字符串
反序列化 Document doc; doc.Parse(str.c_str()); 从字符串解析
检查成员 doc.HasMember("key") 检查键是否存在

希望这能帮助你理解 RapidJSON!有任何疑问欢迎继续提问。

相关推荐
一朵筋斗云6 小时前
c++
c++
有趣的我7 小时前
关于stub和mock
c++
Yupureki7 小时前
从零开始的C++学习生活 18:C语言复习课(期末速通)
c语言·数据结构·c++·学习·visual studio
永远有缘8 小时前
四种编程语言常用函数对比表
java·开发语言·c++·python
C++_girl8 小时前
c++、java/python语言有什么区别?为什么c++更快?
java·开发语言·c++
艾莉丝努力练剑8 小时前
【Linux权限 (二)】Linux权限机制深度解析:umask如何决定默认权限与粘滞位的妙用
大数据·linux·服务器·c++·ubuntu·centos·1024程序员节
彩妙不是菜喵8 小时前
基于C语言上,面向对象语言:C++基础(学完C语言后再看)
c语言·开发语言·c++
夜晚中的人海9 小时前
【C++】位运算算法习题
开发语言·c++·算法
枫叶丹49 小时前
【Qt开发】布局管理器(一)-> QVBoxLayout垂直布局
开发语言·c++·qt