Извлечь Json вложенных объектов по указанному c пути, используя поток ввода в Java - PullRequest
1 голос
/ 14 июля 2020

Я искал это некоторое время, и я также разработал что-то работающее, но мне интересно, есть ли фреймворк, который может облегчить мою жизнь.

Проблема проста, у меня есть Json InputStream, представляющий действительно большие полезные данные.

Я точно знаю, что эти полезные данные содержат массив объектов по известному пути, и я не хочу анализировать поток в памяти, вместо этого я хотел бы seek в файле по заданному пути и извлекать все объекты вложенного массива по одному как Map<String,Object>.

Пример:

{
   "store": {
      "book" : [

         {
           "isbn": "123",
           "author": "author",
           "title": "title",
         },
         ..... many more objects
      ]
   }
}

Мне нужно seek на $.store.book и извлеките отдельные вложенные объекты для дальнейшей обработки.

Я пробовал JsonPath (jayway), но метод синтаксического анализа, похоже, загружает все в память.

Затем я использовал Джексон с потоковой библиотекой, но решение, которое я получил, немного запутано. Есть ли более простой способ добиться этого?

Спасибо

Ответы [ 3 ]

0 голосов
/ 14 июля 2020

Вам нужны ParamTOFilterBy и FilterValue

Если вы настаиваете на использовании JSONPath , выбор будет выглядеть так:

JsonPath.read(jsonAsString, "$.store.book[?(@.ParamTOFilterBy==FilterValue)]")

This question говорит о фильтрации строки JSON. Мнение Мне нравится реализация Джексона в этом ответ

0 голосов
/ 15 июля 2020

Если интересующий вас массив JSON можно идентифицировать по указателю JSON, то эту работу может выполнить FilteringParserDelegate с JsonPointerBasedFilter . По сути, это потоковый анализатор, который пропускает вперед, пока цель не будет найдена. Затем вы можете продолжить потоковую передачу интересных токенов или выполнить привязку данных.

private static final ObjectMapper mapper = new ObjectMapper();
private static final JsonFactory factory = mapper.getFactory();

public static void processArrayElements(InputStream json, 
                                        JsonPointer pointerToArray,
                                        Consumer<Map<String, Object>> consumer)
    throws IOException {

  JsonParser parser = new FilteringParserDelegate(
      factory.createParser(json),
      new JsonPointerBasedFilter(pointerToArray), false, false);

  if (parser.nextToken() != JsonToken.START_ARRAY) {
    throw new IOException("Expected an array but found " + parser.currentToken());
  }

  while (parser.nextToken() != JsonToken.END_ARRAY) {
    consumer.accept(parser.readValueAs(Map.class));
  }
}

Чтобы распечатать книги:

JsonPointer bookArray = JsonPointer.compile("/store/book");
processArrayElements(json, bookArray, System.out::println);
0 голосов
/ 14 июля 2020

Один из вариантов - последовательно просматривать данные с ограниченной скоростью, например 512 или 1024 байта за раз. Затем вы можете проанализировать байты в закодированном формате, который, вероятно, является ISO-8859-1 или UTF-8. Затем вы можете прочитать все байты, пока не встретится какой-либо разделитель, вероятно, ], чтобы обозначить конец массива (надеюсь). Затем вы можете использовать Jackson или Gson для загрузки только этого массива объектов.

...