Код, который вы имеете, просто ищет список предопределенных ключей непосредственно в корне документа (document.HasMember
- это не рекурсивный поиск!).
Вы можете просто рекурсивно циклически перемещаться по узлам документа,Например, для узлов объекта / карты вы выполняете циклы на итераторах MemberBegin()
и MemberEnd()
, аналогично std::map
или другим стандартным контейнерам.
for (auto i = node.MemberBegin(); i != node.MemberEnd(); ++i)
{
std::cout << "key: " << i->name.GetString() << std::endl;
WalkNodes(i->value);
}
Массив использует Begin()
и End()
,Затем, когда вы встречаете узел с «текстовым» членом, вы можете вывести значение этого узла (i->value
).
В качестве альтернативы, вместо использования Document
объекта DOM, вы можете сделать этос потоком парсера.Rapidjson использует для этого «push» API, где он вызывает методы, которые вы определяете в классе, когда сталкивается с каждым фрагментом JSON.В частности, он вызовет метод Key
.
class MyHandler : public BaseReaderHandler<UTF8<>, MyReader> {
bool Key(const char* str, SizeType length, bool copy)
{
std::cout << "Key: " << str << std::endl;
}
...
};
MyHandler handler;
rapidjson::Reader reader;
rapidjson::StringStream ss(json);
reader.Parse(ss, handler);
Это немного усложняется, вы захотите установить флаг некоторых сортов, а затем вывести обратный вызов следующего значения после.
class MyHandler : public BaseReaderHandler<UTF8<>, MyReader> {
bool Key(const char* str, SizeType length, bool copy)
{
isTextKey = strcmp(str, "text") == 0; // Also need to set to false in some other places
return true;
}
bool String(const char* str, SizeType length, bool copy)
{
if (isTextKey) std::cout << "text string " << str << std::endl;
return true;
}
...
bool isTextKey = false;
};
Также помните, что JSON допускает нулевое значение в строке \0
, поэтому также имеют параметры размера и члены, а также Unicode.Таким образом, чтобы полностью поддерживать любой документ JSON, который необходимо учитывать.