2022 Zabbix中国峰会
2022 Zabbix中国峰会

4 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() 返回第一个名为'Object'的对象的价格字段。
$[?(@.name == 'Object')].history.first().length() 返回第一个名为'Object'的对象的历史数组元素个数。
$[?(@.price > 10)].length() 返回price大于10的对象个数。

参考: 从 JSONPath 中的 LLD 宏值中转义特殊字符.

支持的段

描述
<name> 按名称匹配对象属性。
* 匹配所有对象属性。
['<name>'] 按名称匹配对象属性。
['<name>', '<name>', ...] 通过任何列出的名称匹配对象属性。
[<index>] 按索引匹配数组元素。
[<number>, <number>, ...] 通过任何列出的索引匹配数组元素。
[*] 匹配所有对象属性或数组元素。
[<start>:<end>] 按定义的范围匹配数组元素:
<start> - 要匹配的第一个索引(包括)。 如果未指定,则匹配从头开始的所有数组元素。 如果为负数,则指定从数组末尾开始的偏移量。
<end> - 要匹配的最后一个索引(不包括)。 如果未指定,则匹配所有数组元素到最后。 如果为负数,则指定从数组末尾开始的偏移量。
[?(<表达式>)] 通过应用过滤表达式匹配对象/数组元素。

要查找忽略其根节点的匹配段(单独的段),它必须以 '..' 为前缀,例如 $..name$..['name'] 返回所有 'name' 属性的值。

可以通过在 JSONPath 中添加 ~ 后缀来提取匹配的元素名称。 它返回匹配对象的名称或匹配数组项的字符串格式的索引。 输出格式遵循与其他 JSONPath 查询相同的规则 - 确定路径结果按“原样”返回,不确定路径结果以数组形式返回。 但是,提取与明确路径匹配的元素的名称并没有多大意义——它是已知的。

过滤表达式

过滤表达式是一个中缀表示法中的算术表达式。

支持的操作数:

操作数 描述
"<text>"
'<text>'
文本常量。

示例:
'value: \\'1\\''
"value: '1'"
<number> 支持科学计数法的数值常量。

示例: 123
<jsonpath starting with $> 从输入文档根节点引用的 JSONPath 所指的值;仅支持确定的路径。

示例: $.object.name
<jsonpath starting with @> 从当前对象/元素引用的 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 Type Result
$.filters.price definite 10
$.filters.category definite fiction
$.filters['no filters'] definite no "filters"
$.filters definite {
"price": 10,
"category": "fiction",
"no filters": "no \"filters\""
}
$.books[1].title definite Sword of Honour
$.books[-1].author definite J. R. R. Tolkien
$.books.length() definite 4
$.tags[:] indefinite ["a", "b", "c", "d", "e" ]
$.tags[2:] indefinite ["c", "d", "e" ]
$.tags[:3] indefinite ["a", "b", "c"]
$.tags[1:4] indefinite ["b", "c", "d"]
$.tags[-2:] indefinite ["d", "e"]
$.tags[:-3] indefinite ["a", "b"]
$.tags[:-3].length() definite 2
$.books[0, 2].title indefinite ["Moby Dick", "Sayings of the Century"]
$.books[1]['author', "title"] indefinite ["Sword of Honour", "Evelyn Waugh"]
$..id indefinite [1, 2, 3, 4]
$.services..price indefinite [154.99, 5, 46, 24.5, 99.49]
$.books[?(@.id == 4 - 0.4 * 5)].title indefinite ["Sword of Honour"]

Note: This query shows that arithmetical operations can be used in queries; it can be simplified to $.books[?(@.id == 2)].title
$.books[?(@.id == 2 \|\| @.id == 4)].title indefinite ["Sword of Honour", "The Lord of the Rings"]
$.books[?(!(@.id == 2))].title indefinite ["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]
$.books[?(@.id != 2)].title indefinite ["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]
$.books[?(@.title =~ " of ")].title indefinite ["Sayings of the Century", "Sword of Honour", "The Lord of the Rings"]
$.books[?(@.price > 12.99)].title indefinite ["The Lord of the Rings"]
$.books[?(@.author > "Herman Melville")].title indefinite ["Sayings of the Century", "The Lord of the Rings"]
$.books[?(@.price > $.filters.price)].title indefinite ["Sword of Honour", "The Lord of the Rings"]
$.books[?(@.category == $.filters.category)].title indefinite ["Sword of Honour","Moby Dick","The Lord of the Rings"]
$.books[?(@.category == "fiction" && @.price < 10)].title indefinite ["Moby Dick"]
$..[?(@.id)] indefinite [
{
"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 indefinite ["Printing and assembling book in A5 format", "Rebinding torn book"]
$..id.length() definite 4
$.books[?(@.id == 2)].title.first() definite Sword of Honour
$..tags.first().length() definite 5

Note: $..tags is an indefinite path, so it returns an array of matched elements, i.e., [["a", "b", "c", "d", "e" ]]; first() returns the first element, i.e., ["a", "b", "c", "d", "e"]; length() calculates the length of the element, i.e.,5.
$.books[*].price.min() definite 8.95
$..price.max() definite 154.99
$.books[?(@.category == "fiction")].price.avg() definite 14.99
$.books[?(@.category == $.filters.xyz)].title indefinite Note: A query without match returns NULL for definite and indefinite paths.
$.services[?(@.active=="true")].servicegroup indefinite [1001,1000]

Note: Text constants must be used in boolean value comparisons.
$.services[?(@.active=="false")].servicegroup indefinite [1002]

Note: Text constants must be used in boolean value comparisons.
$.services[?(@.servicegroup=="1002")]~.first() definite restoration