RapidJSON入门:手把手教入门实例介绍

article/2025/10/4 8:38:33

RapidJSON优点

  • 跨平台
    编译器:Visual Studio、gcc、clang 等
    架构:x86、x64、ARM 等
    操作系统:Windows、Mac OS X、Linux、iOS、Android 等

  • 容易安装
    只有头文件的库。只需把头文件复制至你的项目中。

  • 独立、最小依赖
    不需依赖 STL、BOOST 等。
    只包含 <cstdio>, <cstdlib>, <cstring>, <inttypes.h>, <new>, <stdint.h>。

  • 没使用 C++ 异常、RTTI

  • 高性能
    使用模版及内联函数去降低函数调用开销。
    内部经优化的 Grisu2 及浮点数解析实现。
    可选的 SSE2/SSE4.2 支持。

RapidJSON教程

1、Value 及 Document

每个 JSON 值都储存为 Value 类,一个 Value 类可包含不同类型的值,而 Document 类则表示整个 DOM,它存储了一个 DOM 树的根 Value。
定义一个JSON字符串,把它解析至一个 Document:

#include "rapidjson/document.h"using namespace rapidjson;// ...const char* json = 
{"hello": "world","t": true ,"f": false,"n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]
}Document document;
document.Parse(json);
//JSON.parse()
//在接收服务器数据时一般是字符串。
//可以使用 JSON.parse() 将数据转换为 JavaScript 对象。

那么现在该 JSON 就会被解析至 document 中,成为一棵DOM 树:
在这里插入图片描述

2、查询Value

//根是一个 Object,验证它的类型
assert(document.IsObject());//查询一下根 Object 中有没有 "hello" 成员
//在此例中,"hello" 成员关联到一个 JSON String
assert(document.HasMember("hello"));
assert(document["hello"].IsString());
printf("hello = %s\n", document["hello"].GetString());
//打印结果:world//JSON True/False 值是以 bool 表示的。
assert(document["t"].IsBool());
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
//打印结果:true//JSON Null 值可用 IsNull() 查询。
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
//打印结果:null//JSON Number 类型表示所有数值
//然而,C++ 需要使用更专门的类型
assert(document["i"].IsNumber());
assert(document["i"].IsInt());// 在此情况下,IsUint()/IsInt64()/IsUint64() 也会返回 true
printf("i = %d\n", document["i"].GetInt());
//打印结果:i = 123
assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble());
//打印结果:pi = 3.1416// 使用引用来连续访问,方便之余还更高效。
const Value& a = document["a"];
assert(a.IsArray());
for (SizeType i = 0; i < a.Size(); i++) // 使用 SizeType 而不是 size_tprintf("a[%d] = %d\n", i, a[i].GetInt());
//打印结果:a[0] = 1
//         a[1] = 2
//         a[2] = 3
//         a[3] = 4//用迭代器去访问所有 Object 成员:
static const char* kTypeNames[] = 
{"Null", "False", "True", "Object", "Array", "String", "Number"
};//若我们不确定一个成员是否存在,便需要在调用 
//1、HasMember()
//2、operator[](const char*) 
//然而,这会导致两次查找
//更好的做法是调用 FindMember()
//它能同时检查成员是否存在并返回它的 Value
Value::ConstMemberIterator itr = document.FindMember("hello");
if (itr != document.MemberEnd())printf("%s\n", itr->value.GetString());
//打印结果:worldfor (Value::ConstMemberIterator itr = document.MemberBegin();itr != document.MemberEnd(); ++itr)
{printf("Type of member %s is %s\n",itr->name.GetString(), kTypeNames[itr->value.GetType()]);
}
//打印结果:Type of member hello is String
//         Type of member t is True
//         Type of member f is False
//         Type of member n is Null
//         Type of member i is Number
//         Type of member pi is Number
//         Type of member a is Array//当使用 C++11 功能时,你可使用范围 for 循环去访问 Object 内的所有成员。
for (auto& m : document.GetObject())printf("Type of member %s is %s\n",m.name.GetString(), kTypeNames[m.value.GetType()]);
//打印结果:Type of member hello is String
//         Type of member t is True
//         Type of member f is False
//         Type of member n is Null
//         Type of member i is Number
//         Type of member pi is Number
//         Type of member a is Array//比较两个 Value
//使用 == 及 != 去比较两个 Value
//当且仅当 两个 Value 的类型及内容相同,它们才当作相等
if (document["hello"] == document["n"]) /*...*/;    // 比较两个值
if (document["hello"] == "world") /*...*/;          // 与字符串字面量作比较
if (document["i"] != 123) /*...*/;                  // 与整数作比较
if (document["pi"] != 3.14) /*...*/;                // 与 double 作比较

JSON 只提供一种数值类型──Number。数字可以是整数或实数,而 C++ 提供多种整数及浮点数类型 当查询一个 Number 时,你可以检查该数字是否能以目标类型来提取:
查检提取
bool IsNumber()不适用
bool IsUint()unsigned GetUint()
bool IsInt()int GetInt()
bool IsUint64()uint64_t GetUint64()
bool IsInt64()int64_t GetInt64()
bool IsDouble()double GetDouble()

3、创建/修改Value

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

Document d; // Null
d.SetObject();Value v;    // Null
v.SetInt(10);//重载构造函数:
Value b(true);              // 调用 Value(bool)
Value i(-123);              // 调用 Value(int)
Value u(123u);              // 调用 Value(unsigned)
Value d(1.5);               // 调用 Value(double)
//Value(Type)
Value o(kObjectType);       // 调用 Value(空object)
Value a(kArrayType);        // 调用 Value(空array)

转移语义(Move Semantics)
在设计 RapidJSON 时,Value 赋值并不是把来源 Value 复制至目的 Value,而是把来源 Value 转移(move)至目的 Value,AddMember(), PushBack() 也采用转移语义。例如:

Value a(123);
Value b(456);
b = a;
// a 变成 Null,b 变成数字 123。
// 优点:提高性能Value o(kObjectType);
{Value contacts(kArrayType);// 把元素加进 contacts 数组。// ...o.AddMember("contacts", contacts, d.GetAllocator());// contacts 在这里变成 Null。它的析构是平凡的。
}

转移语义——临时值
有时候,想直接构造一个 Value 并传递给一个“转移”函数(如 PushBack()、AddMember())。由于临时对象是不能转换为正常的 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);   // 和上一行相同

创建 String
RapidJSON 提供两个 String 的存储策略。

  1. copy-string: 分配缓冲区,然后把来源数据复制至它。
  2. const-string: 简单地储存字符串的指针。
//把一个 copy-string 赋值时
//调用含有 allocator 的 SetString() 重载函数
Document document;
Value author;
char buffer[10];
int len = sprintf(buffer, "%s %s", "Milo", "Yip");
author.SetString(buffer, len, document.GetAllocator());
memset(buffer, 0, sizeof(buffer));
// 清空 buffer 后 author.GetString() 仍然包含 "Milo Yip"

对于字符指针,RapidJSON 需要作一个标记,代表它不复制也是安全的。可以使用 StringRef 函数:

const char * cstr = getenv("USER");
size_t cstr_len = ...;                 // 如果有长度
Value s;
// s.SetString(cstr);                  // 这不能通过编译
s.SetString(StringRef(cstr));          // 可以,假设它的生命周期安全,并且是以空字符结尾的
s = StringRef(cstr);                   // 上行的缩写
s.SetString(StringRef(cstr, cstr_len));// 更快,可处理空字符
s = StringRef(cstr, cstr_len);         // 上行的缩写

Array 类型的 Value 提供与 std::vector 相似的 API。注意,Reserve(…) 及 PushBack(…) 可能会为数组元素分配内存,所以需要一个 allocator。

Clear()
Reserve(SizeType, Allocator&)
Value& PushBack(Value&, Allocator&)
template <typename T> GenericValue& PushBack(T, Allocator&)
Value& PopBack()
ValueIterator Erase(ConstValueIterator pos)
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)

4、使用字符串缓冲器生成——writer

#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include <iostream>
#include <string>using namespace std;void Serialize_1()
{rapidjson::StringBuffer strBuf;rapidjson::Writer<rapidjson::StringBuffer> writer(strBuf);writer.StartObject();//1. 整数类型writer.Key("Int");writer.Int(1);//2. 浮点类型writer.Key("Double");writer.Double(12.0000001);//3. 字符串类型writer.Key("String");writer.String("This is a string");//4. 结构体类型writer.Key("Object");writer.StartObject();writer.Key("name");writer.String("qq849635649");writer.Key("age");writer.Int(25);writer.EndObject();//5. 数组类型//5.1 整型数组writer.Key("IntArray");writer.StartArray();//顺序写入即可writer.Int(10);writer.Int(20);writer.Int(30);writer.EndArray();//5.2 浮点型数组writer.Key("DoubleArray");writer.StartArray();for(int i = 1; i < 4; i++){writer.Double(i * 1.0);}writer.EndArray();//5.3 字符串数组writer.Key("StringArray");writer.StartArray();writer.String("one");writer.String("two");writer.String("three");writer.EndArray();//5.4 混合型数组//这说明了,一个json数组内容是不限制类型的writer.Key("MixedArray");writer.StartArray();writer.String("one");writer.Int(50);writer.Bool(false);writer.Double(12.005);writer.EndArray();//5.5 结构体数组writer.Key("People");writer.StartArray();for(int i = 0; i < 3; i++){writer.StartObject();writer.Key("name");writer.String("qq849635649");writer.Key("age");writer.Int(i * 10);writer.Key("sex");writer.Bool((i % 2) == 0);writer.EndObject();}writer.EndArray();writer.EndObject();string data = strBuf.GetString();cout << data << endl;
}
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"void Serialize_2()
{rapidjson::Document doc;doc.SetObject();rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();//1. 整型类型doc.AddMember("Int", 1, allocator);//2. 浮点类型doc.AddMember("Double", 12.00001, allocator);//3. 字符串类型//正确方式string str= "This is a string";rapidjson::Value str_value(rapidjson::kStringType);str_value.SetString(str.c_str(), str.size());if(!str_value.IsNull()){doc.AddMember("String", str_value, allocator);}/***    注:以下方式不正确,可能成功,也可能失败,因为字符串写入json要重新开辟内存,* 如果使用该方式的话,当数据是字符串常量的话是没问题的,如果为变量就会显示乱码,所* 以为保险起见,我们显式的分配内存(无需释放)*///doc.AddMember("String", str.data(), allocator);//4. 结构体类型rapidjson::Value object(rapidjson::kObjectType);object.AddMember("name", "qq849635649", allocator); //注:常量是没有问题的object.AddMember("age", 25, allocator);doc.AddMember("Object", object, allocator);//5. 数组类型//5.1 整型数组rapidjson::Value IntArray(rapidjson::kArrayType);IntArray.PushBack(10, allocator);IntArray.PushBack(20, allocator);IntArray.PushBack(30, allocator);doc.AddMember("IntArray", IntArray, allocator);//5.2 浮点型数组rapidjson::Value DoubleArray(rapidjson::kArrayType);DoubleArray.PushBack(1.0, allocator);DoubleArray.PushBack(2.0, allocator);DoubleArray.PushBack(3.0, allocator);doc.AddMember("DoubleArray", DoubleArray, allocator);//5.3 字符型数组rapidjson::Value StringArray(rapidjson::kArrayType);string strValue1 = "one";string strValue2 = "two";string strValue3 = "three";str_value.SetString(strValue1.c_str(), strValue1.size());StringArray.PushBack(str_value, allocator);str_value.SetString(strValue2.c_str(), strValue2.size());StringArray.PushBack(str_value, allocator);str_value.SetString(strValue3.c_str(), strValue3.size());StringArray.PushBack(str_value, allocator);doc.AddMember("StringArray", StringArray, allocator);//5.4 结构体数组rapidjson::Value ObjectArray(rapidjson::kArrayType);for(int i = 1; i < 4; i++){rapidjson::Value obj(rapidjson::kObjectType);obj.AddMember("name", "qq849635649", allocator);//注:常量是没有问题的obj.AddMember("age", i * 10, allocator);ObjectArray.PushBack(obj, allocator);}doc.AddMember("ObjectArray", ObjectArray, allocator);rapidjson::StringBuffer strBuf;rapidjson::Writer<rapidjson::StringBuffer> writer(strBuf);doc.Accept(writer);string data = strBuf.GetString();cout << data << endl;
}

http://chatgpt.dhexx.cn/article/URPKMGlX.shtml

相关文章

oracle listagg如何去重

listagg去重 去重思路&#xff1a;利用listagg会忽略null值的特点 按ENTITY_GROUP_RRN 分组&#xff0c;用 listagg 分别合并 EQPT_ID 与 STATION_ID &#xff0c;同时要求去重 表 T_TEST 数据如下&#xff1a; EQPT_IDENTITY_GROUP_RRNSTATION_IDTOOL-00110493721JITAI-1TO…

mysql listagg within_Oracle的 listagg() WITHIN GROUP ()函数使用

1.使用条件查询 查询部门为20的员工列表 -- 查询部门为20的员工列表 SELECT t.DEPTNO,t.ENAME FROM SCOTT.EMP t where t.DEPTNO 20 ; 效果&#xff1a; 2.使用 listagg() WITHIN GROUP () 将多行合并成一行 SELECT T .DEPTNO, listagg (T .ENAME, ,) WITHIN GROUP (ORDER …

listagg结果去重

最近在一个项目中用到了listagg方法&#xff0c;但是在组合结果中出现有重复的情况。默认的结果如下 于是我就写了一个方法对listagg的结果去重&#xff0c;也可以对该格式的字符串去重&#xff0c;方法如下 create or replace function listaggpure(targetStr varchar2,seper…

Oracle函数之listagg函数

语法 有点难以看懂&#xff0c;个人理解listagg是list aggregate的缩写&#xff08;错了勿喷&#xff09;&#xff0c;也就是列表总计&#xff0c;聚合的意思。 官方文档解释为&#xff1a; LISTAGG orders data within each group specified in the ORDER BY clause and then …

listagg()行转列函数

--基础数据 DROP TABLE "ZYH_TEST"; CREATE TABLE "ZYH_TEST" ("ID" NUMBER(19) NOT NULL ,"NAME" VARCHAR2(255 BYTE) ,"CREATETIME" DATE ,"SCORE" NUMBER ,"CLASSID" VARCHAR2(255 BYTE) )INSERT I…

oracle listagg支持,PostgreSQL行列转换(兼容oracle listagg)

oracle11g开始支持的listagg函数替代了wmconcat来实现行列转换的功能。 listagg函数的用法: oracle行列转换例子: —建表https://www.cndba.cn/foucus/article/3929https://www.cndba.cn/foucus/article/3929 SQL> create table b (id number,name varchar2(20)); Table c…

mysql listagg函数_SQLSERVER中的ListAGG

跃然一笑 MySQLSELECT FieldA , GROUP_CONCAT(FieldB ORDER BY FieldB SEPARATOR ,) AS FieldBs FROM TableName GROUP BY FieldA ORDER BY FieldA;Oracle&DB2SELECT FieldA , LISTAGG(FieldB, ,) WITHIN GROUP (ORDER BY FieldB) AS FieldBs FROM TableName GRO…

mysql listagg within_Oracle函数之LISTAGG

最近在学习的过程中&#xff0c;发现一个挺有意思的Oracle函数&#xff0c;它可实现对列值的拼接。下面我们来看看其具体用法。 最近在学习的过程中&#xff0c;发现一个挺有意思的Oracle函数&#xff0c;它可实现对列值的拼接。下面我们来看看其具体用法。 用法&#xff1a; 对…

listagg

1.创建数据表&#xff0c;准备测试数据 CREATE TABLE MK_STUDENT(ID NUMBER(18) NOT NULL,STU_NAME VARCHAR2(200),STU_SCORE VARCHAR2(50),PRIMARY KEY (ID) ); ALTER TABLE MK_STUDENT ADD KEMU VARCHAR2(200);INSERT INTO MK_STUDENT (ID,STU_NAME,STU_SCORE,KEMU) VALUES …

listagg( )详解

想象一个场景&#xff0c;现实生活中一个人有许多手机号已是常态&#xff0c;数据库中也会有类似的结构。 大家肯定想知道listagg()有什么样的效果&#xff1a; 案列分析 一个表中有许多数据&#xff0c;名字叫张三的有许多手机号。希望查询结果出来是分组且清晰。 select …

Oracle列转行函数 Listagg()详解

详解 listagg()函数可以实现多列记录聚合为一条记录&#xff0c;从而实现数据的压缩、致密化&#xff08;data densification&#xff09; 基本用法 像聚合函数一样&#xff0c;通过Group by语句&#xff0c;把每个Group的一个字段&#xff0c;拼接起来 LISTAGG(XXX,XXX) WI…

Oracle 中 LISTAGG 函数的介绍以及使用

LISTAGG 函数介绍 listagg 函数是 Oracle 11.2 推出的新特性。 其主要功能类似于 wmsys.wm_concat 函数&#xff0c; 即将数据分组后&#xff0c; 把指定列的数据再通过指定符号合并。LISTAGG 使用 listagg 函数有两个参数&#xff1a;1、 要合并的列名2、 自定义连接符号☆L…

矩阵乘以其矩阵转置求导-数学

20210703 矩阵论 https://zhuanlan.zhihu.com/p/288541909?utm_sourcewechat_session 矩阵运算法则 20210529 https://blog.csdn.net/Lisa_Ren_123/article/details/81983785 矩阵转置求导 https://jingyan.baidu.com/article/da1091fb69f0b7027849d612.html

matlab中怎么求矩阵的转置

第一步我们首先需要知道matlab中矩阵后面加单引号是共轭转置&#xff0c;加点和单引号是转置&#xff0c;如下图所示&#xff1a; matlab中怎么求矩阵的转置 第二步在matlab命令行窗口中输入“ A[1 2 4;5 6 7]”&#xff0c;如下图所示&#xff1a; matlab中怎么求矩阵的转…

矩阵的转置等于矩阵的逆

http://zhidao.baidu.com/question/334500638.html 百度知道三个回答 矩阵A的转置矩阵A^T等于A的逆矩阵A^-1 那么AA^TAA^-1E 设A(α1&#xff0c;α2&#xff0c;α3&#xff0c;...&#xff0c;αn)^T&#xff0c;其中αi为n维列向量&#xff0c; 那么A^T(α1&#xff0c;α2&…

矩阵转置运算简单总结

矩阵转置的运算规律&#xff1a; &#xff08;1&#xff09;; &#xff08;2&#xff09;; &#xff08;3&#xff09;; &#xff08;4&#xff09;; &#xff08;5&#xff09;

矩阵的转置

稀疏矩阵&#xff1a; 当一个矩阵中的很多元素都是零&#xff0c;而且非零元素的分布没有规律时&#xff0c;该矩阵称为稀疏矩阵。 稀疏矩阵的压缩存储方法&#xff1a; 从稀疏矩阵的概念&#xff0c;我们可以知道&#xff0c;稀疏矩阵的大多元素都是零。所以&#xff0c;我们只…

转置矩阵,逆矩阵和倒转置矩阵

单位矩阵&#xff1a; 转置矩阵(transpose matrix) 在线性代数中&#xff0c;矩阵A的转置是另一个矩阵AT&#xff08;也写做Atr, tA或A′&#xff09;由下列等价动作建立: 把A的横行写为AT的纵列把A的纵列写为AT的横行 形式上说&#xff0c;m n矩阵A的转置是n m矩阵 for 。…