RapidJSON 完整学习指南

目录

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

基础概念

RapidJSON 的三个核心类

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

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

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

JSON 的5种类型

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

创建JSON对象

方式1:基础创建

// 第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:添加字符串(需要特殊处理)

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:添加嵌套对象

// 创建嵌套对象
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:添加数组

// 创建数组
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:数组中添加对象

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()

// 基本用法
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()

if (document.HasMember("name")) {
    std::cout << "name exists" << std::endl;
}

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

删除成员 - RemoveMember()

document.RemoveMember("oldField");

读取JSON

读取文本字段

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

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

读取数字字段

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

读取布尔字段

bool active = document["active"].GetBool();

读取对象字段

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

读取数组字段

// 方式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;
}

类型检查

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; }

序列化与反序列化

序列化(转换为字符串)

// 步骤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;

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

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() 函数:

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);
}

输出示例

{
  "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"
      }
    ]
  }
}

你的代码中的问题

//  问题: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!有任何疑问欢迎继续提问。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]