JSONPath Tutorial: Query JSON Like a Pro

Master JSONPath syntax with practical examples. Learn every operator, filter expression, and real-world query pattern to extract data from complex JSON structures.

Команда JSONTechFebruary 1, 202511 min read

Что такое JSONPath?

JSONPath — это язык запросов для JSON, аналогичный тому, что XPath делает для XML. Он позволяет вам заглянуть в сложную структуру JSON и извлечь именно те данные, которые вам нужны, используя лаконичный синтаксис выражений. Вместо того чтобы писать циклы и условные операторы для поиска по вложенным объектам и массивам, вы пишете одно выражение пути, например $.store.book[?(@.price < 10)].title, и получаете все названия книг стоимостью менее десяти долларов.

Стефан Гесснер представил JSONPath в 2007 году, и с тех пор он стал де-факто стандартом среди языков и инструментов. Если вы работаете с REST API, конфигурационными файлами или любыми нетривиальными данными JSON, JSONPath сэкономит вам значительное время.

JSONPath vs. XPath: Быстрое Сравнение

Если вы уже знаете XPath, JSONPath будет вам знаком. Ключевое отличие заключается в том, что JSON имеет более простую модель данных — объекты и массивы вместо элементов, атрибутов и пространств имен. Вот как они сравниваются:

КонцепцияXPathJSONPath
Корень/$
Ребенок/child.child или ['child']
Рекурсивный спуск//..
Шаблон**
Индекс массива[1] (с 1)[0] (с 0)
Фильтр[predicate][?(expression)]

Полная Справка по Операторам JSONPath

Каждое выражение JSONPath начинается с корня $ и соединяет операторы для более глубокого навигации. Вот все операторы, которые вам нужно знать:

ОператорОписаниеПример
$Корневой объект или массив$ — весь документ
.keyРебенок по имени (точечная нотация)$.store.name
['key']Ребенок по имени (скобочная нотация)$['store']['name']
..Рекурсивный спуск — ищет всех потомков$..price — каждое поле "price"
*Шаблон — все члены объекта или массива$.store.*
[n]Индекс массива (с 0)$.items[0]
[start:end]Срез массива (конечный индекс не включен)$.items[0:3] — первые три элемента
[start:end:step]Срез массива с шагом$.items[::2] — каждый второй элемент
[n,m]Несколько индексов массива$.items[0,2,4]
[?()]Выражение фильтра$.items[?(@.price > 10)]
@Текущий узел (используется внутри фильтров)@.name == 'Alice'

Пример JSON для Наших Примеров

Мы будем использовать этот JSON-документ на протяжении всего учебника. Он представляет собой ответ API небольшого книжного магазина:

{
  "store": {
    "name": "TechBooks Online",
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95,
        "inStock": true
      },
      {
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99,
        "inStock": false
      },
      {
        "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99,
        "inStock": true
      },
      {
        "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99,
        "inStock": true
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

Практические Примеры JSONPath

1. Получить Название Магазина

$.store.name

Результат:

"TechBooks Online"

2. Получить Все Названия Книг

$.store.book[*].title

Результат:

[
  "Sayings of the Century",
  "Sword of Honour",
  "Moby Dick",
  "The Lord of the Rings"
]

3. Получить Первую Книгу

$.store.book[0]

Результат: весь объект первой книги.

4. Получить Последнюю Книгу

$.store.book[-1]

Отрицательные индексы считаются с конца. -1 дает вам последний элемент.

5. Срез: Первые Две Книги

$.store.book[0:2]

Возвращает книги с индексами 0 и 1. Конечный индекс не включен, как в slice() Python и JavaScript.

6. Получить Все Цены во Всём Документе

$..price

Результат:

[8.95, 12.99, 8.99, 22.99, 19.95]

Оператор рекурсивного спуска .. находит каждое поле price независимо от глубины — включая цену велосипеда.

7. Фильтр: Книги Стоимостью Менее $10

$.store.book[?(@.price < 10)]

Возвращает две книги, стоимостью 8.95 и 8.99. Символ @ ссылается на текущий элемент, который оценивается.

8. Фильтр: Книги, У Которых Есть ISBN

$.store.book[?(@.isbn)]

Возвращает только "Моби Дика" и "Властелина колец".

9. Фильтр: Художественные Книги В Наличии

$.store.book[?(@.category == 'fiction' && @.inStock == true)]

Вы можете комбинировать условия с помощью && (и) и || (или).

10. Несколько Индексов

$.store.book[0,3]

Выбирайте конкретные элементы. Возвращает первую и четвертую книги.

11. Шаблон на Объекте

$.store.bicycle.*

Результат:

["red", 19.95]

Возвращает все значения объекта велосипеда.

12. Получить Авторов Дорогих Книг

$.store.book[?(@.price > 15)].author

Результат:

["J. R. R. Tolkien"]

Попробуйте сами: Вставьте приведенный выше пример JSON и поэкспериментируйте с этими выражениями в нашем JSONPath Tester.

Выражения Фильтра В Глубину

Выражения фильтра — это самая мощная часть JSONPath. Они находятся внутри [?()] и оценивают булевое условие для каждого элемента. Вот операторы, которые вы можете использовать:

ОператорЗначениеПример
==Равно@.status == 'active'
!=Не равно@.role != 'admin'
>Больше@.age > 18
>=Больше или равно@.score >= 90
<Меньше@.price < 50
<=Меньше или равно@.quantity <= 0
=~Соответствие регулярному выражению (некоторые реализации)@.name =~ /^J.*/
&&Логическое И@.price > 5 && @.price < 20
``

Один распространенный шаблон — это проверка существования свойства. Запись @.isbn без оператора сравнения возвращает true, если свойство существует и не равно null.

Реальные Сценарии

Извлечение Всех Электронных Почт из Ответа API

Предположим, вы получили ответ от API управления пользователями с глубоко вложенными контактными объектами:

{
  "users": [
    {
      "name": "Alice",
      "contacts": { "email": "alice@example.com", "phone": "555-0101" }
    },
    {
      "name": "Bob",
      "contacts": { "email": "bob@example.com", "phone": "555-0102" }
    }
  ]
}

Запрос: $..email

Результат:

["alice@example.com", "bob@example.com"]

Оператор рекурсивного спуска находит каждое поле email, независимо от того, где оно находится в иерархии.

Найти Продукты по Ценовому Диапазону

$.products[?(@.price >= 25 && @.price <= 100)]

Полезно при фильтрации ответов API на стороне клиента перед отображением списка продуктов.

Получить Вложенные Значения Конфигурации

$.config.database.connections[0].host

Погружайтесь в конфигурационные файлы, не пиша цепочку опционального доступа, как config?.database?.connections?.[0]?.host.

JSONPath в Разных Языках

JavaScript / Node.js

Пакет jsonpath-plus является самой популярной реализацией:

import { JSONPath } from "jsonpath-plus";

const data = { store: { book: [{ title: "Moby Dick", price: 8.99 }] } };
const titles = JSONPath({ path: "$.store.book[*].title", json: data });
console.log(titles); // ["Moby Dick"]

Python

Используйте jsonpath-ng для стандартной реализации:

from jsonpath_ng.ext import parse

data = {"store": {"book": [{"title": "Moby Dick", "price": 8.99}]}}
expr = parse("$.store.book[*].title")
matches = [match.value for match in expr.find(data)]
print(matches)  # ['Moby Dick']

Java

Библиотека Jayway JSONPath — это лучший выбор для проектов на JVM:

import com.jayway.jsonpath.JsonPath;

String json = "{\"store\":{\"book\":[{\"title\":\"Moby Dick\",\"price\":8.99}]}}";
List<String> titles = JsonPath.read(json, "$.store.book[*].title");
System.out.println(titles); // [Moby Dick]

Подводные Камни и Ограничения

JSONPath мощен, но есть несколько моментов, на которые стоит обратить внимание, прежде чем полагаться на него в производстве:

  • Нет стандартной спецификации (до недавнего времени). JSONPath был неформально определен, и разные библиотеки реализовали его с тонкими вариациями. IETF опубликовал RFC 9535 в 2024 году для стандартизации синтаксиса, но многие библиотеки все еще следуют оригинальной спецификации Гесснера. Всегда проверяйте документацию вашей библиотеки на поддерживаемые функции.
  • Поддержка регулярных выражений варьируется. Оператор =~ для регулярных выражений не поддерживается повсеместно. Библиотека Jayway для Java поддерживает его; многие библиотеки JavaScript — нет.
  • Нет операций записи. JSONPath является только для чтения. Вы не можете использовать его для изменения оригинального документа. Для мутаций вам нужен JSON Patch (RFC 6902) или ручное прохождение.
  • Производительность на огромных документах. Рекурсивный спуск (..) сканирует каждый узел в дереве. В документах с миллионами узлов это может быть медленно. Предпочитайте конкретные пути, когда важна производительность.
  • Несоответствие типов возвращаемых значений. Некоторые библиотеки возвращают одно значение для одиночных совпадений и массив для множественных совпадений. Другие всегда возвращают массив. Нормализуйте тип возвращаемого значения в вашем коде, чтобы избежать сюрпризов.
  • Специальные символы в ключах. Если ваши ключи JSON содержат точки, пробелы или другие специальные символы, используйте скобочную нотацию: $('my.key') вместо $.my.key.

JSONPath vs. jq

Вы можете задаться вопросом, как JSONPath сравнивается с jq, популярным командным процессором JSON. Краткий ответ: они решают схожие проблемы, но для разных аудиторий.

  • JSONPath предназначен для встраивания в код приложений. Он имеет поддержку библиотек на каждом основном языке и простой синтаксис запросов.
  • jq — это полноценный язык трансформации данных. Он может фильтровать, отображать, сокращать и изменять JSON. Он более мощный, но имеет более крутой кривую обучения и в основном используется в командной строке.

Для выполнения запросов данных внутри приложения JSONPath является прагматичным выбором. Для сценариев оболочки и конвейеров данных jq трудно превзойти.

Быстрая Справка

Что Вы ХотитеJSONPath
Весь документ$
Конкретное свойство$.user.name
Все элементы в массиве$.items[*]
Первый элемент$.items[0]
Последний элемент$.items[-1]
Диапазон элементов$.items[1:4]
Каждый n-й элемент$.items[::2]
Все поля "name" в любом месте$..name
Фильтр по значению$.items[?(@.price < 10)]
Фильтр по существованию$.items[?(@.discount)]
Несколько условий$.items[?(@.qty > 0 && @.active)]

Попробуйте сами: Откройте JSONPath Tester, чтобы выполнять запросы к вашим собственным данным JSON в реальном времени.

Похожие инструменты