JMESPath规范

本文档描述jmespath的规范。

如果您想了解JMESPath语言,请参阅 JMESPath教程 以及 JMESPath示例 页。

在规范中,通过使用 search 功能。此函数的语法为:

search(<jmespath expr>, <JSON document>) -> <return value>

为了简单起见,jmespath表达式和JSON文档不被引用。例如::

search(foo, {"foo": "bar"}) -> "bar"

对JSON文档应用JMESPath表达式的结果将 总是 得到有效的JSON,前提是在评估过程中没有错误。结构化数据输入,结构化数据输出。

这也意味着,除了JMESPath表达式类型之外,JMESPath只支持JSON支持的相同类型:

  • 数字(JSON中的整数和双精度浮点格式)

  • 一串

  • 布尔 (truefalse

  • 数组(一个有序的值序列)

  • 对象(键值对的无序集合)

  • 无效的

表达式类型在 函数表达式 部分。

实现可以将相应的JSON类型映射到它们的等效语言。例如,JSON null 可以映射到 None 在python中,以及 nil 用ruby和go。

语法

语法是使用ABNF指定的,如中所述 RFC4234

expression        = sub-expression / index-expression  / comparator-expression
expression        =/ or-expression / identifier
expression        =/ and-expression / not-expression / paren-expression
expression        =/ "*" / multi-select-list / multi-select-hash / literal
expression        =/ function-expression / pipe-expression / raw-string
expression        =/ current-node
sub-expression    = expression "." ( identifier /
                                     multi-select-list /
                                     multi-select-hash /
                                     function-expression /
                                     "*" )
pipe-expression   = expression "|" expression
or-expression     = expression "||" expression
and-expression    = expression "&&" expression
not-expression    = "!" expression
paren-expression  = "(" expression ")"
index-expression  = expression bracket-specifier / bracket-specifier
multi-select-list = "[" ( expression *( "," expression ) ) "]"
multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}"
keyval-expr       = identifier ":" expression
bracket-specifier = "[" (number / "*" / slice-expression) "]" / "[]"
bracket-specifier =/ "[?" expression "]"
comparator-expression = expression comparator expression
slice-expression  = [number] ":" [number] [ ":" [number] ]
comparator        = "<" / "<=" / "==" / ">=" / ">" / "!="
function-expression = unquoted-string  (
                        no-args  /
                        one-or-more-args )
no-args             = "(" ")"
one-or-more-args    = "(" ( function-arg *( "," function-arg ) ) ")"
function-arg        = expression / expression-type
current-node        = "@"
expression-type     = "&" expression

raw-string        = "'" *raw-string-char "'"
raw-string-char   = (%x20-26 / %x28-5B / %x5D-10FFFF) / preserved-escape /
                      raw-string-escape
preserved-escape  = escape (%x20-26 / %28-5B / %x5D-10FFFF)
raw-string-escape = escape ("'" / escape)
literal           = "`" json-value "`"
unescaped-literal = %x20-21 /       ; space !
                        %x23-5B /   ; # - [
                        %x5D-5F /   ; ] ^ _
                        %x61-7A     ; a-z
                        %x7C-10FFFF ; |}~ ...
escaped-literal   = escaped-char / (escape %x60)
number            = ["-"]1*digit
digit             = %x30-39
identifier        = unquoted-string / quoted-string
unquoted-string   = (%x41-5A / %x61-7A / %x5F) *(  ; A-Za-z_
                        %x30-39  /  ; 0-9
                        %x41-5A /  ; A-Z
                        %x5F    /  ; _
                        %x61-7A)   ; a-z
quoted-string     = quote 1*(unescaped-char / escaped-char) quote
unescaped-char    = %x20-21 / %x23-5B / %x5D-10FFFF
escape            = %x5C   ; Back slash: \
quote             = %x22   ; Double quote: '"'
escaped-char      = escape (
                        %x22 /          ; "    quotation mark  U+0022
                        %x5C /          ; \    reverse solidus U+005C
                        %x2F /          ; /    solidus         U+002F
                        %x62 /          ; b    backspace       U+0008
                        %x66 /          ; f    form feed       U+000C
                        %x6E /          ; n    line feed       U+000A
                        %x72 /          ; r    carriage return U+000D
                        %x74 /          ; t    tab             U+0009
                        %x75 4HEXDIG )  ; uXXXX                U+XXXX

; The ``json-value`` is any valid JSON value with the one exception that the
; ``%x60`` character must be escaped.  While it's encouraged that implementations
; use any existing JSON parser for this grammar rule (after handling the escaped
; literal characters), the grammar rule is shown below for completeness::

json-value = false / null / true / json-object / json-array /
             json-number / json-quoted-string
false = %x66.61.6c.73.65   ; false
null  = %x6e.75.6c.6c      ; null
true  = %x74.72.75.65      ; true
json-quoted-string = %x22 1*(unescaped-literal / escaped-literal) %x22
begin-array     = ws %x5B ws  ; [ left square bracket
begin-object    = ws %x7B ws  ; { left curly bracket
end-array       = ws %x5D ws  ; ] right square bracket
end-object      = ws %x7D ws  ; } right curly bracket
name-separator  = ws %x3A ws  ; : colon
value-separator = ws %x2C ws  ; , comma
ws              = *(%x20 /              ; Space
                    %x09 /              ; Horizontal tab
                    %x0A /              ; Line feed or New line
                    %x0D                ; Carriage return
                   )
json-object = begin-object [ member *( value-separator member ) ] end-object
member = quoted-string name-separator json-value
json-array = begin-array [ json-value *( value-separator json-value ) ] end-array
json-number = [ minus ] int [ frac ] [ exp ]
decimal-point = %x2E       ; .
digit1-9 = %x31-39         ; 1-9
e = %x65 / %x45            ; e E
exp = e [ minus / plus ] 1*DIGIT
frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )
minus = %x2D               ; -
plus = %x2B                ; +
zero = %x30                ; 0

除了语法之外,还有以下从最弱到最紧绑定的标记优先级:

  • 管道: |

  • 或: ||

  • 还有: &&

  • 一元不: !

  • R球拍: ]

标识符

identifier        = unquoted-string / quoted-string
unquoted-string   = (%x41-5A / %x61-7A / %x5F) *(  ; A-Za-z_
                        %x30-39  /  ; 0-9
                        %x41-5A /  ; A-Z
                        %x5F    /  ; _
                        %x61-7A)   ; a-z
quoted-string     = quote 1*(unescaped-char / escaped-char) quote
unescaped-char    = %x20-21 / %x23-5B / %x5D-10FFFF
escape            = %x5C   ; Back slash: \
quote             = %x22   ; Double quote: '"'
escaped-char      = escape (
                        %x22 /          ; "    quotation mark  U+0022
                        %x5C /          ; \    reverse solidus U+005C
                        %x2F /          ; /    solidus         U+002F
                        %x62 /          ; b    backspace       U+0008
                        %x66 /          ; f    form feed       U+000C
                        %x6E /          ; n    line feed       U+000A
                        %x72 /          ; r    carriage return U+000D
                        %x74 /          ; t    tab             U+0009
                        %x75 4HEXDIG )  ; uXXXX                U+XXXX

identifier 是最基本的表达式,可用于从JSON文档中提取单个元素。的返回值 identifier 与标识符关联的值。如果 identifier 在JSON文档中不存在,而不是 null 返回值。

根据上面列出的语法规则,标识符可以是一个或多个字符,并且必须以 A-Za-z_ .

也可以引用标识符。当标识符中没有指定字符时,这是必需的 unquoted-string 语法规则。在这种情况下,标识符用双引号指定,后跟任意数量的 unescaped-charescaped-char 字符,后跟双引号。这个 quoted-string rule与JSON字符串的语法规则相同,因此任何有效的字符串都可以在双引号、包括JSON支持的转义序列和六个字符的unicode转义序列之间使用。

Note that any identifier that does not start with A-Za-z_ must be quoted.

实例

search(foo, {"foo": "value"}) -> "value"
search(bar, {"foo": "value"}) -> null
search(foo, {"foo": [0, 1, 2]}) -> [0, 1, 2]
search("with space", {"with space": "value"}) -> "value"
search("special chars: !@#", {"special chars: !@#": "value"}) -> "value"
search("quote\"char", {"quote\"char": "value"}) -> "value"
search("\u2713", {"\u2713": "value"}) -> "value"

SubExpressions

sub-expression    = expression "." ( identifier /
                                     multi-select-list /
                                     multi-select-hash /
                                     function-expression /
                                     "*" )

子表达式是用“.”字符分隔的两个表达式的组合。子表达式的评估如下:

  • 使用原始JSON文档计算左侧的表达式。

  • 使用左侧表达式求值的结果计算右侧表达式。

在伪代码中:

left-evaluation = search(left-expression, original-json-document)
result = search(right-expression, left-evaluation)

子表达式本身就是表达式,因此可以有多个级别的子表达式: grandparent.parent.child .

实例

给定一个JSON文档: {{"foo": {{"bar": "baz"}}}} ,以及jmespath表达式: foo.bar ,评估过程为:

left-evaluation = search("foo", {"foo": {"bar": "baz"}}) -> {"bar": "baz"}
result = search("bar": {"bar": "baz"}) -> "baz"

这个例子的最终结果是 "baz" .

其他示例:

search(foo.bar, {"foo": {"bar": "value"}}) -> "value"
search(foo."bar", {"foo": {"bar": "value"}}) -> "value"
search(foo.bar, {"foo": {"baz": "value"}}) -> null
search(foo.bar.baz, {"foo": {"bar": {"baz": "value"}}}) -> "value"

索引表达式

index-expression  = expression bracket-specifier / bracket-specifier
bracket-specifier = "[" (number / "*") "]" / "[]"

索引表达式用于访问列表中的元素。索引是基于0的,索引0是指列表的第一个元素。负数是有效的索引。负数表示索引相对于列表的结尾,特别是:

negative-index == (length of array) + negative-index

给定一个数组的长度 N ,一个索引 -1 等于正指数 N - 1 ,它是列表的最后一个元素。如果索引表达式引用的索引大于数组的长度,则 null 返回。

语法规则 expression bracket-specifier 这个 expression 首先计算,然后从 expression 作为输入提供给 bracket-specifier .

在中使用“*”字符 bracket-specifier 在下面的 wildcard expressions 部分。

slice-expression  = [number] ":" [number] [ ":" [number] ]

切片表达式允许您选择数组的连续子集。一片有一片 startstopstep 价值观。切片的一般形式是 [start:stop:step] ,但每个组件都是可选的,可以省略。

注解

JMESPath中的切片与python切片具有相同的语义。如果您熟悉python切片,那么就熟悉JMESPath切片。

给出了一个 startstopstep 值,则数组中的子元素按如下方式提取:

  • 提取数组中的第一个元素是用 start .

  • 提取数组中的最后一个元素是用 end - 1 .

  • 这个 step 值确定从数组中选择每个元素后要跳过的索引数。数组1(默认步骤)不会跳过任何索引。从数组中提取元素时,步长值为2将每隔一个索引跳过一次。步长值-1将从数组中以相反的顺序提取值。

切片表达式遵循以下规则:

  • 如果给定的起始位置为负,则计算为数组的总长度加上给定的起始位置。

  • 如果没有给定起始位置,如果给定步长大于0,则假定为0;如果给定步长小于0,则假定为数组的结束。

  • 如果给定负停止位置,则将其计算为数组的总长度加上给定的停止位置。

  • 如果没有给定停止位置,如果给定步长大于0,则假定为数组的长度;如果给定步长小于0,则假定为0。

  • 如果省略给定步骤,则假定为1。

  • 如果给定步骤为0,则必须引发错误。

  • 如果被切片的元素不是数组,则结果是 null .

  • 如果被切片的元素是一个数组并且没有产生结果,那么结果必须是空数组。

实例

search([0:4:1], [0, 1, 2, 3]) -> [0, 1, 2, 3]
search([0:4], [0, 1, 2, 3]) -> [0, 1, 2, 3]
search([0:3], [0, 1, 2, 3]) -> [0, 1, 2]
search([:2], [0, 1, 2, 3]) -> [0, 1]
search([::2], [0, 1, 2, 3]) -> [0, 2]
search([::-1], [0, 1, 2, 3]) -> [3, 2, 1, 0]
search([-2:], [0, 1, 2, 3]) -> [2, 3]

展平运算符

当字符序列 [] 作为括号说明符提供,则对当前结果执行展平操作。展平运算符将当前结果中的子列表合并到单个列表中。“展平”操作符具有以下语义:

  • 创建空结果列表。

  • 迭代当前结果的元素。

  • 如果当前元素不是列表,请添加到结果列表的末尾。

  • 如果当前元素是列表,则将当前元素的每个元素添加到结果列表的末尾。

  • 结果列表现在是新的当前结果。

一旦执行了展平操作,后续操作将被投影到展平列表上,其语义与通配符表达式相同。因此 [*][] 那是 [] 将首先展平当前结果中的子列表。

实例

search([0], ["first", "second", "third"]) -> "first"
search([-1], ["first", "second", "third"]) -> "third"
search([100], ["first", "second", "third"]) -> null
search(foo[0], {"foo": ["first", "second", "third"]) -> "first"
search(foo[100], {"foo": ["first", "second", "third"]) -> null
search(foo[0][0], {"foo": [[0, 1], [1, 2]]}) -> 0

或表达式

or-expression     = expression "||" expression

or表达式将计算为左表达式或右表达式。如果左表达式的求值不是false,则将其用作返回值。如果正确表达式的求值不是false,则将其用作返回值。如果left或right表达式都不是非null,则返回null值。假值对应于以下任何条件:

  • 空列表: []

  • 空对象: {{}}

  • 空字符串: ""

  • 假布尔值: false

  • 空值: null

真值对应于任何非false的值。

实例

search(foo || bar, {"foo": "foo-value"}) -> "foo-value"
search(foo || bar, {"bar": "bar-value"}) -> "bar-value"
search(foo || bar, {"foo": "foo-value", "bar": "bar-value"}) -> "foo-value"
search(foo || bar, {"baz": "baz-value"}) -> null
search(foo || bar || baz, {"baz": "baz-value"}) -> "baz-value"
search(override || mylist[-1], {"mylist": ["one", "two"]}) -> "two"
search(override || mylist[-1], {"mylist": ["one", "two"], "override": "yes"}) -> "yes"

和表达式

and-expression  = expression "&&" expression

and表达式将计算为左表达式或右表达式。如果左侧的表达式是一个类似于真值的值,则返回右侧的值。否则,将返回左侧表达式的结果。这也简化为期望真值表:

与表达式真值表

LHS

RHS

结果

这是一个 logical conjunction (AND) .

实例

search(True && False, {"True": true, "False": false}) -> false
search(Number && EmptyList, {"Number": 5, EmptyList: []}) -> []
search(foo[?a == `1` && b == `2`],
       {"foo": [{"a": 1, "b": 2}, {"a": 1, "b": 3}]}) -> [{"a": 1, "b": 2}]

Paren表达式

paren-expression  = "(" expression ")"

A paren-expression 允许用户重写表达式的优先顺序,例如。 (a || b) && c .

实例

search(foo[?(a == `1` || b ==`2`) && c == `5`],
       {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}) -> []

不是表达式

not-expression    = "!" expression

A not-expression 否定表达式的结果。如果表达式的结果是一个类真值,则 not-expression 将此值更改为 false . 如果表达式的结果是一个类假值,则 not-expression 将此值更改为 true .

实例

search(!True, {"True": true}) -> false
search(!False, {"False": false}) -> true
search(!Number, {"Number": 5}) -> false
search(!EmptyList, {"EmptyList": []}) -> true

多选列表

multi-select-list = "[" ( expression *( "," expression ) "]"

multiselect表达式用于从JSON哈希中提取元素的子集。multiselect有两个版本,其中一个版本中包含multiselect表达式 {{...}} 还有一个 [...] . 本节介绍 [...] 版本。在开始和结束字符中是一个或多个用逗号分隔的非表达式。每个表达式都将根据JSON文档进行计算。每个返回的元素将是计算表达式的结果。A multi-select-list 具有 N 表达式将生成一个长度列表 N . 给出一个多选表达式 [expr-1,expr-2,...,expr-n] ,则计算的表达式将返回 [evaluate(expr-1), evaluate(expr-2), ..., evaluate(expr-n)] .

实例

search([foo,bar], {"foo": "a", "bar": "b", "baz": "c"}) -> ["a", "b"]
search([foo,bar[0]], {"foo": "a", "bar": ["b"], "baz": "c"}) -> ["a", "b"]
search([foo,bar.baz], {"foo": "a", "bar": {"baz": "b"}}) -> ["a", "b"]
search([foo,baz], {"foo": "a", "bar": "b"}) -> ["a", null]

多选哈希

multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) "}"
keyval-expr       = identifier ":" expression

A multi-select-hash 表达式类似于 multi-select-list 表达式,但创建的是哈希而不是列表。A multi-select-hash 表达式还需要提供键名,如 keyval-expr 规则。根据以下规则:

keyval-expr       = identifier ":" expression

这个 identifier 作为键名和计算 expression 是与关联的值 identifier 关键。

keyval-exprmulti-select-hash 将对应于所创建哈希中的单个键值对。

实例

给出了一个 multi-select-hash 表达 {{foo: one.two, bar: bar}} 数据呢 {{"bar": "bar", {{"one": {{"two": "one-two"}}}}}} ,表达式计算如下:

  1. 将创建哈希: {{}}

  2. 一把钥匙 foo 其价值是评估的结果 one.two 针对提供的JSON文档: {{"foo": evaluate(one.two, <data>)}}

  3. 一把钥匙 bar 其值是对表达式求值的结果 bar 针对提供的JSON文档。

最终结果将是: {{"foo": "one-two", "bar": "bar"}} .

其他示例:

search({foo: foo, bar: bar}, {"foo": "a", "bar": "b", "baz": "c"})
              -> {"foo": "a", "bar": "b"}
search({foo: foo, firstbar: bar[0]}, {"foo": "a", "bar": ["b"]})
              -> {"foo": "a", "firstbar": "b"}
search({foo: foo, "bar.baz": bar.baz}, {"foo": "a", "bar": {"baz": "b"}})
              -> {"foo": "a", "bar.baz": "b"}
search({foo: foo, baz: baz}, {"foo": "a", "bar": "b"})
              -> {"foo": "a", "baz": null}

通配符表达式

expression        =/ "*"
bracket-specifier = "[" "*" "]"

通配符表达式是 *[*] . 通配符表达式可以返回多个元素,其余表达式将根据通配符表达式返回的每个元素进行求值。这个 [*] 语法应用于列表类型,并且 * 语法适用于哈希类型。

这个 [*] 语法(称为列表通配符表达式)将返回列表中的所有元素。任何后续表达式都将针对每个单独的元素进行计算。给出一个表达式 [*].child-expr ,以及N个元素的列表,则此表达式的计算结果为 [child-expr(el-0), child-expr(el-2), ..., child-expr(el-N)] . 这被称为 投影child-expr 表达式被投影到结果列表的元素上。

创建投影后,所有后续表达式都将投影到结果列表中。

这个 * 语法(称为哈希通配符表达式)将返回哈希元素值的列表。任何后续表达式都将针对列表中的每个单独元素进行计算(这也称为 投影

注意,如果通配符表达式后面的任何后续表达式返回 null 值,则从最终结果列表中省略。

列表通配符表达式仅对JSON数组类型有效。如果列表通配符表达式应用于任何其他JSON类型,则值为 null 返回。

类似地,散列通配符表达式仅对JSON对象类型有效。如果哈希通配符表达式应用于任何其他JSON类型,则值为 null 返回。注意,JSON哈希被显式定义为无序。因此,哈希通配符表达式可以以任何顺序返回与哈希关联的值。实现不需要以任何特定顺序返回哈希值。

实例

search([*].foo, [{"foo": 1}, {"foo": 2}, {"foo": 3}]) -> [1, 2, 3]
search([*].foo, [{"foo": 1}, {"foo": 2}, {"bar": 3}]) -> [1, 2]
search('*.foo', {"a": {"foo": 1}, "b": {"foo": 2}, "c": {"bar": 1}}) -> [1, 2]

文字表达式

literal           = "`" json-value "`"

文本表达式是允许指定任意JSON对象的表达式。这在过滤器表达式和多选散列(创建任意键值对)中很有用,但在允许表达式的任何地方都允许使用。该规范包含了用于JSON的ABNF,实现应该使用现有的JSON解析器来解析文本值。注意 \ 字符现在必须在 ``json-value` 这意味着实现需要在将结果字符串传递给JSON解析器之前处理这种情况。

实例

search(`"foo"`, "anything") -> "foo"
search(`"foo\`bar"`, "anything") -> "foo`bar"
search(`[1, 2]`, "anything") -> [1, 2]
search(`true`, "anything") -> true
search(`{"a": "b"}`.a, "anything") -> "b"
search({first: a, type: `"mytype"`}, {"a": "b", "c": "d"}) -> {"first": "b", "type": "mytype"}

原始字符串文本

raw-string        = "'" *raw-string-char "'"
raw-string-char   = (%x20-26 / %x28-5B / %x5D-10FFFF) / preserved-escape /
                      raw-string-escape
preserved-escape  = escape (%x20-26 / %28-5B / %x5D-10FFFF)
raw-string-escape = escape ("'" / escape)

原始字符串是允许指定文本字符串值的表达式。计算原始字符串文本表达式的结果是文本字符串值。它是一种更简单的文本表达式形式,它是字符串的特殊大小写形式。例如,以下表达式的值都相同:“foo”::

search(`"foo"`, "") -> "foo"
search('foo', "") -> "foo"

正如您在上面的示例中所看到的,它是指定文本字符串值的常见场景的一种更简洁的形式。

此外,它不执行JSON字符串支持的任何其他处理,包括:

  • 不扩展unicode转义序列

  • 不扩展换行符

  • 不扩展制表符或RFC 4627第2.5节中记录的任何其他转义序列。

search('foo', "") -> "foo"
search(' bar ', "") -> " bar "
search('[baz]', "") -> "[baz]"
search('[baz]', "") -> "[baz]"
search('\u03a6', "") -> "\u03a6"
search('\\', "") -> "\\"

筛选表达式

list-filter-expr      = "[?" expression "]"
comparator-expression = expression comparator expression
comparator            = "<" / "<=" / "==" / ">=" / ">" / "!="

过滤器表达式提供了一种根据与另一个表达式的比较来选择JSON元素的方法。筛选器表达式的计算方法如下:对于数组中的每个元素,计算 expression 对元素不利。如果表达式求值为真值,则该项(全部)将添加到结果列表中。否则,它将从结果列表中排除。过滤器表达式只为JSON数组定义。尝试针对任何其他类型计算筛选器表达式将返回 null .

比较运算符

支持以下操作:

  • == ,相等性测试。

  • != ,不平等测试。

  • < ,小于。

  • <= ,小于或等于。

  • > ,大于。

  • >= ,大于或等于。

每个操作的行为取决于每个计算表达式的类型。

下面根据对应的JSON类型定义每个运算符的比较语义:

相等运算符

为了 string/number/true/false/null 类型,相等是完全匹配的。A string 等于另一个 string 如果他们有准确的代码点序列。文字值 true/false/null 只等于它们自己的字面值。如果两个JSON对象具有相同的键和值集(给定两个JSON对象),则它们是相等的 xy ,对于每个键值对 (i, j) 在里面 x ,存在等效对 (i, j) 在里面 y ). 如果两个JSON数组的顺序相同,则它们的顺序相同 xy ,每个 i0 直到 length(x)x[i] == y[i]

排序运算符

排序运算符 >, >=, <, <=only 对数字有效。使用比较运算符计算任何其他类型都将生成 null 值,这将导致元素从结果列表中排除。例如,给定:

search('foo[?a<b]', {"foo": [{"a": "char", "b": "char"},
                             {"a": 2, "b": 1},
                             {"a": 1, "b": 2}]})

对foo列表中的三个元素进行计算 a < b . 第一个元素解析为比较 "char" < "bar" ,并且由于这些类型是字符串,因此表达式将导致 null ,因此第一个元素不包含在结果列表中。第二个元素解析为 2 < 1 ,这就是 false ,因此第二个元素从结果列表中排除。第三个表达式解析为 1 < 2 评估结果 true ,因此第三个元素包含在列表中。这个表达式的最终结果是 [{{"a": 1, "b": 2}}] .

实例

search(foo[?bar==`10`], {"foo": [{"bar": 1}, {"bar": 10}]}) -> [{"bar": 10}]
search([?bar==`10`], [{"bar": 1}, {"bar": 10}]}) -> [{"bar": 10}]
search(foo[?a==b], {"foo": [{"a": 1, "b": 2}, {"a": 2, "b": 2}]}) -> [{"a": 2, "b": 2}]

函数表达式

function-expression = unquoted-string  (
                        no-args  /
                        one-or-more-args )
no-args             = "(" ")"
one-or-more-args    = "(" ( function-arg *( "," function-arg ) ) ")"
function-arg        = expression / current-node / expression-type
current-node        = "@"
expression-type     = "&" expression

函数允许用户轻松转换和过滤JMESPath表达式中的数据。

数据类型

为了支持功能,需要一个类型系统。使用JSON类型:

  • 数字(JSON中的整数和双精度浮点格式)

  • 一串

  • 布尔 (truefalse

  • 数组(一个有序的值序列)

  • 对象(键值对的无序集合)

  • 无效的

还有一个附加类型不是JMESPath函数中使用的JSON类型:

  • 表达式(用 &expression

当前节点

这个 current-node 令牌可用于表示正在计算的当前节点。这个 current-node 令牌对于需要将当前节点作为参数求值的函数很有用。例如,下面的表达式创建一个数组,其中包含 foo 对象后跟的值 foo["bar"] .

foo[].[count(@), bar]

JMESPath假定所有函数参数都在当前节点上操作,除非参数是 literalnumber 令牌。因此,一个像 @.bar 相当于 bar ,因此当前节点只允许作为裸表达式。

当前节点状态

在表达式的开头,当前节点的值是由JMESPath表达式计算的数据。计算表达式时,当前节点表示的值必须更改以反映当前正在计算的节点。在投影中时,当前节点值必须更改为当前由投影计算的节点。

功能评价

函数按应用顺序求值。每个参数必须是一个表达式,每个参数表达式必须在计算函数之前求值。然后用求值的函数参数调用函数。结果 function-expression 函数调用返回的结果。如果 function-expression 为不存在的函数求值,则JMESPath实现必须向调用方指示 unknown-function 发生错误。引发此错误的方式和时间是特定于实现的,但实现应向调用方指示发生了此特定错误。

函数可以有一个特定的arity,也可以是变量,参数数量最少。如果 function-expression 如果arity不匹配或未提供变量函数的最小参数数,则实现必须向调用方指示 invalid-arity 发生错误。引发此错误的方式和时间取决于实现。

每个函数签名声明其输入参数的类型。如果不满足任何类型约束,则实现必须指示 invalid-type 发生错误。

为了适应类型约束,提供了将类型转换为其他类型的函数 (to_stringto_number )定义如下。除非用户专门使用这些类型转换函数之一,否则不会发生显式类型转换。

函数表达式也允许作为子表达式的子元素。这使得函数可以与投影一起使用,这样就可以将函数应用于投影中的每个元素。例如,给定的输入数据 ["1", "2", "3", "notanumber", true] ,可以使用以下表达式将所有元素转换(和筛选)为数字:

search([].to_number(@), ``["1", "2", "3", "notanumber", true]``) -> [1, 2, 3]

这提供了一个简单的机制,以便在需要时显式地转换类型。

内置功能

JMESPath有各种内置函数,这些函数可以对不同的数据类型进行操作,如下所述。下面的每个函数都有一个签名,用于定义预期的输入类型和返回的输出类型:

return_type function_name(type $argname)
return_type function_name2(type1|type2 $argname)

函数支持的数据类型列表包括:

  • 数字(JSON中的整数和双精度浮点格式)

  • 一串

  • 布尔 (truefalse

  • 数组(一个有序的值序列)

  • 对象(键值对的无序集合)

  • 无效的

  • 表达式(用 &expression

除了最后一项之外,上述所有类型都与JSON提供的类型相对应。

如果一个函数可以为一个输入值接受多个类型,则用 | . 如果解析的参数与签名中指定的类型不匹配,则 invalid-type 发生错误。

这个 array 类型可以进一步指定对元素类型的要求,如果它们希望强制执行同构类型。子类型由 [type] ,例如,下面的函数签名要求其输入参数解析为数字数组:

return_type foo(array[number] $argname)

作为一种速记 any 用于指示参数可以是任何类型 (array|object|number|string|boolean|null

JMESPath函数需要对其输入参数进行类型检查。为函数参数指定无效类型将导致JMESPath错误。

表达式类型,用 &expression ,用于指定不立即求值的表达式。相反,对该表达式的引用将提供给被调用的函数。然后,函数可以根据需要选择应用表达式引用。它在语义上类似于匿名函数。见 sort_by 函数来获取表达式类型的示例用法。

类似地,数组如何使用 array[type] 语法,表达式可以使用 expression->type 语法。这意味着函数参数的已解析类型必须是自身将解析为的表达式 type .

下面的第一个函数, abs 详细讨论了以上几点。为了简洁起见,后续函数定义将不包括这些详细信息,但同样的规则也适用。

注解

所有与字符串相关的函数都是基于Unicode代码点定义的;它们不考虑规范化。

防抱死制动系统

number abs(number $value)

Returns the absolute value of the provided argument. The signature indicates that a number is returned, and that the input argument $value must resolve to a number, otherwise a invalid-type error is triggered.

下面是一个成功的例子。鉴于::

{"foo": -1, "bar": "2"}

评价 abs(foo) 工程如下:

  1. 根据当前数据计算输入参数:

    search(foo, {"foo": -1, "bar": "2"}) -> -1
    
  2. 验证已解析参数的类型。在这种情况下 -1 属于类型 number 所以它通过了类型检查。

  3. 使用已解析的参数调用函数::

    abs(-1) -> 1
    
  4. 价值 1 函数表达式的解析值 abs(foo) .

以下是评估的相同步骤 abs(bar)

  1. 根据当前数据计算输入参数:

    search(bar, {"foo": -1, "bar": "2"}) -> "2"
    
  2. 验证已解析参数的类型。在这种情况下 "2" 属于类型 string 我们立即表示 invalid-type 发生错误。

作为最后一个例子,下面是评估 abs(to_number(bar))

  1. 根据当前数据计算输入参数:

    search(to_number(bar), {"foo": -1, "bar": "2"})
    
  2. 为了计算上述表达式,我们需要计算 to_number(bar) ::

    search(bar, {"foo": -1, "bar": "2"}) -> "2"
    # Validate "2" passes the type check for to_number, which it does.
    to_number("2") -> 2
    

    注意 to_number 定义如下。

  3. 现在我们可以计算原始表达式:

    search(to_number(bar), {"foo": -1, "bar": "2"}) -> 2
    
  4. 使用最终解析的值调用函数::

    abs(2) -> 2
    
  5. 价值 2 函数表达式的解析值 abs(to_number(bar)) .

实例

表情

结果

abs(1)

1

abs(-1)

1

abs(`abc`)

<error: invalid-type>

平均

number avg(array[number] $elements)

返回所提供数组中元素的平均值。

空数组将产生null的返回值。

实例

鉴于

表情

结果

[10, 15, 20]

avg(@)

15

[10, false, 20]

avg(@)

<error: invalid-type>

[false]

avg(@)

<error: invalid-type>

false

avg(@)

<error: invalid-type>

包含

boolean contains(array|string $subject, any $search)

返回 true 如果给定 $subject 包含提供的 $search 字符串。

如果 $subject 是一个数组,如果数组中的一个元素等于提供的 $search 价值。

如果提供 $subject 是字符串,如果字符串包含提供的 $search 争论。

实例

鉴于

表情

结果

n/a

contains(`foobar`, `foo`)

true

n/a

contains(`foobar`, `not`)

false

n/a

contains(`foobar`, `bar`)

true

n/a

contains(`false`, `bar`)

<error: invalid-type>

n/a

contains(`foobar`, 123)

false

["a", "b"]

contains(@, `a`)

true

["a"]

contains(@, `a`)

true

["a"]

contains(@, `b`)

false

["foo", "bar"]

contains(@, `foo`)

true

["foo", "bar"]

contains(@, `b`)

false

塞尔

number ceil(number $value)

如果需要,通过向上舍入返回下一个最大的整数值。

实例

表情

结果

ceil(`1.001`)

2

ceil(`1.9`)

2

ceil(`1`)

1

ceil(`abc`)

null

ends_with

boolean ends_with(string $subject, string $prefix)

返回 true 如果 $subject$prefix ,否则此函数返回 false .

实例

鉴于

表情

结果

foobarbaz

ends_with(@, ``baz)``

true

foobarbaz

ends_with(@, ``foo)``

false

foobarbaz

ends_with(@, ``z)``

true

地板

number floor(number $value)

如果需要,通过向下舍入返回下一个最小的整数值。

实例

表情

结果

floor(`1.001`)

1

floor(`1.9`)

1

floor(`1`)

1

参加

string join(string $glue, array[string] $stringsarray)

返回所提供的 $stringsarray 数组使用 $glue 参数作为每个参数之间的分隔符。

实例

鉴于

表情

结果

["a", "b"]

join(`, `, @)

“a,b”

["a", "b"]

join(``, @)``

“ab”

["a", false, "b"]

join(`, `, @)

<error: invalid-type>

[false]

join(`, `, @)

<error: invalid-type>

钥匙

array keys(object $obj)

返回包含所提供对象的键的数组。请注意,由于JSON哈希是继承无序的,因此与提供的对象关联的键 obj 继承无序。实现不需要以任何特定顺序返回键。

实例

鉴于

表情

结果

{"foo": "baz", "bar": "bam"}

keys(@)

["foo", "bar"]

{}

keys(@)

[]

false

keys(@)

<error: invalid-type>

[b, a, c]

keys(@)

<error: invalid-type>

长度

number length(string|array|object $subject)

使用以下类型规则返回给定参数的长度:

  1. 字符串:返回字符串中代码点的数目

  2. array:返回数组中的元素数

  3. object:返回对象中键值对的数目

实例

鉴于

表情

结果

n/a

length(`abc`)

3

“当前”

length(@)

7

“当前”

length(not_there)

<error: invalid-type>

["a", "b", "c"]

length(@)

3

[]

length(@)

0

{}

length(@)

0

{"foo": "bar", "baz": "bam"}

length(@)

2

地图

array[any] map(expression->any->any expr, array[any] elements)

应用 expr 中的每个元素 elements 数组并返回结果数组。安 elements 将生成长度为N的返回数组。

与投影不同, ([*].barmap() 将包括应用 expr 中的每个元素 elements 数组,即使结果 null .

实例

鉴于

表情

结果

{"array": [{"foo": "a"}, {"foo": "b"}, {}, [], {"foo": "f"}]}

map(&foo, array)

["a", "b", null, null, "f"]

[[1, 2, 3, [4]], [5, 6, 7, [8, 9]]]

map(&[], @)

[[1, 2, 3, 4], [5, 6, 7, 8, 9]]

最大值

number max(array[number]|array[string] $collection)

返回在提供的数组参数中找到的最大值。

空数组将产生null的返回值。

实例

鉴于

表情

结果

[10, 15]

max(@)

15

["a", "b"]

max(@)

“b”

["a", 2, "b"]

max(@)

<error: invalid-type>

[10, false, 20]

max(@)

<error: invalid-type>

max_by

max_by(array elements, expression->number|expression->string expr)

使用表达式返回数组中的最大元素 expr 作为比较键。返回整个maximum元素。下面是几个使用 people 数组(上面定义的)作为给定的输入。

实例

表情

结果

max_by(people, &age)

{"age": 50, "age_str": "50", "bool": false, "name": "d"}

max_by(people, &age).age

50

max_by(people, &to_number(age_str))

{"age": 50, "age_str": "50", "bool": false, "name": "d"}

max_by(people, &age_str)

<错误:无效类型>

max_by(people, age)

<错误:无效类型>

合并

object merge([object *argument, [, object $...]])

接受0个或多个对象作为参数,并返回一个合并了后续对象的对象。每个后续对象的键/值对将添加到前一个对象。此函数用于将多个对象合并为一个对象。您可以将其视为第一个对象是基对象,而每个后续参数都是应用于基对象的重写。

实例

表情

结果

merge(`{"a": "b"}`, `{"c": "d"}`)

{"a": "b", "c": "d"}

merge(`{"a": "b"}`, `{"a": "override"}`)

{"a": "override"}

merge(`{"a": "x", "b": "y"}`, `{"b": "override", "c": "z"}`)

{"a": "x", "b": "override", "c": "z"}

number min(array[number]|array[string] $collection)

返回在提供的 $collection 争论。

实例

鉴于

表情

结果

[10, 15]

min(@)

10

["a", "b"]

min(@)

“a”

["a", 2, "b"]

min(@)

<error: invalid-type>

[10, false, 20]

min(@)

<error: invalid-type>

min_by

min_by(array elements, expression->number|expression->string expr)

使用表达式返回数组中的最小元素 expr 作为比较键。返回整个maximum元素。下面是几个使用 people 数组(上面定义的)作为给定的输入。

实例

表情

结果

min_by(people, &age)

{"age": 10, "age_str": "10", "bool": true, "name": 3}

min_by(people, &age).age

10

min_by(people, &to_number(age_str))

{"age": 10, "age_str": "10", "bool": true, "name": 3}

min_by(people, &age_str)

<error: invalid-type>

min_by(people, age)

<error: invalid-type>

not_null

any not_null([any $argument [, any $...]])

返回第一个不解析为的参数 null . 此函数接受一个或多个参数,并按顺序计算它们,直到遇到非空参数。如果所有参数值都解析为 null ,则值为 null 返回。

实例

鉴于

表情

结果

{"a": null, "b": null, "c": [], "d": "foo"}

not_null(no_exist, a, b, c, d)

[]

{"a": null, "b": null, "c": [], "d": "foo"}

not_null(a, b, `null`, d, c)

"foo"

{"a": null, "b": null, "c": [], "d": "foo"}

not_null(a, b)

null

颠倒

array reverse(string|array $argument)

颠倒 $argument .

实例

鉴于

表情

结果

[0, 1, 2, 3, 4]

reverse(@)

[4, 3, 2, 1, 0]

[]

reverse(@)

[]

["a", "b", "c", 1, 2, 3]

reverse(@)

[3, 2, 1, "c", "b", "a"]

"abcd

reverse(@)

dcba

分类

array sort(array[number]|array[string] $list)

此函数接受数组 $list 参数,并返回 $list 作为一个数组。

数组必须是字符串或数字的列表。字符串排序基于代码点。不考虑区域设置。

实例

鉴于

表情

结果

[b, a, c]

sort(@)

[a, b, c]

[1, a, c]

sort(@)

[1, a, c]

[false, [], null]

sort(@)

[[], null, false]

[[], {}, false]

sort(@)

[{}, [], false]

{"a": 1, "b": 2}

sort(@)

null

false

sort(@)

null

sort_by

sort_by(array elements, expression->number|expression->string expr)

使用表达式对数组排序 expr 作为排序键。数组中的每个元素 elements , the expr 表达式并将结果值用作排序时使用的键 elements .

如果评估结果 expr 当前数组元素的结果不是 number 或A string ,将发生类型错误。

下面是几个使用 people 数组(上面定义的)作为给定的输入。 sort_by 遵循与 sort 功能。

实例

表情

结果

sort_by(people, &age)[].age

[10, 20, 30, 40, 50]

sort_by(people, &age)[0]

{"age": 10, "age_str": "10", "bool": true, "name": 3}

sort_by(people, &to_number(age_str))[0]

{"age": 10, "age_str": "10", "bool": true, "name": 3}

starts_with

boolean starts_with(string $subject, string $prefix)

返回 true 如果 $subject$prefix ,否则此函数返回 false .

实例

鉴于

表情

结果

foobarbaz

starts_with(@, ``foo)``

true

foobarbaz

starts_with(@, ``baz)``

false

foobarbaz

starts_with(@, ``f)``

true

总和

number sum(array[number] $collection)

返回提供的数组参数的和。

空数组将生成返回值0。

实例

鉴于

表情

结果

[10, 15]

sum(@)

25

[10, false, 20]

max(@)

<error: invalid-type>

[10, false, 20]

sum([].to_number(@))

30

[]

sum(@)

0

to_array

array to_array(any $arg)
  • 数组-返回传入的值。

  • number/string/object/boolean-返回包含传入参数的单元素数组。

实例

表情

结果

to_array(`[1, 2]`)

[1, 2]

to_array(`"string"`)

["string"]

to_array(`0`)

[0]

to_array(`true`)

[true]

to_array(`{"foo": "bar"}`)

[{"foo": "bar"}]

to_string

string to_string(any $arg)
  • 字符串-返回传入的值。

  • number/array/object/boolean—对象的JSON编码值。JSON编码器应该发出编码的JSON值,而不添加任何额外的新行。

实例

表情

结果

to_string(`2`)

"2"

to_number

number to_number(any $arg)
  • 字符串-返回解析后的数字。任何符合 json-number 支持生产。请注意,浮点数支持将是特定于实现的,但是实现应该至少支持ieee754-2008二进制64(双精度)数字,因为这是普遍可用的并且被广泛使用的。

  • number-返回传入的值。

  • 数组-空

  • 对象-空

  • 布尔值-空

  • 空-空

类型

string type(array|object|string|number|boolean|null $subject)

返回给定的 $subject 参数作为字符串值。

返回值必须是以下值之一:

  • 一串

  • 布尔

  • 数组

  • 对象

  • 无效的

实例

鉴于

表情

结果

“福”

type(@)

“字符串”

true

type(@)

“布尔值”

false

type(@)

“布尔值”

null

type(@)

“空”

123

type(@)

123.05

type(@)

["abc"]

type(@)

“数组”

{"abc": "123"}

type(@)

“对象”

价值观

array values(object $obj)

返回对象的值。请注意,由于JSON哈希是继承无序的,因此与提供的对象关联的值 obj 继承无序。实现不需要以任何特定顺序返回值。例如,给定输入:

{"a": "first", "b": "second", "c": "third"}

表达式 values(@) 可能有以下任何返回值:

  • ["first", "second", "third"]

  • ["first", "third", "second"]

  • ["second", "first", "third"]

  • ["second", "third", "first"]

  • ["third", "first", "second"]

  • ["third", "second", "first"]

如果您想要特定的订单,请考虑使用 sortsort_by 功能。

实例

鉴于

表情

结果

{"foo": "baz", "bar": "bam"}

values(@)

["baz", "bam"]

["a", "b"]

values(@)

<error: invalid-type>

false

values(@)

<error: invalid-type>

管道表达式

pipe-expression  = expression "|" expression

管道表达式组合两个表达式,用分隔符分隔 | 性格。它类似于 sub-expression 有两个重要区别:

  1. 任何表达式都可以用在右手边。A sub-expression 限制可在右侧使用的表达式类型。

  2. A pipe-expression stops projections on the left hand side for propagating to the right hand side. If the left expression creates a projection, it does not apply to the right hand side.

例如,给定以下数据:

{"foo": [{"bar": ["first1", "second1"]}, {"bar": ["first2", "second2"]}]}

表达式 foo[*].bar 给出的结果是:

[
    [
        "first1",
        "second1"
    ],
    [
        "first2",
        "second2"
    ]
]

表达的第一部分, foo[*] ,创建投影。此时,剩下的表达式, bar 映射到从创建的列表的每个元素上 foo[*] . 如果你把 [0] 表达式,则从每个子列表中获取第一个元素。表达式 foo[*].bar[0] 将返回:

["first1", "first2"]

如果你愿意 only 第一个子列表, ["first1", "second1"] ,可以使用 pipe-expression ::

foo[*].bar[0] -> ["first1", "first2"]
foo[*].bar | [0] -> ["first1", "second1"]

实例

search(foo | bar, {"foo": {"bar": "baz"}}) -> "baz"
search(foo[*].bar | [0], {
    "foo": [{"bar": ["first1", "second1"]},
            {"bar": ["first2", "second2"]}]}) -> ["first1", "second1"]
search(foo | [0], {"foo": [0, 1, 2]}) -> [0]