简体   繁体   English

使用 Rapidjson 检索 JSON 字符串中的嵌套对象

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

I need to retrieve a nested object inside a JSON string and I'm trying to do it using rapidjson.我需要在 JSON 字符串中检索嵌套对象,并且我正在尝试使用 Rapidjson 来完成它。 All I've found is how to retrieve arrays and basic types, but not sub-objects.我发现的只是如何检索数组和基本类型,而不是子对象。 I have created the following toy example which gives an error:我创建了以下玩具示例,该示例出现错误:

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;
    }
}

This is the output when executed:这是执行时的输出:

{ "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

How do I retrieve the inner object to continue my parsing?如何检索内部对象以继续解析? Thanks.谢谢。

Edit : What I need is to obtain the string representation of the inner object so I can call another function that is going to parse it.编辑:我需要的是获取内部对象的字符串表示,以便我可以调用另一个要解析它的函数。

Edit 2 : code that allows to retrieve the inner object as a string:编辑 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;
    }
}

You need to iterate through object's members manually, as GetString() only works on string members, while document["a"] is an Object.您需要手动遍历对象的成员,因为 GetString() 仅适用于字符串成员,而 document["a"] 是一个对象。 You need to iterate through that object's members using MemberIterator variable.您需要使用 MemberIterator 变量遍历该对象的成员。 I had no practice in C* for more than 15 years, so I can only give a general idea of how it should work:我有超过 15 年没有在 C* 方面实践过,所以我只能给出它应该如何工作的一般概念:

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

Also, you might want to look at Accept() method, it seems to return a JSON string of an object you give it.此外,您可能想查看 Accept() 方法,它似乎返回您提供的对象的 JSON 字符串。

If element is an object you can just access subproperties with []:如果 element 是一个对象,您可以使用 [] 访问子属性:

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

There is another great approach realized in rapidjson - JSON Pointers .在 Rapidjson 中实现了另一种很棒的方法 - JSON Pointers They have experimental status and according to the documentation shall be included in v.1.1.它们具有实验状态,根据文档应包含在 v.1.1 中。 Anyway this approach looks like XPATH for XML so to get nested value we can use syntax like无论如何,这种方法看起来像 XML 的 XPATH,因此为了获得嵌套值,我们可以使用类似的语法

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

I tried this functionality and in my opinion this is better than iterators.我尝试了这个功能,在我看来这比迭代器更好。

You can use a pointer to get the subobject:您可以使用指针来获取子对象:

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

an easy way to parse out nested objects inside json with rapidJson lib for c++..使用用于 C++ 的 RapidJson 库解析 json 中嵌套对象的简单方法..

Here is one example code to get the nested object as rapidjson::Document object.这是将嵌套对象作为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;
}

you can also use the pointer of Document:您还可以使用 Document 的指针:

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

and putting in the Value pointer and use it并放入值指针并使用它

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

This is something I recently worked on:这是我最近在做的事情:

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 
    }     
}
}

This can handle any type of JSON tree.这可以处理任何类型的 JSON 树。 All you have to do is pass a Value as such:您所要做的就是传递一个值:

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

And you're done!你完成了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM