簡體   English   中英

使用 Rapidjson 檢索 JSON 字符串中的嵌套對象

[英]Retrieving a nested object inside a JSON string using rapidjson

我需要在 JSON 字符串中檢索嵌套對象,並且我正在嘗試使用 Rapidjson 來完成它。 我發現的只是如何檢索數組和基本類型,而不是子對象。 我創建了以下玩具示例,該示例出現錯誤:

rapidjson::Document document;
std::string test =  " { \"a\": { \"z\" : 21 } } ";
std::cout << test << std::endl;
if ( document.Parse<0>( test.c_str() ).HasParseError() ) {
    std::cout << "Parsing error" << std::endl;
} else {
    if ( document[ "a" ].IsObject() ) {
        std::cout << "OK" << std::endl;
        std::cout << document[ "a" ].GetString() << std::endl;
    }
}

這是執行時的輸出:

{ "a": { "z" : 21 } } 
OK
JSONTest: ../rapidjson/document.h:441: const typename Encoding::Ch* rapidjson::GenericValue<Encoding, Allocator>::GetString() const [with Encoding = rapidjson::UTF8<char>, Allocator = rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>]: Assertion `IsString()' failed. Aborted

如何檢索內部對象以繼續解析? 謝謝。

編輯:我需要的是獲取內部對象的字符串表示,以便我可以調用另一個要解析它的函數。

編輯 2 :允許以字符串形式檢索內部對象的代碼:

rapidjson::Document document;
std::string test =  "{\"a\":{\"z\":21}} ";
if ( document.Parse<0>( test.c_str() ).HasParseError() ) {
    std::cout << "Error parsing" << std::endl;
} else {
    if ( document[ "a" ].IsObject() ) {
        rapidjson::StringBuffer sb;
        rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
        document[ "a" ].Accept( writer );
        std::cout << sb.GetString() << std::endl;
    }
}

您需要手動遍歷對象的成員,因為 GetString() 僅適用於字符串成員,而 document["a"] 是一個對象。 您需要使用 MemberIterator 變量遍歷該對象的成員。 我有超過 15 年沒有在 C* 方面實踐過,所以我只能給出它應該如何工作的一般概念:

for (MemberIterator m = document["a"].MemberBegin(); m != document["a"].MemberEnd(); ++m) {
    std::cout << m.name << " " << (m.IsNumber()?m.GetNumber():m.GetString()) << endl;
}

此外,您可能想查看 Accept() 方法,它似乎返回您提供的對象的 JSON 字符串。

如果 element 是一個對象,您可以使用 [] 訪問子屬性:

for (SizeType i = 0; i < layers.Size(); i++){   
  cout << layers[i]["name"].GetString() << endl;
}

在 Rapidjson 中實現了另一種很棒的方法 - JSON Pointers 它們具有實驗狀態,根據文檔應包含在 v.1.1 中。 無論如何,這種方法看起來像 XML 的 XPATH,因此為了獲得嵌套值,我們可以使用類似的語法

Value* tmpValue = GetValueByPointer(doc, "/result/job/blob");

我嘗試了這個功能,在我看來這比迭代器更好。

您可以使用指針來獲取子對象:

Value& a = *GetValueByPointer(document, "/a");
int z = a["z"].GetInt();
GenericObject doc2 = document["a"].GetObjectW();
int z = doc2["z"].GetInt();    

使用用於 C++ 的 RapidJson 庫解析 json 中嵌套對象的簡單方法..

這是將嵌套對象作為rapidjson::Document對象獲取的示例代碼。

Document get_nested(Document &d, std::string key){
rapidjson::StringBuffer buffer;
const char *key_ctr = key.c_str();

assert(d[key_ctr].IsObject());

rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
d[key_ctr].Accept(writer);

rapidjson::Document result;
rapidjson::StringStream s(buffer.GetString());
result.ParseStream(s);

return result;
}

您還可以使用 Document 的指針:

Document *document= new Document();
document->parse( test.c_str());

並放入值指針並使用它

Value *val= document;
val = &(*val)["a"];
val = &(*val)["z"];
cout << val->GetString();

這是我最近在做的事情:

void enter(const Value &obj, size_t indent = 0) { //print JSON tree

if (obj.IsObject()) { //check if object
    for (Value::ConstMemberIterator itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr) {   //iterate through object   
        const Value& objName = obj[itr->name.GetString()]; //make object value

        for (size_t i = 0; i != indent; ++i) //indent
            cout << " ";

        cout << itr->name.GetString() << ": "; //key name

        if (itr->value.IsNumber()) //if integer
            std::cout << itr->value.GetInt() ;

        else if (itr->value.IsString()) //if string
            std::cout << itr->value.GetString();


        else if (itr->value.IsBool()) //if bool
            std::cout << itr->value.GetBool();

        else if (itr->value.IsArray()){ //if array

            for (SizeType i = 0; i < itr->value.Size(); i++) {
                if (itr->value[i].IsNumber()) //if array value integer
                    std::cout << itr->value[i].GetInt() ;

                else if (itr->value[i].IsString()) //if array value string
                    std::cout << itr->value[i].GetString() ;

                else if (itr->value[i].IsBool()) //if array value bool
                    std::cout << itr->value[i].GetBool() ;

                else if (itr->value[i].IsObject()){ //if array value object
                    cout << "\n  ";
                    const Value& m = itr->value[i]; 
                    for (auto& v : m.GetObject()) { //iterate through array object
                        if (m[v.name.GetString()].IsString()) //if array object value is string
                            cout << v.name.GetString() << ": " <<   m[v.name.GetString()].GetString();
                        else //if array object value is integer
                            cout << v.name.GetString() << ": "  <<  m[v.name.GetString()].GetInt();

                       cout <<  "\t"; //indent
                    }
                }
                cout <<  "\t"; //indent
            }
        }

        cout << endl; 
        enter(objName, indent + 1); //if couldn't find in object, enter object and repeat process recursively 
    }     
}
}

這可以處理任何類型的 JSON 樹。 您所要做的就是傳遞一個值:

Value v = document.GetObject();
Value& m= v;
enter(m);

你完成了!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM