Извлечение JSON с использованием JsonPath с примерами

Научитесь извлекать информацию из документов JSON с помощью JsonPath от Jayway. JsonPath похож на Xpath для документов XML. В этом руководстве мы рассмотрим синтаксис JsonPath и несколько примеров, чтобы лучше понять его использование.

1. Настройка JsonPath

Включите JsonPath в приложение, если он еще не добавлен. Последнюю версию JsonPath можно найти в репозитории Maven.

<dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>2.7.0</version></dependency>

Обычно мы получаем документ JSON из ответа API или любого другого источника в приложении. Но в этом примере мы читаем файл JSON.

 {"виджет": {"отладка": "вкл","окно": {"title": "Информация о клиенте","имя": "client_info","ширина": 500,"высота": 500,"заполнение": [10,10,10,50],"местоположения" : [{ "имя": "заголовок", "отображение": "истина" },{ "имя": "нижний колонтитул", "отображение": "истина" },{ "имя": "боковая панель", "отображение": "ложь" }]}}}

Если мы пишем тест Junit, мы можем прочитать JSON в строку в методе setup().

static String json;@BeforeAllpublic static void setup() {try {URL fileUrl = TestJsonPathExpressions.class.getClassLoader().getResource("widget.json");File file = new File(fileUrl.getFile());json = new String(Files.readAllBytes(file.toPath()));} catch(Exception e) {e.printStackTrace();}}

2. Простой пример

Прежде чем углубляться в синтаксис, давайте начнем с простого примера того, как извлечь информацию из данного документа. В следующем примере мы извлекаем название виджета и проверяем ожидаемое значение.

@Testpublic void testGetWidgetTitle_ThenSuccess(){String widgetTitle = JsonPath.read(json, "$.widget.window.title");Assertions.assertEquals("Client Info", widgetTitle);}

3. Синтаксис JsonPath

3.1.Обозначения

JsonPath поддерживает две нотации для представления узлов: точка и скобка. В следующем примере оба выражения указывают на один и тот же узел:

  • $.widget.window.title //Точечная нотация
  • $['widget']['window']['title'] //Обозначение скобок

3.2 Операторы

JsonPath поддерживает множество операторов, которые можно использовать для представления определенных узлов или диапазонов в документе JSON.

  • $ представляет корневой узел. Все выражения пути начинаются с него.
  • @ представляет текущий обрабатываемый узел. Он используется с предикатом фильтра. В следующем примере мы находим все местоположения, где display имеет значение true.
@Testpublic void testGetDisplayLocations_ThenSuccess(){List<String> locations = JsonPath.read(json, "$.widget.window.locations[?(@.display == 'true')].name");Assertions.assertTrue(List.of("header", "footer").containsAll(locations));}
  • * представляет все узлы в текущей области. Например, следующее выражение возвращает все местоположения независимо от свойства display.
@Testpublic void testGetAllDisplayLocations_ThenSuccess(){List<String> locations = JsonPath.read(json, "$.widget.window.locations[*].name");Assertions.assertTrue(List.of("header", "footer", "sidebar").containsAll(locations));}
  • [start:end] разрезает элементы массива от начального до конечного индекса.
@Testpublic void testFirstDisplayLocation_ThenSuccess(){List<String> locations = JsonPath.read(json, "$.widget.window.locations[0,1].name");Assertions.assertTrue(List.of("header", "footer").containsAll(locations));}

3.3 Функции

JsonPath предоставляет встроенные функции для поддержки некоторых распространенных операций, таких как: sum(), min(), max(), avg(), stddev(), length(), keys(), concat(input) и append(input).

В следующем примере мы находим самые большие значения отступов для виджета.

@Testpublic void testLargestPadding_ThenSuccess(){Double largestPadding = JsonPath.read(json, "$.widget.window.padding.max()");Assertions.assertEquals(50, largestPadding);}

4. Предикаты JsonPath

Предикаты помогают фильтровать массив узлов на основе предоставленных условий. Это полезно, когда мы хотим извлечь только те элементы массива, которые соответствуют определенному критерию.

Мы уже рассматривали пример встроенного предиката в предыдущем разделе.

List<String> locations = JsonPath.read(json, "$.widget.window.locations[?(@.display == 'true')].name");

Давайте перепишем тот же предикат с классом com.jayway.jsonpath.Predicate. Обратите внимание на использование символа ? в 'locations[?]', который подразумевает местоположение предиката для применения.

@Testpublic void testGetTrueDisplayLocationsWithPredicate_ThenSuccess(){Predicate displayEnabled = new Predicate() {@Overridepublic boolean apply(PredicateContext ctx) {return ctx.item(Map.class).get("display").toString().equalsIgnoreCase("true");}};List<String> locations = JsonPath.read(json, "$.widget.window.locations[?].name", displayEnabled);Assertions.assertTrue(List.of("header", "footer").containsAll(locations));}

Обратите внимание, что мы можем передавать несколько предикатов и заполнителей в выражении. Когда указано несколько предикатов, они применяются в порядке, где количество заполнителей должно соответствовать количеству предоставленных предикатов. В следующем примере мы передаем два предиката widgetEnabled и displayEnabled.

JsonPath.read(json, "$.widget.window[?].locations[?].name", widgetEnabled, displayEnabled);

5. Индивидуальные конфигурации

Перечисление JsonPath Option предоставляет несколько параметров для настройки конфигурации по умолчанию:

  • Option.AS_PATH_LIST возвращает пути оценки вместо значений.
  • Option.DEFAULT_PATH_LEAF_TO_NULL возвращает null для отсутствующих узлов.
  • Option.ALWAYS_RETURN_LIST возвращает список, даже если выражение оценивает одно значение.
  • Option.SUPPRESS_EXCEPTIONS подавляет все исключения во время выполнения.
  • Option.REQUIRE_PROPERTIES требует свойства, определенные в пути, когда оценивается неопределенный путь.

Чтобы передать конфигурацию объекту JsonPath, используйте его метод using(). В следующем примере мы извлекаем одно значение, но оно возвращается как список.

@Testpublic void testConfiguration_ThenSuccess(){Configuration configuration = Configuration.builder().options(ALWAYS_RETURN_LIST, SUPPRESS_EXCEPTIONS).build();List<String> locations = JsonPath.using(configuration).parse(json).read("$.widget.window.locations[0].name");Assertions.assertTrue(List.of("header").containsAll(locations));}

6. Заключение

В этом руководстве по JsonPath мы научились устанавливать и настраивать JsonPath в соответствии с нашими потребностями. Мы изучили синтаксис JsonPath, включая нотации, символы и операторы с примерами. Мы также рассмотрели несколько примеров извлечения информации из документов JSON путем применения фильтров с использованием предикатов.

Исходный код на Github

Прокрутить вверх