Извлечение данных из JSON документов
Путь GJSON — это синтаксис текстовой строки, описывающий шаблон поиска для быстрого извлечение значений из полей события содержащих данные в формате JSON.
Содержание:
- Формат выражения
- Общая информация
- Использование wildcard маски
- Символы экранирования
- Массивы
- Запросы
- Точка vs pipe
- Модификаторы
- Модификаторы аргументов
- Новый JSON как продукт нескольких выражений извлечения
- Литералы
Формат выражения
Путь (выражение) - это последовательность ключей, разделённых точкой.
Ключ может содержать специальные символы подстановки *
и ?
.
Для доступа к значению массива используйте индекс в качестве ключа.
Для получения количества элементов в массиве или для доступа к дочернему пути используйте символ #
.
Символы точка (.
) и подстановка (*
, ?
) могут быть экранированы символом \
.
Путь предназначен для простого представления в виде серии
компонентов, разделенных символом .
.
Наряду с символом .
есть еще несколько, которые имеют специальные
значения, включая |
, #
, @
, \
, *
, !
и ?
Пример
Исходный JSON
{
"name": {"first": "Tom", "last": "Anderson"},
"age":37,
"children": ["Sara","Alex","Jack"],
"fav.movie": "Deer Hunter",
"friends": [
{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
]
}
Общая информация
В большинстве случаев необходимо получить значения по имени объекта или индексу массива.
name.last "Anderson"
name.first "Tom"
age 37
children ["Sara","Alex","Jack"]
children.0 "Sara"
children.1 "Alex"
friends.1 {"first": "Roger", "last": "Craig", "age": 68}
friends.1.first "Roger"
Использование wildcard маски
В ключе могут содержаться специальные символы подстановки *
и ?
, где *
соответствует любому набору из нуля и более символов, а ? — любому одному символу.
child*.2 "Jack"
c?ildren.0 "Sara"
Символы экранирования
Условные обозначения, такие как .
, *
и ?
можно экранировать с помощью \
.
fav\.movie "Deer Hunter"
Для корректного экранирования символа \
при жестком кодировании пути в исходном коде, также необходимо убедиться, что он правильно экранирован.
val := gjson.Get(json, "fav\\.movie") // необходимо экранировать `\`
val := gjson.Get(json, `fav\.movie`) // нет необходимости экранировать `\`
let val = gjson::get(json, "fav\\.movie") // необходимо экранировать `\`
let val = gjson::get(json, r#"fav\.movie"#) // нет необходимости экранировать `\`
Массивы
Символ #
позволяет ра в массивах JSON.
Чтобы получить длину массива, Вы просто будете использовать #
сам по себе.
Символ #
позволяет работать с JSON массивами.
Чтобы получить длину массива, вам просто нужно использовать символ #
сам по себе.
friends.# 3
friends.#.age [44,68,47]
Запросы
Вы также можете запросить массив для первого совпадения, используя #(...)
, или
найти все совпадения с помощью #(...)#
. Запросы поддерживают операторы сравнения ==
, !=
, <
,
<=
, >
, >=
, а также операторы простого соответствия %
(как) и !%
(не как).
friends.#(last=="Murphy").first "Dale"
friends.#(last=="Murphy")#.first ["Dale","Jane"]
friends.#(age>45)#.last ["Craig","Murphy"]
friends.#(first%"D*").last "Murphy"
friends.#(first!%"D*").last "Craig"
Чтобы запросить значение не объекта в массиве, можно пропустить строку справа от оператора.
children.#(!%"**a**") "Alex"
children.#(%"**a**")# ["Sara","Jack"]
Вложенные запросы разрешены.
friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
Операторы тильда (~
) преобразуют значение к булеву типу перед сравнением. Поддерживаемые типы сравнений тильдой:
~true
: преобразует значения, похожие наtrue
, кtrue
;~false
: преобразует ложные и не существующие значения кtrue
null
: преобразуетnull
и не существующие значения кtrue
.*
(звездочка): преобразует любое существующее значение кtrue.
Например, используя следующий JSON:
{
"vals": [
{ "a": 1, "b": true },
{ "a": 2, "b": true },
{ "a": 3, "b": false },
{ "a": 4, "b": "0" },
{ "a": 5, "b": 0 },
{ "a": 6, "b": "1" },
{ "a": 7, "b": 1 },
{ "a": 8, "b": "true" },
{ "a": 9, "b": false },
{ "a": 10, "b": null },
{ "a": 11 }
]
}
Теперь Вы можете запросить все значения true(ish)
или false(ish)
:
vals.#(b==~true)#.a >> [1,2,6,7,8]
vals.#(b==~false)#.a >> [3,4,5,9,10,11]
«Последнее значение, которого не было, считается ложным.
Проверка на существование нулевого значения и явного значения:
vals.((b==NULL)).a >> [10, 11]
vals.(((b == NULL)) ).a >> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
vals.(!((b != NULL)).b).a >> 11»
Точка vs Pipe
Точка (.
) — это стандартный разделитель, но можно использовать и символ pipe (|
).
В большинстве случаев они дают одинаковые результаты.
Исключения — когда | используется после символа #
для массивов и запросов.
В тех случаях, когда | отличается от ., это происходит, когда оно используется после для массивов и запросов.
Вот несколько примеров:
friends.0.first "Dale"
friends|0.first "Dale"
friends.0|first "Dale"
friends|0|first "Dale"
friends|# 3
friends.# 3
friends.#(last="Murphy")# [{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
friends.#(last="Murphy")#.first ["Dale","Jane"]
friends.#(last="Murphy")#|first <non-existent>
friends.#(last="Murphy")#.0 []
friends.#(last="Murphy")#|0 {"first": "Dale", "last": "Murphy", "age": 44}
friends.#(last="Murphy")#.# []
friends.#(last="Murphy")#|# 2
Давайте разберем некоторые из них.
Применение выражения friends.#(last="Murphy")#
даёт следующий результат
[{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
Суффикс .first
будет обрабатывать путь first
для каждого элемента массива
before и вернёт результат:
["Dale","Jane"]
Но суффикс |first
на самом деле обрабатывает first
путь после
предыдущего результата. Поскольку предыдущий результат представляет собой массив, а не объект,
его невозможно обработать, поскольку first
не существует.
Тем не менее суффикс |0
возвращает
{"first": "Dale", "last": "Murphy", "age": 44}
Потому что 0
- это первый индекс предыдущего результата.
Модификаторы
Модификатор — это компонент пути, который выполняет пользовательскую обработку JSON.
Например, применение встроенного модификатора @reverse
в приведенном выше JSON вернёт инвертированный массив children
:
children.@reverse ["Jack","Alex","Sara"]
children.@reverse.0 "Jack"
Существуют следующие встроенные модификаторы:
@reverse
: - инвертировать массив или элементы объекта;@ugly
: - удаляет все пробелы из JSON;@pretty
: - делает JSON более удобочитаемым для человека;@this
: - возвращает текущий элемент; можно использовать для извлечения корневого элемента;@valid
: - проверяет что документ - валидный JSON;@flatten
: - преобразует массив в плоский список;@join
: - объединяет несколько объектов в один объект;@keys
: - возвращает массив ключей для объекта;@values
: - возвращает массив значений для объекта;@tostr
: - преобразует JSON в строку, обертывает строку JSON;@fromstr
: - преобразует строку из JSON, разворачивает строку JSON;@group
: - группирует массивы объектов (см. e4fc67c);@dig
: - позволяет искать значения в глубоких или произвольно вложенных документах JSON не указывая точный путь до элементов;
Модификаторы аргументов
Модификатор может принимать опциональный аргумент. Аргументом может быть действительный JSON объект или просто символы.
Например, модификатор @pretty
принимает в качестве аргумента JSON объект:
@pretty:{"sortKeys":true}
Это делает JSON красивым и упорядочивает все его ключи.
{
"age":37,
"children": ["Sara","Alex","Jack"],
"fav.movie": "Deer Hunter",
"friends": [
{"age": 44, "first": "Dale", "last": "Murphy"},
{"age": 68, "first": "Roger", "last": "Craig"},
{"age": 47, "first": "Jane", "last": "Murphy"}
],
"name": {"first": "Tom", "last": "Anderson"}
}
Новый JSON как продукт нескольких выражений извлечения
Можно соединять несколько путей в один, чтобы сформировать новый документ.
Если разделить запятыми пути между [...]
или {...}
, получится новый массив или объект соответственно.
Например, используя заданный мультипуть:
{name.first,age,"the_murphys":friends.#(last="Murphy")#.first}
мы выбрали имя, возраст и имя для друзей с фамилией "Murphy".
Обратите внимание, что можно предоставить необязательный ключ, в данном случае the_murphys
.
Это позволит принудительно назначить ключ значению.
В противном случае будет использоваться название фактического поля, в данном случае это first
.
Если имя определить невозможно, то используется _
.
В результате получается:
{"first":"Tom","age":37,"the_murphys":["Dale","Jane"]}
Литералы
При создании нового документа JSON с использованием нескольких выражений извлечения особенно полезно добавлять статические блоки JSON.
Литерал JSON начинается с символа объявления !
.
Например, для выражения:
{name.first,age,"company":!"Happysoft","employed":!true}
выбрано имя и возраст, к ним добавлены два новых поля:
company
и employed
.
Результат:
{"first":"Tom","age":37,"company":"Happysoft","employed":true}