4. Поддержка функционала JSONPath

Обзор

В этом разделе описывается поддерживаемый функционал JSONPath в шагах предварительной обработки значений элементов данных.

JSONPath состоит из сегментов, разделенных точками. Сегмент может быть иметь форму либо простого слова, представляющего имя значения JSON, либо подстановочного символа (*), либо более замысловатой конструкции, заключённой в квадратные скобки. Точка перед сегментом скобок необязательна и может быть опущена.

Пример JSONPath Описание
$.object.name Возвращает содержимое object.name.
$.object['name'] Возвращает содержимое object.name.
$.object.['name'] Возвращает содержимое object.name.
$["object"]['name'] Возвращает содержимое object.name.
$.['object'].["name"] Возвращает содержимое object.name.
$.object.history.length() Возвращает количество элементов массива object.history.
$[?(@.name == 'Object')].price.first() Возвращает значение свойства price первого объекта по имени «Object».
$[?(@.name == 'Object')].history.first().length() Возвращает количество элементов массива history первого объекта с именем «Object».
$[?(@.price > 10)].length() Возвращает количество объектов с price больше чем 10.

Смотрите также: Экранирование специальных символов из значений LLD макросов в JSONPath.

Поддерживаемые сегменты

Сегмент Описание
<имя> Соответствие свойству объекта по имени.
* Соответствие всем свойствам объекта.
['<имя>'] Соответствие свойству объекта по имени.
['<имя>', '<имя>', ...] Соответствие свойству объекта по любому из перечисленных имён.
[<индекс>] Соответствие элементу массива по его индексу.
[<число>, <число>, ...] Соответствие элементу массива по любому из перечисленных индексов.
[*] Соответствие всем свойствам объекта или элементам массива.
[<начало>:<конец>] Соответствие элементам массива по заданному диапазону:
<начало> — первый индекс соответствия (включительно). Если не указан, соответствует всем элементам с самого начала. В случае отрицательного значения указывает начальное смещение от конца массива.
<конец> — последний индекс соответствия (не включая). Если не указан, соответствует всем элементам массива до самого конца. В случае отрицательного значения указывает начальное смещение от конца массива.
[?(<выражение>)] Соответствие объектов / элементов массива с применением выражения фильтра.

Чтобы найти соответствующий сегмент, игнорируя его происхождение (отсоединённый сегмент), его необходимо указывать с префиксом '..', например $..name или $..['name'] вернёт значения всех свойств «name».

Соответствующие имена элементов можно извлечь, добавив суффикс ~ к JSONPath. Он возвращает имя соответствующего объекта или индекс в строковом формате соответствующего элемента массива. Формат вывода следует тем же самым правилам, что и остальные запросы JSONPath — результаты определённого пути возвращаются «как есть», а результаты неопределённого пути возвращаются в виде массива. Однако, нет особого смысла извлекать имя соответствующего элемента определённого пути — оно и так уже известно.

Выражение фильтра

Выражение фильтра является арифметическим выражением в инфиксной нотации.

Поддерживаемые операнды:

Операнд Описание
"<текст>"
'<text>'
Текстовая константа.

Пример:
'value: \\'1\\''
"value: '1'"
<число> Числовая константа, поддерживая научное представление.

Пример: 123
<jsonpath начиная с $> Значение, указанное в JSONPath, начиная с корневого узла входного документа; поддерживаются только определённые пути.

Пример: $.object.name
<jsonpath начиная с @> Значение, указанное в JSONPath, начиная с текущего объекта/элемента; поддерживаются только определённые пути.

Пример: @.name

Поддерживаемые операторы:

Оператор Тип Описание Результат
- бинарный Вычитание Число
+ бинарный Сложение Число
/ бинарный Деление Число
* бинарный Умножение Число
== бинарный Равно Логический (1 или 0)
!= бинарный Не равно Логический (1 или 0)
< бинарный Меньше чем Логический (1 или 0)
<= бинарный Меньше чем или равно Логический (1 или 0)
> бинарный Больше чем Логический (1 или 0)
>= бинарный Больше чем или равно Логический (1 или 0)
=~ бинарный Соответствие регулярному выражению Логический (1 или 0)
! унарный Логическое НЕ Логический (1 или 0)
|| бинарный Логическое ИЛИ Логический (1 или 0)
&& бинарный Логическое И Логический (1 или 0)

Функции

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

Поддерживаемые функции:

Функция Описание Вход Выход
avg Среднее значение из чисел во входящем массиве Массив чисел Число
min Минимальное значение из чисел во входящем массиве Массив чисел Число
max Максимальное значение из чисел во входящем массиве Массив чисел Число
sum Сумма чисел во входящем массиве Массив чисел Число
length Количество элементов во входящем массиве Массив Число
first Первый элемент массива Массив Конструкция JSON (объект, массив, значение), в зависимости от содержимого входящего массива

Функциями агрегации JSONPath принимаются числовые значения в кавычках. Это означает, что значения преобразуются из строкового типа в числовой, если требуется агрегирование.

Несовместимые входные данные повлекут ошибку в функции.

Результирующее значение

JSONPath можно разделить на определённые и неопределённые пути. Определённый путь может вернуть только null или одно совпадение. Неопределённый путь может вернуть несколько совпадений: JSONPath с отсоединёнными несколькими именами / списком индексов, фрагментами массива или сегментами выражения. Однако, когда используется функция, JSONPath становится определённым, так как функции всегда имеют одиночное результирующее значение.

Определённый путь возвращает объект/массив/значение, на которое он ссылается. Напротив, неопределённый путь возвращает массив соответствующих объектов/массивов/значений.

Порядок свойств в результатах запроса JSONPath может не соответствовать порядку свойств исходного JSON'а из-за внутренних методов оптимизации. Например, JSONPath $.books[1]["author", "title"] может вернуть ["title", "author"]. Если сохранение исходного порядка свойств имеет важное значение, следует рассмотреть альтернативные методы обработки пост-запроса.

Правила форматирования пути

Пробельные символы (пробелы и символы табуляции) можно свободно использовать в сегментах с представлением в виде квадратных скобок и в выражениях, например: $[ 'a' ][ 0 ][ ?( $.b == 'c' ) ][ : -1 ].first( ).

Строки должны быть заключены в одинарные (') или двойные (") кавычки. Внутри строк одинарные или двойные кавычки (в зависимости от того, в какие кавычки заключена строка) и обратные косые черты (\) экранируются при помощи символа обратной косой черты (\).

Пример

{
         "books": [
           {
             "category": "reference",
             "author": "Nigel Rees",
             "title": "Sayings of the Century",
             "price": 8.95,
             "id": 1
           },
           {
             "category": "fiction",
             "author": "Evelyn Waugh",
             "title": "Sword of Honour",
             "price": 12.99,
             "id": 2
           },
           {
             "category": "fiction",
             "author": "Herman Melville",
             "title": "Moby Dick",
             "isbn": "0-553-21311-3",
             "price": 8.99,
             "id": 3
           },
           {
             "category": "fiction",
             "author": "J. R. R. Tolkien",
             "title": "The Lord of the Rings",
             "isbn": "0-395-19395-8",
             "price": 22.99,
             "id": 4
           }
         ],
         "services": {
           "delivery": {
             "servicegroup": 1000,
             "description": "Next day delivery in local town",
             "active": true,
             "price": 5
           },
           "bookbinding": {
             "servicegroup": 1001,
             "description": "Printing and assembling book in A5 format",
             "active": true,
             "price": 154.99
           },
           "restoration": {
             "servicegroup": 1002,
             "description": "Various restoration methods",
             "active": false,
             "methods": [
               {
                 "description": "Chemical cleaning",
                 "price": 46
               },
               {
                 "description": "Pressing pages damaged by moisture",
                 "price": 24.5
               },
               {
                 "description": "Rebinding torn book",
                 "price": 99.49
               }
             ]
           }
         },
         "filters": {
           "price": 10,
           "category": "fiction",
           "no filters": "no \"filters\""
         },
         "closed message": "Store is closed",
         "tags": [
           "a",
           "b",
           "c",
           "d",
           "e"
         ]
       }
JSONPath Тип Результат
$.filters.price определённый 10
$.filters.category определённый fiction
$.filters['no filters'] определённый no "filters"
$.filters определённый {
"price": 10,
"category": "fiction",
"no filters": "no \"filters\""
}
$.books[1].title определённый Sword of Honour
$.books[-1].author определённый J. R. R. Tolkien
$.books.length() определённый 4
$.tags[:] неопределённый ["a", "b", "c", "d", "e" ]
$.tags[2:] неопределённый ["c", "d", "e" ]
$.tags[:3] неопределённый ["a", "b", "c"]
$.tags[1:4] неопределённый ["b", "c", "d"]
$.tags[-2:] неопределённый ["d", "e"]
$.tags[:-3] неопределённый ["a", "b"]
$.tags[:-3].length() определённый 2
$.books[0, 2].title неопределённый ["Moby Dick", "Sayings of the Century"]
$.books[1]['author', "title"] неопределённый ["Sword of Honour", "Evelyn Waugh"]
$..id неопределённый [1, 2, 3, 4]
$.services..price неопределённый [154.99, 5, 46, 24.5, 99.49]
$.books[?(@.id == 4 - 0.4 * 5)].title неопределённый ["Sword of Honour"]

Примечание: Этот запрос показывает, что в запросах можно использовать математические операции. Конечно, этот запрос можно упростить до $.books[?(@.id == 2)].title
$.books[?(@.id == 2 \|\| @.id == 4)].title неопределённый ["Sword of Honour", "The Lord of the Rings"]
$.books[?(!(@.id == 2))].title неопределённый ["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]
$.books[?(@.id != 2)].title неопределённый ["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]
$.books[?(@.title =~ " of ")].title неопределённый ["Sayings of the Century", "Sword of Honour", "The Lord of the Rings"]
$.books[?(@.price > 12.99)].title неопределённый ["The Lord of the Rings"]
$.books[?(@.author > "Herman Melville")].title неопределённый ["Sayings of the Century", "The Lord of the Rings"]
$.books[?(@.price > $.filters.price)].title неопределённый ["Sword of Honour", "The Lord of the Rings"]
$.books[?(@.category == $.filters.category)].title неопределённый ["Sword of Honour","Moby Dick","The Lord of the Rings"]
$.books[?(@.category == "fiction" && @.price < 10)].title неопределённый ["Moby Dick"]
$..[?(@.id)] неопределённый [
{
"price": 8.95,
"id": 1,
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century"
},
{
"price": 12.99,
"id": 2,
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour"
},
{
"price": 8.99,
"id": 3,
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3"
},
{
"price": 22.99,
"id": 4,
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8"
}
]
$.services..[?(@.price > 50)].description неопределённый ["Printing and assembling book in A5 format", "Rebinding torn book"]
$..id.length() определённый 4
$.books[?(@.id == 2)].title.first() определённый Sword of Honour
$..tags.first().length() определённый 5

Примечание: $..tags неопределённый путь, поэтому он вернёт массив соответствующих элементов, т.е. [["a", "b", "c", "d", "e" ]]; first() вернёт первый элемент, т.е., ["a", "b", "c", "d", "e"]; length() вычислит его размер, т.е.5.
$.books[*].price.min() определённый 8.95
$..price.max() определённый 154.99
$.books[?(@.category == "fiction")].price.avg() определённый 14.99
$.books[?(@.category == $.filters.xyz)].title неопределённый Примечание: Запрос без совпадения вернёт NULL по определённому и неопределённому путям.
$.services[?(@.active=="true")].servicegroup неопределённый [1001,1000]

Примечание: В сравнениях логических значений необходимо использовать текстовые константы.
$.services[?(@.active=="false")].servicegroup неопределённый [1002]

Примечание: В сравнениях логических значений необходимо использовать текстовые константы.
$.services[?(@.servicegroup=="1002")]~.first() определённый restoration