【c++】rapidjson

https://rapidjson.org/zh-cn/

1. 概念


  • Document类代表整个DOM,每个 JSON 值都储存为 Value 类
#include "rapidjson/document.h"
using namespace rapidjson;

//把json字符串解析到doc
const char* json;
Document doc;
doc.Parse(json);

数据类型

//! Type of JSON value
enum Type {
    kNullType = 0,      //!< null
    kFalseType = 1,     //!< false
    kTrueType = 2,      //!< true
    kObjectType = 3,    //!< object
    kArrayType = 4,     //!< array 
    kStringType = 5,    //!< string
    kNumberType = 6     //!< number
};

判断类型

Document::IsNull()
Document::IsBool()
Document::IsObject()
Document::IsArray()
Document::IsString()
Document::IsNumber()
Document::IsInt()
Document::IsDouble()

使用默认构造函数创建一个 Value 或 Document,它的类型便会是 Null。要改变其类型,需调用 SetXXX() 或赋值操作

Value v;    // Null
v.SetInt(10);
v = 10;     // 简写,和上面的相同

构造Value及赋值

  • 创建空Object或 Array。一次性使用 Value(Type)
Value o(kObjectType);
Value a(kArrayType);
  • 构造赋值
Value b(true);    // 调用 Value(bool)
Value i(-123);    // 调用 Value(int)
Value u(123u);    // 调用 Value(unsigned)
Value d(1.5);     // 调用 Value(double)

赋值

  • 字符串
    函数原型:SetString(const char*, int, SizeType length, Allocator& allocator)
Value a(kNumberType);
a.SetInt(42);
a=Value().SetInt(42).Move();

std::string str = "hello";
Value b(kStringType);
b.SetString(str.c_str(), str.size(), doc.GetAllocator());
b=Value().SetString(str.c_str(), str.size(), doc.GetAllocator()).Move();

取值

  • 通过Value::name获取字段名,通过Value::value获取字段值。
auto bodyObj = bodyDoc.GetObject();
for(auto& m:body)
{
    string col(m.name.GetString());
    auto val = m.value.GetString();
}

  • 取值前为了健壮性,一定要先判断字段是否存在,是否为null。
//Array
GetArray();
SizeType Capacity() const
bool Empty() const
你可以用整数字面量访问元素,如 a[0]、a[1]、a[2]
除了使用索引,也可使用迭代器来访问所有元素。

for (Value::ConstValueIterator iter = a.Begin(); iter != a.End(); ++iter)
{
  if(!iter->IsNull())  cout<<iter->GetInt();
} 

//String
GetString();
if(doc.HasMember("key") && !doc["key"].IsNull())
{
  string str = doc["key"].IsString();
}

//Number
| bool IsUint()   | unsigned GetUint()   |
| --------------- | -------------------- |
| bool IsInt()    | int GetInt()         |
| bool IsUint64() | uint64_t GetUint64() |
| bool IsInt64()  | int64_t GetInt64()   |
| bool IsDouble() | double GetDouble()   |

//Ojbect
operator[]

Value的拷贝使用的是移动语义

Value a(123);
Value b(456);
b = a;         // a 变成 Null,b 变成数字 123。

添加元素

Object添加k-v:AddMember("key", Value, allocator)
Array添加元素:PushBack(Value, allocator)
Value如果用直接临时值会报错。临时对象是不能转换为正常的 Value 引用,我们加入了一个方便的 Move() 函数:

Value a(kArrayType);
Document::AllocatorType& allocator = document.GetAllocator();
// a.PushBack(Value(42), allocator);       // 不能通过编译
a.PushBack(Value().SetInt(42), allocator); // fluent API
a.PushBack(Value(42).Move(), allocator);   // 和上一行相同

Value b(kObjectType);
std::string str = "hello";
b.AddMember("key", Value().SetString(str.c_str(), str.size(), allocator), allocator);//key可以直接写字符串
b.AddMember(Value("key", allocator).Move(), Value().SetString(str.c_str(), str.size(), allocator), allocator);
b.AddMember(Value("key", allocator).Move(), Value(str.c_str(), str.size(), allocator).Move(), allocator);

2. 读写json文件

(1)从文件读到Document

#include "rapidjson/filereadstream.h"
#include <cstdio>

static tl::expected<Document, string> jsonDocFromFile(string const &file) 
{
    FILE *fp = fopen(file.c_str(), "r");
    if (!fp)
      return tl::make_unexpected("failed opening file: " + file);

    char readBuf[1024];
    FileReadStream frs(fp, readBuf, sizeof(readBuf));
    Document doc;

    if (doc.ParseStream<kParseCommentsFlag>(frs).HasParseError()) {
      return tl::make_unexpected("jsonDocFromFile: invalid json file:" + file);
    }
    fclose(fp);
    return std::move(doc);
}

(2)把Document写到文件

#include "rapidjson/filewritestream.h"
//#include "rapidjson/writer.h"
#include "rapidjson/prettywriter.h"
#include <cstdio>

static tl::expected<bool, string> saveToJsonFile(string const &jsonPath, Document const &doc) 
{
    FILE* fp = fopen(jsonPath.c_str(), "w");//清空写入(wb的b二进制)  
    if(!fp)  
      return tl::make_unexpected("failed opening file: " + jsonPath);
    
    char writeBuf[1024];
    FileWriteStream fws(fp, writeBuf, sizeof(writeBuf));
    PrettyWriter<FileWriteStream> writer(fws);//PrettyWriter会自动设定换行等格式
    //Writer<FileWriteStream> writer(fws);//紧凑
    writer.SetMaxDecimalPlaces(6);
    doc.Accept(writer);
    fclose(fp);
    return true;
}

(3)修改json

//修改json的devices数组
/*
"devices": [
        {
            "id": 1,
            "ip": "127.0.0.1",
            "device_port": 6666,
        }
    ],
"server":"hello"
*/
void modifyJson(string jsonName, vector<Device> devicesUpdate)
{
      // 读json
      auto retReadJson = Config::jsonDocFromFile(jsonName);
      if (!retReadJson.has_value())
      {
        cout<<"读取json文件失败: " + retReadJson.error()<<endl;
        return;
      }
      Document &docSave = retReadJson.value();
      if(!docSave.HasMember("devices") || !docSave["devices"].IsArray())
      {
        cout<<"json文件没有devices字段: " + retReadJson.error()<<endl;
        return;
      }

      //修改devices字段
      for(int i=0;i<devicesUpdate.size();i++)
      {
        Value& device = docSave["devices"][i];
        if(!device.IsObject())
          continue;
        device["id"].SetInt(devicesUpdate[i].id);
        device["device_ip"] = Value(devicesUpdate[i].devIp.c_str(), devicesUpdate[i].devIp.size(), docSave.GetAllocator()).Move();
        device["device_port"] = Value().SetInt(devicesUpdate[i].devPort);
        device["server_port"] = Value().SetInt(devicesUpdate[i].serverPort);
      }

      //写入到json文件
      auto retWriteJson = Config::saveToJsonFile(jsonName, docSave); 
      if (!retWriteJson.has_value())
      {
        cout<<"保存到json文件失败: " + retWriteJson.error()<<endl;;
        return;
      }
      else if (retWriteJson.value() == true)  cout<<"更新json文件OK"<<endl;
      return;
}

(4)将Document输出文本

// 将 Document 序列化为字符串
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
docSave.Accept(writer);
// 输出字符串到控制台
std::cout << buffer.GetString() << std::endl;
posted @ 2025-03-27 17:32  仰望星河Leon  阅读(53)  评论(0)    收藏  举报