RapidJSON入门:手把手教入门实例介绍
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 的存储策略。
- copy-string: 分配缓冲区,然后把来源数据复制至它。
- 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;
}
RapidJSON入门:手把手教入门实例介绍相关推荐
- 编程语言python入门-手把手教你从零开始用Python语言写爬虫程序
简单来说互联网是由一个个站点和网络设备组成的大网,我们通过浏览器访问站点,站点把HTML.JS.CSS代码返回给浏览器,这些代码经过浏览器解析.渲染,将丰富多彩的网页呈现我们眼前.如果我们把互联网比作 ...
- 新手入门手把手教你自学吉他,简单易懂看完就会
0基础初学者和新手小白入门自学吉他,很简单看完就会. 记得之前的文章中好像说过,关于吉他的结构和各项功能自己买本书或者查资料很容易就能找到,思来想去还是想写一篇关于吉他0基础新手入门的内容,正好自己也 ...
- PyQt5入门——手把手教你配置环境,快速上手GUI程序开发(Anaconda+PyCharm+Qt Designer+pyuic)
文章目录 引言 1. 安装python环境 1.1 安装anaconda 1.2 创建虚拟环境 2. 安装PyQt库 3. 安装pycharm 4. 在pycharm中配置PyQt 4.1 配置PyQ ...
- EGE 库入门——手把手教你从零完成 Flappy Bird 的编写
文章目录 运行效果图 什么是 EGE 安装 EGE 下载 找到你的 MinGW 复制文件 测试 开始吧 获取素材 下载 Apktool 下载一个 FlappyBird.apk 开始解析 前置知识 图片 ...
- 数据库入门——手把手教你安装数据库
1,网上搜索 SQL server 下载数据库 2,点击setup,安装--全新SQL server独立安装 3,勾选使用检查更新,点击下一步 4,默认选项不用管,直接点击下一步 5,点击下一步 6, ...
- Jmeter手把手教入门详细步骤,包括使用Jmeter进行Web,java模块测试
进入公司实习,老大教给我的第一个任务就是学习Jmeter,然后给组里的人讲...只能一面懵逼的开始学习. Jmeter是什么? 我就不用官方的定义了,简单来说就是一个免费开源的软件,用于给服务器进行各 ...
- C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据)
C# SuperSocket 手把手教你入门 傻瓜教程系列教程 C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据) C# SuperSocket 手把手教你 ...
- 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接
转自即时通讯网:http://www.52im.net/ 本文原作者:"水晶虾饺",原文由"玉刚说"写作平台提供写作赞助,原文版权归"玉刚说" ...
- c++从入门到精通_资料下载:从入门到精通,手把手教你学DSP
学习一个东西首先是了解它,比如DSP到底是什么?用在什么地方?怎么用?和单片机特点有那些相同与不同?开发需要注意什么?想了解清楚这些问题自然就清楚比较清楚的认识DSP.DSP,因为它是用来做数据处理, ...
最新文章
- python学习笔记-Day17(jinja2)
- 小菜的 VUE 使用技巧 持续更新
- tensorflow随笔-条件循环控制(4)
- Cpp 对象模型探索 / 类引入虚函数有哪些成本?
- Github 的清点对象算法
- 监督学习和无监督学习_一篇文章区分监督学习、无监督学习和强化学习
- getpriority java_Java Thread类的最终int getPriority()方法(带示例)
- python里none什么意思_Python 中None的用法
- offset,client,scroll的学习记录
- Confluence 6 审查日志的对象
- 《华为基本法》-笔记
- 可测空间、测度空间及σ-代数
- python捕捉warning_Python warnings.warn方法代码示例
- CentOS7如何升级ruby版本
- 一个开源「知乎日报」Android 客户端
- 极米H5值得入手吗?极米H5实际体验如何?画面对比实测
- html div 移除,js动态创建及移除div的方法
- RabbitMQ 开发时指定消息消费者的方式
- XT.COM直播间第109期 | CDT XT.COM AMA 专场
- 服务器硬盘插拔原理拆解,如何正确拆除在 ServeRAID适配器控制着的热插拔硬盘...