功能

JEP

3

作者

迈克尔·道林,詹姆斯·萨耶维尼

状态

认可的

创建

2013年11月27日

摘要

本文件建议修改 JMESPath grammar 支持函数表达式。

动机

函数允许用户轻松转换和过滤JMESPath表达式中的数据。由于JMESPath目前是实现的,函数在 multi-select-listmulti-select-hash 表达式来格式化表达式的输出,以包含可能不在原始JSON输入中的数据。与过滤表达式相结合,函数将是一个强大的机制来执行任何类型的特殊比较,例如 length()contains() 等。

数据类型

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

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

  • 一串

  • 布尔 (truefalse

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

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

  • 无效的

语法更改

函数在中定义 function-expression 规则如下。函数表达式是 expression 在任何地方都是有效的 expression 是允许的。

语法需要添加以下语法:

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

expression 将需要更新以添加 function-expression 生产:

expression        = sub-expression / index-expression / or-expression / identifier / "*"
expression        =/ multi-select-list / multi-select-hash
expression        =/ literal / function-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)

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

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

return_type foo(array[number] $argname)

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

下面的第一个函数, 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": -11, "bar": 2"}) -> -1
    
  2. 验证已解析参数的类型。在这种情况下 -1 属于类型 number 所以它通过了类型检查。

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

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

    abs(foo) .

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

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

    search(foo, {"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
    
  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, array|object|string|number|boolean $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

塞尔

number ceil(number $value)

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

实例

表情

结果

ceil(`1.001`)

2

ceil(`1.9`)

2

ceil(`1`)

1

ceil(`abc`)

null

地板

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)

返回包含所提供对象的键的数组。

实例

鉴于

表情

结果

{"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

最大值

number max(array[number] $collection)

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

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

实例

鉴于

表情

结果

[10, 15]

max(@)

15

[10, false, 20]

max(@)

<error: invalid-type>

number min(array[number] $collection)

返回在提供的 $collection 争论。

实例

鉴于

表情

结果

[10, 15]

min(@)

10

[10, false, 20]

min(@)

<error: invalid-type>

分类

array sort(array $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

to_string

string to_string(string|number|array|object|boolean $arg)
  • 字符串-返回传入的值。

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

实例

鉴于

表情

结果

null

to_string(`2`)

"2"

to_number

number to_number(string|number $arg)
  • 字符串-返回解析后的数字。任何符合 json-number 支持生产。

  • 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)

返回所提供对象的值。

实例

鉴于

表情

结果

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

values(@)

["baz", "bam"]

["a", "b"]

values(@)

<error: invalid-type>

false

values(@)

<error: invalid-type>

符合性测试

A functions.json 将添加到符合性测试套件中。测试套件将添加以下新错误类型:

  • 未知函数

  • 无效arity

  • 无效的类型

合规性没有规定 when 将引发错误,因为这将取决于实现细节。为了使实现兼容,它们需要指示在尝试计算JMESPath表达式时发生错误。

历史

  • 这个JEP最初提出了字面语法。这个JEP的文字部分被删除并添加到jep7中。

  • 这个JEP最初指定类型匹配应该返回null。它已被更新以指定应该发生无效类型错误。