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

Обзор

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

JSONPath состоит из сегментов, разделенных точками. Сегмент может быть либо простым словом, например имя значения JSON, либо *, либо более сложной конструкцией, заключённой в квадратные скобки [ ]. Разделительная точка перед сегментом скобок является опциональной, и её можно опустить. Например:

Путь Описание
$.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": "Checmical 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 неопределённый ["Sayings of the Century", "Moby Dick"]
$.books[1]['author', "title"] неопределённый ["Evelyn Waugh", "Sword of Honour"]
$..id неопределённый [1, 2, 3, 4]
$.services..price неопределённый [5, 154.99, 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)] неопределённый [
{
"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..[?(@.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 неопределённый [1000,1001] В сравнениях логических значений необходимо использовать текстовые константы.
$.services[?(@.active=="false")].servicegroup неопределённый [1002] В сравнениях логических значений необходимо использовать текстовые константы.
$.services[?(@.servicegroup=="1002")]~.first() определенный restoration