Получение вложенного объекта внутри строки JSON с помощью 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;
}
}
7 ответов
вам нужно перебирать члены объекта вручную, так как GetString () работает только со строковыми членами, в то время как document["a"] является объектом. Вам нужно перебирать элементы этого объекта, используя переменную MemberIterator. Я не имел практики в языке C* более 15 лет, поэтому я могу только дать общее представление о том, как это должно работать:
for (MemberIterator m = document["a"].MemberBegin(); m != document["a"].MemberEnd(); ++m) {
std::cout << m.name << " " << (m.IsNumber()?m.GetNumber():m.GetString()) << endl;
}
кроме того, вы можете посмотреть метод Accept (), он, кажется, возвращает строку JSON объекта, который вы ему даете.
если элемент является объектом, вы можете просто открыть вложенные с []:
for (SizeType i = 0; i < layers.Size(); i++){
cout << layers[i]["name"].GetString() << endl;
}
есть еще один отличный подход, реализованный в rapidjson -указатели JSON. Они имеют экспериментальный статус и, согласно документации, должны быть включены в в. 1.1. В любом случае этот подход выглядит как XPATH для XML, поэтому для получения вложенного значения мы можем использовать синтаксис, такой как
Value* tmpValue = GetValueByPointer(doc, "/result/job/blob");
я попробовал эту функцию и на мой взгляд это лучше, чем итераторы.
вы можете использовать указатель для получения подобъекта:
Value& a = *GetValueByPointer(document, "/a");
int z = a["z"].GetInt();
вы также можете использовать указатель документа:
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);
и вы сделали!