iterate and retrieve nested object in JSON using rapidjson
First, let me provide credit to MiloYip at this link
Second-- here's what I did for my project:
rapidjson::Document document;// document holds a json document retrieved from a http GET request// I did not include all of that in this example. I am only showing// the part of iterating through a nested object and retrieving members.std::vector<std::string> symbols;// holds the values I retrieve from the json documentif (document.Parse<0>( symbol.c_str() ).HasParseError() ) Log() << "ERROR: encountered a JSON parsing error" << std::endl;else { // Get the nested object that contains the elements I want. // In my case, the nested object in my json document was results // and the values I was after were identified as "t" rapidjson::Value& results = document["results"]; assert(results.IsArray()); for (rapidjson::SizeType i = 0; i < results.Size(); i++) { // Store the value of the element in a vector. symbols.emplace_back(results[i]["t"].GetString());}
I think this is a pretty clean/efficient approach.
This is something I recently worked on:
void enter(const Value &obj, size_t indent = 0) { //print JSON treeif (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. All you have to do is pass a Value as such:
Value v = document.GetObject();Value& m= v;enter(m);
And you're done!
void parseRecursive(std::string scope , rapidjson::Value::ConstMemberIterator object , std::unordered_map<std::string, std::string>& values){ if (scope.empty()) { scope = object->name.GetString(); } else { scope = scope + "::" + object->name.GetString(); } auto inElement = scope + "::"; if (object->value.IsObject()) { for (auto it = object->value.MemberBegin(); it != object->value.MemberEnd(); ++it) { parseRecursive(scope, it, values); } } else if (object->value.IsDouble()) { values.emplace(inElement, std::to_string(object->value.GetDouble())); } else if (object->value.IsInt()) { values.emplace(inElement, std::to_string(object->value.GetInt())); } else { LOGW("Unsuported: " << inElement << object->name.GetString()); }}
And start with document: rapidjson::Document document;
for (auto it = document.MemberBegin(); it != document.MemberEnd(); ++it){ parseRecursive("", it, _values);}