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_t
        printf("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());
//打印结果:world


 
for (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;
}
  • 11
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DSP 28335是一款常用于数字信号处理的芯片。要想从入门到精通,有一些基本的步骤和方法可以帮助你。下面是一个手把手教程开发攻略: 1. 学习基础知识:了解数字信号处理的基本概念和原理,学习DSP 28335的功能和架构,熟悉开发环境和工具。 2. 准备开发环境:安装并配置好DSP 28335开发套件,包括编译器、仿真器和调试器等工具。确保软硬件环境的正常运行。 3. 学习编程语言和开发工具:DSP 28335可以使用C语言进行编程,学习C语言的基础知识,并熟悉DSP特有的编程方法和指令集。掌握并熟练使用DSP开发工具,如Code Composer Studio等。 4. 学习DSP算法:了解常用的数字信号处理算法,例如滤波、变换、加解密等,掌握它们的原理和实现方法。学习如何在DSP 28335上实现这些算法。 5. 进行实验和项目:选择一些简单的实验和项目,例如音频处理、图像处理等,从简单和小规模开始,逐渐深入和扩展。通过实验和项目,不断提升自己的实践能力和解决问题的能力。 6. 参考资料和交流 :搜索并阅读DSP 28335的官方文档和资料,参考一些相关的书籍和教程。参加一些DSP相关的培训和学术交流活动,和其他开发者一起交流和学习。 7. 实践和总结:持续进行实践,尝试解决各种难题和挑战。不断总结和归纳经验,深化对DSP 28335的理解和掌握。 通过以上的步骤和方法,逐渐从入门到精通DSP 28335是可能的。然而,这个过程需要持续的学习和实践,需要不断的思考和探索,也需要耐心和毅力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值