Найти все ключи JSON - RapidJSON - PullRequest
       10

Найти все ключи JSON - RapidJSON

0 голосов
/ 11 апреля 2019

Мне нужно найти все ключи в kTypeNames [] с библиотекой rapidJSON. Пытаюсь перебрать все узлы, но я что-то упускаю; вот код:

#include <iostream>
#include <fstream>
#include <string>
#include <bits/stdc++.h>
#include <unistd.h>
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"

using namespace rapidjson;

using namespace std;

const char* kTypeNames[] = { "id", "text", "templ_text", "key" };

int main(int argc, char* argv[]) {

string line;
char json[65000];
std::ifstream file(argv[1]);
unsigned long i = 0;
if (file.is_open()) {
    while (!file.eof()) {
        file.get(json[i]);
        i++;
    }
    file.close();
} else {
    cout << "Unable to open file";
}

Document document;
document.Parse(json);
printf("\n\n\n\n*********Access values in document**********\n");

assert(document.IsObject());

for (auto Typename : kTypeNames) {
    if (document.HasMember(Typename)) {

        cout << "\n";
        cout << Typename << ":" << document[Typename].GetString()<< endl;
        cout << "\n";
    }
    else {
        cout << "\n None\n";
    }
 }

Не работает с вложенным JSON.

{
"node": {
    "text": "find this",
    "templ_text": "don't find",
    "ver": "don't find"
},
"ic": "",
"text": "also this",
"templ_text": "don't care",
"par": {
    "SET": {
        "vis": "<blabla>",
        "text": "keyFound",
        "templ_text": "don't need this"
    }
}
}

Это вывод:

None
text:also this
templ_text:don't care
None

Я бы хотел найти все "текстовые" клавиши Как я могу перебрать все узлы / документ json?

1 Ответ

1 голос
/ 11 апреля 2019

Код, который вы имеете, просто ищет список предопределенных ключей непосредственно в корне документа (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, который необходимо учитывать.

...