輸入rapidjson錯誤信息

深度複製值

Document d;
v2.CopyFrom(d, a); // 把整個document複製至v2,d不變

rapidjson爲了最大化性能,大量使用了淺拷貝,使用之前一定要了解清楚。
如果採用了淺拷貝,特別要注意局部對象的使用,以防止對象已被析構了,卻還在被使用。

輸出rapidjson解析錯誤信息

#include "rapidjson/document.h"
#include <rapidjson/error/error.h>
#include <rapidjson/error/en.h>
#define ErrorName(DOC) printf("%s - %d: %s", GetParseError(), document.GetErrorOffset(),
#undefine ErrorName
void test()
{
    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\n", document.GetParseError(), document.GetErrorOffset(), rapidjson::GetParseError_En(document.GetParseError()));
    }

示例1:解析字符串

#include "rapidjson/document.h"
#include <rapidjson/error/error.h>
#include <rapidjson/error/en.h>
// 示例1:解析一個字符串
// 運行輸出結果:
// count=2
// name=zhangsan
// name=wangwu
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\n", document.GetParseError(), document.GetErrorOffset(), rapidjson::GetParseError_En(document.GetParseError()));
    }
    else
    {
        // 判斷某成員是否存在
        if (!document.HasMember("count") || !document.HasMember("names"))
        {
            printf("invalid format: %s\n", 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\n", 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                 printf("name=%s\n", name.c_str());
            }
        }
    }
}

示例2:構造一個json並轉成字符串

輸出結果:

 {"count":2,"names":[{"name":"zhangsan"},{"name":"wangwu"}]}
void x2()
{
    rapidjson::StringBuffer buffer;
    rapidjson::Writer 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\n", buffer.GetString());
}

示例3:修改一個已有的json字符串

運行輸出結果:
{"name":"wangwu","age":22}

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 writer(buffer);
    document.Accept(writer);
    printf("%s\n", buffer.GetString());
}

示例4:讀數組

運行輸出結果:
zhangsan wangwu

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\n", document.GetParseError());
    }
    else
    {
        rapidjson::Value& names_json = document["names"];
        for (rapidjson::SizeType i=0; i             {
                rapidjson::Value& name_json = names_json[i]["name"];
                printf("%s ", name_json.GetString());
            }
        }
        printf("\n");
    }
}

示例5: 以Writer構造一個json,然後修改它,最後轉成字符串

運行輸出結果:
{"count":2}{"count":8}

void x5()
{
    rapidjson::StringBuffer buffer1;
    rapidjson::Writer writer1(buffer1);
    
    writer1.StartObject();
    writer1.Key("count");
    writer1.Int(2);    
    writer1.EndObject();
    printf("%s\n", 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 writer2(buffer2);

    document.Accept(writer2);
    printf("%s\n", buffer2.GetString());
}

示例6: 以Document構造一個json,然後修改它,最後轉成字符串

// 運行輸出結果:

{"count":3,"names":[{"id":1,"name":"zhangsan"}]}
 {"count":9,"names":[{"id":1,"name":"zhangsan"}]}
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 writer1(buffer1);
    document.Accept(writer1);
    printf("%s\n", buffer1.GetString());
    
    // 修改值
    rapidjson::Value& count_json = document["count"];
    count_json.SetInt(9);


    // 再次輸出
    rapidjson::StringBuffer buffer2;
    rapidjson::Writer writer2(buffer2);
    document.Accept(writer2);
    printf("%s\n", buffer2.GetString());
}

示例7: 以Document構造一個json,然後修改它,最後轉成字符串

運行輸出結果:

x7=>
{"title":"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"}
void x7()
{
    std::string root = "{}";
    rapidjson::Document document;
    document.Parse(root.c_str());


    std::string title = "\u8D2B\u56F0\u5B64\u513F\u52A9\u517B";
    document.AddMember("title", rapidjson::Value(title.c_str(), document.GetAllocator()).Move(), document.GetAllocator());

    rapidjson::StringBuffer buffer;
    rapidjson::Writer writer(buffer);
    // 如果上面一句改成普通的:
    // rapidjson::Writer writer(buffer);
    // 則輸出將變成:
    // x7=>
    // 貧困孤兒助養
    
    document.Accept(writer);
    printf("x7=>\n%s\n", buffer.GetString());
}

示例8:構造空對象和數組

運行輸出結果:

{"age":{},"times":{},"names":[],"urls":[],"books":[]}
{"age":6,"times":{},"names":[],"urls":[],"books":[]}
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 writer1(buffer1);
    document.Accept(writer1);
    printf("%s\n", buffer1.GetString());

    rapidjson::Value& age = document["age"];
    age.SetInt(6);

    rapidjson::StringBuffer buffer2;
    rapidjson::Writer writer2(buffer2);
    document.Accept(writer2);
    printf("%s\n", buffer2.GetString());
}

刪除數組元素

示例運行輸出:

{ "names": [ {"name":"zhangsan","age":100}, {"name":"wangwu","age":90}, {"name":"xiaozhang","age":20} ]}
{"names":[{"name":"zhangsan","age":100},{"name":"wangwu","age":90}]}
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 writer(buffer);
    document.Accept(writer);
    
    printf("%s\n", str.c_str());
    printf("%s\n", buffer.GetString());
}


int main()
{
    x1();
    x2();
    x3();
    x4();
    x5();
    x6();
    x7();
    x8();
    x9();
    return 0;
}

示例:不轉義中文

運行輸出結果:

{"title":"貧困孤兒助養"}
{"title":"\u8D2B\u56F0\u5B64\u513F\u52A9\u517B"}
int main()
{
    std::string str = "{\"title\":\"\u8d2b\u56f0\u5b64\u513f\u52a9\u517b\"}";
    rapidjson::Document document;
    document.Parse(str.c_str());
    if (document.HasParseError())
    {
        printf("parse %s failed\n", str.c_str());
        exit(1);
    }
    rapidjson::StringBuffer buffer1;
    rapidjson::Writer writer1(buffer1);
    document.Accept(writer1);
    printf("%s\n", buffer1.GetString());

    rapidjson::StringBuffer buffer2;
    rapidjson::Writer writer2(buffer2);
    document.Accept(writer2);
    printf("%s\n", buffer2.GetString());

    return 0;
}

輔助函數

(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 ,
        // 同時編譯時需要定義宏__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] = '\0';
    }


    return str;
}

(2) 當爲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;
}

(3)當爲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;
}

(4)當爲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;
}

(5)當爲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;
}

schema使用示例:

json的schema用來檢驗json數據,它也採用了json格式。

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\n", sb.GetString());
             printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
             
             sb.Clear();
             validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
             printf("Invalid document: %s\n", sb.GetString());
        }
    }
}

示例json:

{
    "id": 1,
    "name": "A green door",
    "price": 12.50,
    "tags": ["home", "green"]
}

上段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》。

附1:rapidjson的“坑”

使用不當,則會掉進“坑”裏。下列代碼在valgrind中運行時,會報大量錯誤,而且如果sub是在一個循環中被AddMember,則無法得到預期的結果。
從現象看像是sub析構後仍在被使用,爲驗證這個推測,改成:rapidjson::Document* sub = new rapidjson::Document;,然後再使用不但valgrind不報錯,而且循環使用也沒問題,那麼可以肯定AddMember是淺拷貝,這樣一來使用就不方便了,除非還有深拷貝的調用方式。

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 writer(buffer);
    doc.Accept(writer);
    printf("%s\n", buffer.GetString());
    return 0;
}

上述代碼在valgrind中跑,會報錯大量如下這樣的錯誤:

==30425== Invalid read of size 2
==30425==    at 0x804B008: rapidjson::GenericValue::IsString() const (document.h:947)
==30425==    by 0x8051632: bool rapidjson::GenericValue::Accept >(rapidjson::Writer&) 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::Clear() (allocators.h:148)
==30425==    by 0x804BE2E: rapidjson::MemoryPoolAllocator::~MemoryPoolAllocator() (allocators.h:140)
==30425==    by 0x804BE5F: rapidjson::GenericDocument::Destroy() (document.h:2382)
==30425==    by 0x804BE7E: rapidjson::GenericDocument::~GenericDocument() (document.h:2064)

正確可以使用的寫法:

int main()
{
    std::vector 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 writer(buffer);
    doc.Accept(writer);
    printf("%s\n", buffer.GetString());


    for (std::vector::size_type i=0; i         delete sub_ptr;
    }
    subs.clear();


    return 0;
}

附2:rapidjson的schema特性使用示例

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\n", str.c_str());
    printf("%s\n", 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\n");
    }
    else
    {
        rapidjson::StringBuffer sb;
        validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);

        printf("Invalid schema: %s\n", sb.GetString());
        printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());

        sb.Clear();
        validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
        printf("Invalid document: %s\n", sb.GetString());
    }

    return 0;
}

類型注意事項

  1. rapidjson::Document可以爲object, array, number, string, boolean, null中任意一種類型
  2. 只有爲object時纔可以調用HasMember等與object有關的方法
int main(int argc, char* argv[])
{
    std::string str;
    rapidjson::Document doc;
    doc.Parse(argv[1]);
    if (doc.HasParseError())
        printf("parse error\n");
        
    // 注意doc可爲object, array, number, string, boolean, null中任意一種類型
    if (!doc.IsObject())
        printf("not object\n");
    else
    {
        printf("parse ok\n");
        if (doc.IsNumber())
        printf("%d\n", doc.GetInt());
        
        // doc爲object類型時,才能調用HasMember
        if (doc.HasMember("x"))
            printf("has x\n");
        else
            printf("without x\n");
    }


    return 0;
}

遍歷

遍歷成員

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\n", name_json.GetString());
}

遍歷數組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\n", (*v_iter).GetString());
}

遍歷數組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\n", key, value);
        break;
    }
}

遍歷數組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\n", 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\n", field); // f1,f2,f3
        }
    }
}

參考:
http://blog.chinaunix.net/uid-20682147-id-5206358.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章