zoukankan      html  css  js  c++  java
  • rapidjson常见使用示例

    目录

    目录 1

    1. 前言 2

    2. Move语意 2

    3. rapidjson::Document 2

    4. 内存泄漏 3

    5. 成员迭代器MemberIterator 4

    6. 数组迭代器ValueIterator 4

    7. #include头文件 5

    8. 示例1:解析一个字符串 5

    9. 示例2:构造一个json并转成字符串 7

    10. 示例3:修改一个已有的json字符串 8

    11. 示例4:读数组 8

    12. 示例5: Writer构造一个json,然后修改它,最后转成字符串 9

    13. 示例6: Document构造一个json,然后修改它,最后转成字符串 10

    14. 示例7: Document构造一个json,然后修改它,最后转成字符串 12

    15. 示例8:构造空对象和数组 12

    16. 示例9:删除数组元素 13

    17. 示例10:不转义中文 14

    18. 示例11schema使用示例 15

    19. 示例12schema完整示例 17

    20. FindMember整数值 18

    21. FindMember字符串值 18

    22. 遍历成员 18

    23. 遍历数组1:字符串数组 19

    24. 遍历数组2:一级对象数组 19

    25. 遍历数组3:两级对象数组 20

    26. 辅助函数1:任意类型都以字符串返回 20

    27. 辅助函数2:取int32_t 22

    28. 辅助函数3:取int64_t 22

    29. 辅助函数4:取uint32_t 23

    30. 辅助函数5:取uint64_t 23

    31. 辅助函数6:对象转字符串 24

    32. 辅助函数7:字符串转对象 24

    33. rapidjson的“坑” 25

    1. 前言

    rapidjson相比jsoncpp性能高出太多,使用接口一样的简单的。官方中文帮助文档:http://rapidjson.org/zh-cn/

    2. Move语意

    rapidjsonMove语意,请浏览

    http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#MoveSemantics

    示例:

    rapidjson::Value a(123);

    rapidjson::Value b(456);

    b = a; // a变成Null,b变成数字123,这样的做法是基于性能考虑

    除了上述示例的复制语句外,AddMember()PushBack()也采用了Move语意。深复制Value

    Value v1("foo");

    // Value v2(v1); // 不容许

    Value v2(v1, a); // 制造一个克隆,v1不变

    Document d;

    v2.CopyFrom(d, a); // 把整个document复制至v2,d不变

    rapidjson为了最大化性能,大量使用了浅拷贝,使用之前一定要了解清楚。如果采用了浅拷贝,特别要注意局部对象的使用,以防止对象已被析构了,却还在被使用。

    3. rapidjson::Document

    特别注意rapidjson::Document可以为object、array、number、string、boolean和null中任意一种类型只有为object时才可以调用HasMember等与object有关的方法

    #include <rapidjson/document.h>

    #include <rapidjson/error/en.h>

    #include <rapidjson/stringbuffer.h>

    #include <rapidjson/writer.h>

    #include <stdio.h>

    int main(int argc, char* argv[])

    {

        std::string str;

        rapidjson::Document doc;

        doc.Parse(argv[1]);

        if (doc.HasParseError())

            printf("parse error ");

            

        // 注意doc可为object, array, number, string, boolean, null中任意一种类型

        if (!doc.IsObject())

            printf("not object ");

        else

        {

            printf("parse ok ");

            if (doc.IsNumber())

            printf("%d ", doc.GetInt());

            

            // doc为object类型时,才能调用HasMember

            if (doc.HasMember("x"))

                printf("has x ");

            else

                printf("without x ");

        }

        return 0;

    }

    4. 内存泄漏

    两种使用,Rapidjson会产生内存泄漏:

    1) 重复使用Document对象

    重复使用Document可能导致内存泄漏,如下段代码即存在内存泄漏:

    #include <rapidjson/document.h>

    int main() {

      rapidjson::Document doc;

      for (int i=0; i<1000000; ++i) {

          std::string a = "{"b":1" + std::to_string(i) + "}";

          doc.Parse(a.c_str());

      }

      return 0;

    }

    参考:https://github.com/Tencent/rapidjson/issues/1333。解决办法:

    #include <rapidjson/document.h>

    int main() {

      rapidjson::Document doc;

      for (int i=0; i<1000000; ++i) {

          std::string a = "{"b":1" + std::to_string(i) + "}";

          doc.Parse(a.c_str());

          rapidjson::Document tmpdoc;

          doc.Swap(tmpdoc);

      }

      return 0;

    }

    2) 使用Value类型指针

    Document类型指针当Value类型指针使用,出现内存泄漏,原因是Value的析构不是虚拟的,打开-Wall编译器也不会告警

    5. 成员迭代器MemberIterator

    成员迭代器rapidjson::Value::MemberIterator实际指向GenericMember

    template <typename Encoding, typename Allocator>

    struct GenericMember {

        // 成员名,只能为string值

        GenericValue<Encoding, Allocator> name;

        // 成员值,可为各类类型,如字符串、数组、子对象等

        GenericValue<Encoding, Allocator> value;

    };

    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;

    class GenericMemberIterator {

        typedef GenericMember<Encoding,Allocator> PlainType;

        typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;

        typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;

        typedef GenericMemberIterator Iterator;

        // Pointer to (const) GenericMember

        typedef typename BaseType::pointer Pointer;

        Pointer ptr_; // raw pointer

        Pointer   operator->() const { return ptr_; }

    };

    6. 数组迭代器ValueIterator

    数组迭代器ValueIterator实际为GenericValue指针:

    typedef GenericValue* ValueIterator;

    typedef const GenericValue* ConstValueIterator;

    7. #include头文件

    // 需要#include的头文件:

    #include <rapidjson/document.h>

    #include <rapidjson/error/en.h>

    #include <rapidjson/stringbuffer.h>

    #include <rapidjson/writer.h>

    其中en为english的简写,定义了取出错信息的函数GetParseError_En(errcode)。

    8. 示例1:解析一个字符串

    1) 运行输出结果

    count=2

    name=zhangsan

    name=wangwu

    2) 示例代码

    void x1()

    {

        rapidjson::Document document; // 定义一个Document对象

        std::string str = "{"count":2,"names":["zhangsan","wangwu"]}";

        document.Parse(str.c_str()); // 解析,Parse()无返回值,也不会抛异常

        if (document.HasParseError()) // 通过HasParseError()来判断解析是否成功

        {

            // 可通过GetParseError()取得出错代码,

            // 注意GetParseError()返回的是一个rapidjson::ParseErrorCode类型的枚举值

            // 使用函数rapidjson::GetParseError_En()得到错误码的字符串说明,这里的En为English简写

            // 函数GetErrorOffset()返回出错发生的位置

            printf("parse error: (%d:%d)%s ", document.GetParseError(), document.GetErrorOffset(), rapidjson::GetParseError_En(document.GetParseError()));

        }

        else

        {

            // 判断某成员是否存在

            if (!document.HasMember("count") || !document.HasMember("names"))

            {

                printf("invalid format: %s ", str.c_str());

            }

            else

            {

                // 如果count不存在,则运行程序会挂,DEBUG模式下直接abort

                rapidjson::Value& count_json = document["count"];

                

                // 如果count不是整数类型,调用也会挂,DEBUG模式下直接abort

                // GetInt()返回类型为int

                // GetUint()返回类型为unsigned int

                // GetInt64()返回类型为int64_t

                // GetUint64()返回类型为uint64_t

                // GetDouble()返回类型为double

                // GetString()返回类型为char*

                // GetBool()返回类型为bool

                int count = count_json.GetInt();

                printf("count=%d ", count);

                

                // 方法GetType()返回枚举值: kNullType,kFalseType,kTrueType,kObjectType,kArrayType,kStringType,kNumberType

                // 可用IsArray()判断是否为数组,示例: { "a": [1, 2, 3, 4] }

                // 用IsString()判断是否为字符串值

                // 用IsDouble()判断是否为double类型的值,示例: { "pi": 3.1416 }

                // 用IsInt()判断是否为int类型的值

                // 用IsUint()判断是否为unsigned int类型的值

                // 用IsInt64()判断是否为int64_t类型的值

                // 用IsUint64()判断是否为uint64_t类型的值

                // 用IsBool()判断是否为bool类型的值

                // 用IsFalse()判断值是否为false,示例: { "t": true, "f": false }

                // 用IsTrue()判断值是否为true

                // 用IsNull()判断值是否为NULL,示例: { "n": null }

                // 更多说明可浏览:

                // https://miloyip.gitbooks.io/rapidjson/content/zh-cn/doc/tutorial.zh-cn.html

                const rapidjson::Value& names_json = document["names"];

                for (rapidjson::SizeType i=0; i<names_json.Size(); ++i)

                {

                    std::string name = names_json[i].GetString();

                    printf("name=%s ", name.c_str());

                }

            }

        }

    }

    9. 示例2:构造一个json并转成字符串

    1) 运行输出结果

    {"count":2,"names":[{"name":"zhangsan"},{"name":"wangwu"}]}

    2) 示例代码

    void x2()

    {

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        writer.StartObject();

        // count

        writer.Key("count");

        writer.Int(2);

        // 写4字节有符号整数: Int(int32_t x)

        // 写4字节无符号整数: Uint(uint32_t x)

        // 写8字节有符号整数: Int64(int64_t x)

        // 写8字节无符号整数: Uint64(uint64_t x)

        // 写double值: Double(double x)

        // 写bool值: Bool(bool x)

        // names

        writer.Key("names");

        writer.StartArray();

        writer.StartObject();

        writer.Key("name");

        writer.String("zhangsan");

        writer.EndObject();

        writer.StartObject();

        writer.Key("name");

        writer.String("wangwu");

        writer.EndObject();

        writer.EndArray();

        writer.EndObject();

        // 以字符串形式打印输出

        printf("%s ", buffer.GetString());

    }

    10. 示例3:修改一个已有的json字符串

    1) 运行输出结果

    {"name":"wangwu","age":22}

    2) 示例代码

    void x3()

    {

        rapidjson::Document document;

        std::string str = "{"name":"zhangsan","age":20}";

        document.Parse(str.c_str());

        rapidjson::Value& name_json = document["name"];

        rapidjson::Value& age_json = document["age"];

        std::string new_name = "wangwu";

        int new_age = 22;

        // 注意第三个参数是document.GetAllocator(),相当于深拷贝,rapidjson会分配一块内存,然后复制new_name.c_str(),

        // 如果不指定第三个参数,则是浅拷贝,也就是rapidjson不会分配一块内存,而是直接指向new_name.c_str(),省去复制提升了性能

        // 官方说明:

        // http://rapidjson.org/zh-cn/md_doc_tutorial_8zh-cn.html#CreateString

        name_json.SetString(new_name.c_str(), new_name.size(), document.GetAllocator());

        age_json.SetInt(new_age);

        // 转成字符串输出

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        document.Accept(writer);

        printf("%s ", buffer.GetString());

    }

    11. 示例4:读数组

    1) 运行输出结果

    zhangsan wangwu

    2) 示例代码

    void x4()

    {

        rapidjson::Document document;

        std::string str = "{"count":2,"names":[{"name":"zhangsan"},{"name":"wangwu"}]}";

        document.Parse(str.c_str());

        if (document.HasParseError())

        {

            printf("parse error: %d ", document.GetParseError());

        }

        else

        {

            rapidjson::Value& names_json = document["names"];

            for (rapidjson::SizeType i=0; i<names_json.Size(); ++i)

            {

                if (names_json[i].HasMember("name"))

                {

                    rapidjson::Value& name_json = names_json[i]["name"];

                    printf("%s ", name_json.GetString());

                }

            }

            printf(" ");

        }

    }

    12. 示例5: Writer构造一个json,然后修改它,最后转成字符串

    1) 运行输出结果

    {"count":2}

    {"count":8}

    2) 示例代码

    void x5()

    {

        rapidjson::StringBuffer buffer1;

        rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

        

        writer1.StartObject();

        writer1.Key("count");

        writer1.Int(2);    

        writer1.EndObject();

        printf("%s ", buffer1.GetString());

        // 转成Document对象

        rapidjson::Document document;

        document.Parse(buffer1.GetString());

        // 修改

        rapidjson::Value& count_json = document["count"];

        count_json.SetInt(8);

        

        // 转成字符串

        rapidjson::StringBuffer buffer2;

        rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2);

        document.Accept(writer2);

        printf("%s ", buffer2.GetString());

    }

    13. 示例6: Document构造一个json,然后修改它,最后转成字符串

    1) 运行输出结果

    {"count":3,"names":[{"id":1,"name":"zhangsan"}]}

    {"count":9,"names":[{"id":1,"name":"zhangsan"}]}

    2) 示例代码

    void x6()

    {

        rapidjson::Document document;

        std::string str = "{}"; // 这个是必须的,且不能为"",否则Parse出错

        document.Parse(str.c_str());

        // 新增成员count

        // AddMember第一个参数可以为字符串常,如“str”,不能为“const char*”和“std::string”,

        // 如果使用“const char*”,则需要使用StringRefType转换:StringRefType(str.c_str())

        document.AddMember("count", 3, document.GetAllocator());

        // 新增数组成员

        rapidjson::Value array(rapidjson::kArrayType);

        rapidjson::Value object(rapidjson::kObjectType); // 数组成员

        object.AddMember("id", 1, document.GetAllocator());

        object.AddMember("name", "zhangsan", document.GetAllocator());

        

        // 如果数组添加无名字的成员,定义Value时应当改成相应的类型,如:

        //rapidjson::Value value(rapidjson::kStringType);

        //rapidjson::Value value(rapidjson::kNumberType);

        //rapidjson::Value value(rapidjson::kFalseType);

        //rapidjson::Value value(rapidjson::kTrueType);

        //array.PushBack(value, document.GetAllocator());

        //效果将是这样:'array':[1,2,3,4,5]

        

        // 注意下面用法编译不过:

        //std::string str1 = "hello";

        //object.AddMember("name", str1.c_str(), document.GetAllocator());

        //const char* str2 = "hello";

        //object.AddMember("name", str2, document.GetAllocator());

        //

        // 下面这样可以:

        //object.AddMember("name", "hello", document.GetAllocator());

        //const char str3[] = "hello";

        //object.AddMember("name", str3, document.GetAllocator());

        //    

        //std::string str4 = "#####";

        //rapidjson::Value v(str4.c_str(), document.GetAllocator());

        //obj.AddMember("x", v, document.GetAllocator());

        // 上面两行也可以写在一行:

        //obj.AddMember("x", rapidjson::Value(str4.c_str(), document.GetAllocator()).Move(), document.GetAllocator());

        // 添加到数组中

        array.PushBack(object, document.GetAllocator());

        // 添加到document中

        document.AddMember("names", array, document.GetAllocator());

        // 转成字符串输出

        rapidjson::StringBuffer buffer1;

        rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

        document.Accept(writer1);

        printf("%s ", buffer1.GetString());

        

        // 修改值

        rapidjson::Value& count_json = document["count"];

        count_json.SetInt(9);

        // 再次输出

        rapidjson::StringBuffer buffer2;

        rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2);

        document.Accept(writer2);

        printf("%s ", buffer2.GetString());

    }

    14. 示例7: Document构造一个json,然后修改它,最后转成字符串

    1) 运行输出结果(不转义就输出)

    x7=>

    {"title":"u8D2Bu56F0u5B64u513Fu52A9u517B"}

    2) 示例代码

    void x7()

    {

        std::string root = "{}";

        rapidjson::Document document;

        document.Parse(root.c_str());

        std::string title = "u8D2Bu56F0u5B64u513Fu52A9u517B";

        document.AddMember("title", rapidjson::Value(title.c_str(), document.GetAllocator()).Move(), document.GetAllocator());

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<> > writer(buffer);

        // 如果上面一句改成普通的:

        // rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        // 则输出将变成:

        // x7=>

        // 贫困孤儿助养

        

        document.Accept(writer);

        printf("x7=> %s ", buffer.GetString());

    }

    15. 示例8:构造空对象和数组

    1) 运行输出结果

    {"age":{},"times":{},"names":[],"urls":[],"books":[]}

    {"age":6,"times":{},"names":[],"urls":[],"books":[]}

    2) 示例代码

    void x8()

    {

        rapidjson::Document document;

        document.Parse("{}"); // 这里换成document.SetObject()也可以

        // 下面为2种构造空对象的方法

        document.AddMember("age", rapidjson::Value(rapidjson::kObjectType).Move(), document.GetAllocator());

        document.AddMember("times", rapidjson::Value().SetObject(), document.GetAllocator());

        // 下面为2种构造空数组的方法

        document.AddMember("names", rapidjson::Value(rapidjson::kArrayType).Move(), document.GetAllocator());

        document.AddMember("urls", rapidjson::Value(rapidjson::kArrayType).Move(), document.GetAllocator());

        document.AddMember("books", rapidjson::Value().SetArray(), document.GetAllocator());

        rapidjson::StringBuffer buffer1;

        rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

        document.Accept(writer1);

        printf("%s ", buffer1.GetString());

        rapidjson::Value& age = document["age"];

        age.SetInt(6);

        rapidjson::StringBuffer buffer2;

        rapidjson::Writer<rapidjson::StringBuffer> writer2(buffer2);

        document.Accept(writer2);

        printf("%s ", buffer2.GetString());

    }

    16. 示例9:删除数组元素

    1) 运行输出结果

    { "names": [ {"name":"zhangsan","age":100}, {"name":"wangwu","age":90}, {"name":"xiaozhang","age":20} ]}

    {"names":[{"name":"zhangsan","age":100},{"name":"wangwu","age":90}]}

    2) 示例代码

    void x9()

    {

        std::string str = "{ "names": [ {"name":"zhangsan","age":100}, {"name":"wangwu","age":90}, {"name":"xiaozhang","age":20} ]}";

        

        rapidjson::Document document;

        document.Parse(str.c_str());

        

        rapidjson::Value& names_json = document["names"];

        for (rapidjson::Value::ValueIterator iter=names_json.Begin(); iter!=names_json.End();)

        {

            std::string name = (*iter)["name"].GetString();

            

            // 不要小张了

            if (name == "xiaozhang")

                iter = names_json.Erase(iter);

            else

                ++iter;

        }

        

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        document.Accept(writer);

        

        printf("%s ", str.c_str());

        printf("%s ", buffer.GetString());

    }

    17. 示例10:不转义中文

    1) 运行输出结果

    {"title":"贫困孤儿助养"}

    {"title":"u8D2Bu56F0u5B64u513Fu52A9u517B"}

    2) 示例代码

    //g++ -g -o b b.cpp -I/usr/local/thirdparty/rapidjson/include

    #include <rapidjson/document.h>

    #include <rapidjson/stringbuffer.h>

    #include <rapidjson/writer.h>

    #include <string>

    #include <stdio.h>

    int main()

    {

        std::string str = "{"title":"u8d2bu56f0u5b64u513fu52a9u517b"}";

        rapidjson::Document document;

        document.Parse(str.c_str());

        if (document.HasParseError())

        {

            printf("parse %s failed ", str.c_str());

            exit(1);

        }

        rapidjson::StringBuffer buffer1;

        rapidjson::Writer<rapidjson::StringBuffer> writer1(buffer1);

        document.Accept(writer1);

        printf("%s ", buffer1.GetString());

        rapidjson::StringBuffer buffer2;

        rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<> > writer2(buffer2);

        document.Accept(writer2);

        printf("%s ", buffer2.GetString());

        return 0;

    }

    18. 示例11schema使用示例

    jsonschema用来检验json数据,它也采用了json格式。

    1) 示例代码

    rapidjson::Document schema_document;

    schema_document.Parse(schema.c_str());

    if (!schema_document.HasParseError())

    {

        rapidjson::Document document;

        document.Parse(str.c_str());

        

        if (!document.HasParseError())

        {

            SchemaDocument schema(schema_document);

            SchemaValidator validator(schema);

            if (!document.Accept(validator))

            {

                 // 检验出错,输出错误信息

                 StringBuffer sb;

                 validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);

                 

                 printf("Invalid schema: %s ", sb.GetString());

                 printf("Invalid keyword: %s ", validator.GetInvalidSchemaKeyword());

                 

                 sb.Clear();

                 validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);

                 printf("Invalid document: %s ", sb.GetString());

            }

        }

    }

    2) 示例json

    {

        "id": 1,

        "name": "A green door",

        "price": 12.50,

        "tags": ["home", "green"]

    }

    3) 上段json对应的schema

    {

        "$schema": "http://json-schema.org/draft-04/schema#",

        "title": "Product",

        "description": "A product from Acme's catalog",

        "type": "object",

        

        "properties": {

            "id": {

                "description": "The unique identifier for a product",

                "type": "integer"

            },

            "name": {

                "description": "Name of the product",

                "type": "string"

            },

            "price": {

                "type": "number",

                "minimum": 0,

                "exclusiveMinimum": true

            },

            "tags": {

                "type": "array",

                "items": {

                    "type": "string"

                },

                "minItems": 1,

                "uniqueItems": true

            }

        },

        "required": ["id", "name", "price"]

    }

    title”和“description”是描述性的,可以不写。$schema也是可选的,依据的是《JSON Schema Draft v4》。

    19. 示例12schema完整示例

    #include <rapidjson/document.h>

    #include <rapidjson/schema.h>

    #include <rapidjson/stringbuffer.h>

    int main()

    {

        std::string str = "{"aaa":111,"aaa":222}"; // "{"aaa":111,"a":222}"

    #if 0

        std::string schema_str = "{"type":"object","properties":{"aaa":{"type":"integer"},"bbb":{"type":"string"}},"required":["aaa","bbb"]}";

    #else

        std::string schema_str = "{"type":"object","properties":{"aaa":{"type":"integer"},"bbb":{"type":"integer"}},"required":["aaa","bbb"]}";

    #endif

        printf("%s ", str.c_str());

        printf("%s ", schema_str.c_str());

        rapidjson::Document doc;

        rapidjson::Document schema_doc;

        schema_doc.Parse(schema_str.c_str());

        doc.Parse(str.c_str());

        rapidjson::SchemaDocument schema(schema_doc);

        rapidjson::SchemaValidator validator(schema);

        if (doc.Accept(validator))

        {

            printf("data ok ");

        }

        else

        {

            rapidjson::StringBuffer sb;

            validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);

            printf("Invalid schema: %s ", sb.GetString());

            printf("Invalid keyword: %s ", validator.GetInvalidSchemaKeyword());

            sb.Clear();

            validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);

            printf("Invalid document: %s ", sb.GetString());

        }

        return 0;

    }

    20. FindMember整数值

    int age;

    const rapidjson::Value::ConstMemberIterator iter =

        doc.FindMember("age");

    if (iter!=doc.MemberEnd() && iter->value.IsInt())

        age = iter->value.GetInt();

    21. FindMember字符串值

    std::string name;

    const rapidjson::Value::ConstMemberIterator iter =

        doc.FindMember("name");

    if (iter!=doc.MemberEnd() && iter->value.IsString())

        name.assign(iter->value.GetString(), iter->value.GetStringLength());

    22. 遍历成员

    rapidjson::Value value;

    。。。

    for (rapidjson::Value::ConstMemberIterator iter=value.MemberBegin();

        iter!=value.MemberEnd(); ++iter)

    {

        const rapidjson::Value& name_json = iter->name; // 这个必是字符串

        const rapidjson::Value& value_json = iter->value; // 这个可以为对象、数组等

        printf("%s ", name_json.GetString());

    }

    23. 遍历数组1:字符串数组

    // 示例数组:

    // {"k":["k1","k2","k3"]}

    rapidjson::Document doc;

    doc.Parse(str.c_str());

    const rapidjson::Value& k = doc["k"];

    // 遍历数组

    for (rapidjson::Value::ConstValueIterator v_iter=k.Begin();

        v_iter!=k.End(); ++v_iter)

    {

        // k1

        // k2

        // k3

        printf("%s ", (*v_iter).GetString());

    }

    24. 遍历数组2:一级对象数组

    // 数组示例:

    // {"h":[{"k1":"f1"},{"k2":"f2"}]}

    rapidjson::Document doc;

    doc.Parse(str.c_str());

    const rapidjson::Value& h = doc["h"];

    // 遍历数组

    for (rapidjson::Value::ConstValueIterator v_iter=h.Begin();

        v_iter!=h.End(); ++v_iter)

    {

        const rapidjson::Value& field = *v_iter;

        for (rapidjson::Value::ConstMemberIterator m_iter=field.MemberBegin();

            m_iter!=field.MemberEnd(); ++m_iter) // kf对

        {

            // k1 => f1

            // k2 => f2

            const char* key = m_iter->name.GetString();

            const char* value = m_iter->value.GetString();

            printf("%s => %s ", key, value);

            break;

        }

    }

    25. 遍历数组3:两级对象数组

    // 数组示例:

    // {"h":[{"k1":["f1","f2"]},{"k2":["f1","f2"]}]}

    rapidjson::Document doc;

    doc.Parse(str.c_str());

    const rapidjson::Value& h = doc["h"];

    // 遍历第一级数组

    for (rapidjson::Value::ConstValueIterator v1_iter=h.Begin();

        v1_iter!=h.End(); ++v1_iter)

    {

        const rapidjson::Value& k = *v1_iter; // k1,k2,k3

        // 成员遍历

        for (rapidjson::Value::ConstMemberIterator m_iter=k.MemberBegin();

            m_iter!=k.MemberEnd(); ++m_iter)

        {

            const char* node_name = m_iter->name.GetString();

            printf("hk: %s ", node_name);

                                

            const rapidjson::Value& node = m_iter->value;

            // 遍历第二级数组

            for (rapidjson::Value::ConstValueIterator v2_iter=node.Begin();

                v2_iter!=node.End(); ++v2_iter)  

            {

                const char* field = (*v2_iter).GetString();

                printf("field: %s ", field); // f1,f2,f3

            }

        }

    }

    26. 辅助函数1:任意类型都以字符串返回

    // 如果不存在,或者为数组则返回空字符串。

    std::string rapidjson_string_value(rapidjson::Value& value, const std::string& name)

    {

        if (!value.HasMember(name.c_str()))

            return std::string("");

        const rapidjson::Value& child = value[name.c_str()];

        if (child.IsString())

            return child.GetString();

        char str[100];

        if (child.IsInt())

        {

            snprintf(str, sizeof(str), "%d", child.GetInt());

        }

        else if (child.IsInt64())

        {

            // 为使用PRId64,需要#include <inttypes.h>,

            // 同时编译时需要定义宏__STDC_FORMAT_MACROS

            snprintf(str, sizeof(str), "%"PRId64, child.GetInt64());

        }

        else if (child.IsUint())

        {

            snprintf(str, sizeof(str), "%u", child.GetUint());

        }

        else if (child.IsUint64())

        {

            snprintf(str, sizeof(str), "%"PRIu64, child.GetUint64());

        }

        else if (child.IsDouble())

        {

            snprintf(str, sizeof(str), "%.2lf", child.GetDouble());

        }

        else if (child.IsBool())

        {

            if (child.IsTrue())

                strcpy(str, "true");

            else

                strcpy(str, "false");

        }

        else

        {

            str[0] = '';

        }

        return str;

    }

    27. 辅助函数2:取int32_t

    当为int32_t值或字符串实际为int32_t值时,返回对应的int32_t值,其它情况返回0

    // 当为int32_t值,或字符串实际为int32_t值时,返回对应的int32_t值,其它情况返回0

    int32_t rapidjson_int32_value(rapidjson::Value& value, const std::string& name)

    {

        if (!value.HasMember(name.c_str()))

            return 0;

        const rapidjson::Value& child = value[name.c_str()];

        if (child.IsInt())

        {

            return child.GetInt();

        }

        else if (child.IsString())

        {

            return atoi(child.GetString());

        }

        return 0;

    }

    28. 辅助函数3:取int64_t

    当为int64_t值,或字符串实际为int64_t值时,返回对应的int64_t值,其它情况返回0

    int64_t rapidjson_int64_value(rapidjson::Value& value, const std::string& name)

    {

        if (!value.HasMember(name.c_str()))

            return 0;

        const rapidjson::Value& child = value[name.c_str()];

        if (child.IsInt64())

        {

            return child.GetInt64();

        }

        else if (child.IsString())

        {

            return (int64_t)atoll(child.GetString());

        }

        return 0;

    }

    29. 辅助函数4:取uint32_t

    当为uin32_t值,或字符串实际为uin32_t值时,返回对应的uin32_t值,其它情况返回0

    uint32_t rapidjson_uint32_value(rapidjson::Value& value, const std::string& name)

    {

        if (!value.HasMember(name.c_str()))

            return 0;

        const rapidjson::Value& child = value[name.c_str()];

        if (child.IsUint())

        {

            return child.GetUint();

        }

        else if (child.IsString())

        {

            return (uint32_t)atoll(child.GetString());

        }

        return 0;

    }

    30. 辅助函数5:取uint64_t

    当为uin64_t值,或字符串实际为uin64_t值时,返回对应的uin64_t值,其它情况返回0

    uint64_t rapidjson_uint64_value(rapidjson::Value& value, const std::string& name)

    {

        if (!value.HasMember(name.c_str()))

            return 0;

        const rapidjson::Value& child = value[name.c_str()];

        if (child.IsUint64())

        {

            return child.GetUint64();

        }

        else if (child.IsString())

        {

            return (uint64_t)atoll(child.GetString());

        }

        return 0;

    }

    31. 辅助函数6:对象转字符串

    std::string& to_string(const rapidjson::Value& value, std::string* str)

    {

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        value.Accept(writer);

        str->assign(buffer.GetString(), buffer.GetSize());

        return *str;

    }

    std::string to_string(const rapidjson::Value& value)

    {

        std::string str;

        to_string(value, &str);

    #if __cplusplus < 201103L

        return str;

    #else

        return std::move(str);

    #endif // __cplusplus < 201103L

    }

    32. 辅助函数7:字符串转对象

    bool to_rapidjson(const std::string& str, rapidjson::Document* doc)

    {

        doc->Parse(str.c_str());

        return !doc->HasParseError();

    }

    void to_rapidjson(const std::string& str, rapidjson::Document& doc)

    {

        doc.Parse(str.c_str());

        if (doc.HasParseError())

            doc.Parse("{}");

    }

    33. rapidjson的“坑”

    使用不当,则会掉进“坑”里。下列代码在valgrind中运行时,会报大量错误,而且如果sub是在一个循环中被AddMember,则无法得到预期的结果。

    从现象看像是sub析构后仍在被使用,为验证这个推测,改成:rapidjson::Document* sub = new rapidjson::Document;,然后再使用不但valgrind不报错,而且循环使用也没问题,那么可以肯定AddMember是浅拷贝,这样一来使用就不方便了,除非还有深拷贝的调用方式。

    #include <rapidjson/schema.h>

    #include <rapidjson/document.h>

    #include <rapidjson/stringbuffer.h>

    #include <rapidjson/writer.h>

    #include <string>

    #include <vector>

    int main()

    {

        rapidjson::Document doc;

        doc.Parse("{}");

        { // 目的是让sub在printf时已无效

            rapidjson::Document sub;

            sub.Parse("{"name":"tom"}");

            doc.AddMember("sub", sub, doc.GetAllocator());

        }

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        doc.Accept(writer);

        printf("%s ", buffer.GetString());

        return 0;

    }

    上述代码在valgrind中跑,会报错大量如下这样的错误:

    ==30425== Invalid read of size 2

    ==30425==    at 0x804B008: rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::IsString() const (document.h:947)

    ==30425==    by 0x8051632: bool rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Accept<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u> >(rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>&) const (document.h:1769)

    ==30425==    by 0x80488CE: main (f.cpp:30)

    ==30425==  Address 0x428eb62 is 58 bytes inside a block of size 65,548 free'd

    ==30425==    at 0x4023329: free (vg_replace_malloc.c:473)

    ==30425==    by 0x804BC72: rapidjson::CrtAllocator::Free(void*) (allocators.h:79)

    ==30425==    by 0x804BDD7: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::Clear() (allocators.h:148)

    ==30425==    by 0x804BE2E: rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>::~MemoryPoolAllocator() (allocators.h:140)

    ==30425==    by 0x804BE5F: rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::Destroy() (document.h:2382)

    ==30425==    by 0x804BE7E: rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>::~GenericDocument() (document.h:2064)

    正确可以使用的写法:

    #include <rapidjson/schema.h>

    #include <rapidjson/document.h>

    #include <rapidjson/stringbuffer.h>

    #include <rapidjson/writer.h>

    #include <string>

    #include <vector>

    int main()

    {

        std::vector<rapidjson::Document*> subs;

        rapidjson::Document doc;

        doc.Parse("{}");

        {    

            // 注意,下面没有使用Document的默认构造,

            // 而是指定Allocator为其父的Allocator。

            // 如果存在多级Document,一定要统一使用根Document的Allocator,

            // 原因是Allocator分配的内存会随Document析构被释放掉!

            //

            // 如果不这样做,必须保证sub的生命在doc之后才结束。

            rapidjson::Document sub(&doc.GetAllocator());

            sub.Parse("{"name":"tom"}");

            doc.AddMember("sub", sub, doc.GetAllocator());

        }

        rapidjson::StringBuffer buffer;

        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

        doc.Accept(writer);

        printf("%s ", buffer.GetString());

        for (std::vector<rapidjson::Document*>::size_type i=0; i<subs.size(); ++i)

        {

            rapidjson::Document *sub_ptr = subs[i];

            delete sub_ptr;

        }

        subs.clear();

        return 0;

    }

  • 相关阅读:
    让你在PC上调试Web App,UC浏览器发布开发者版
    多态
    深入理解DIP、IoC、DI以及IoC容器
    设计模式之迪米特原则(LOD)(最少知识原则)
    设计模式之合成/聚合利用原则(CARP)
    设计模式之接口隔离原则(ISP)
    设计模式之依赖倒转原则(DIP)
    设计模式之里氏代换原则(LSP)
    OO设计原则
    SQL分页
  • 原文地址:https://www.cnblogs.com/aquester/p/10331346.html
Copyright © 2011-2022 走看看