JMESPath教程¶
这是JMESPath语言的教程。JMESPath是一种JSON查询语言。您可以从JSON文档中提取和转换元素。下面的例子是交互式的。您可以更改JMESPath表达式并看到结果自动更新。
对于这些示例中的每一个,JMESPath表达式都应用于左侧的输入JSON,计算JMESPath表达式的结果显示在右侧的JSON文档中。
基本表达式¶
最简单的JMESPath表达式是 identifier ,它选择JSON对象中的键:
Result
尝试将上面的表达式更改为 b
和 c
注意更新的结果。还请注意,如果引用的键不存在,则值 null
(或相当于 null
)返回。
你可以使用 subexpression 要返回JSON对象中的嵌套值,请执行以下操作:
Result
如果引用的键不存在,则值为 null
返回。尝试随后访问标识符将继续返回值 null
. 尝试将表达式更改为 b.c.d.e
上面。
Index Expressions 允许您选择列表中的特定元素。它应该类似于通用编程语言中的数组访问。索引基于0。
Result
如果指定的索引大于列表,则值为 null
返回。您也可以使用负索引从列表末尾开始索引。 [-1]
引用列表中的最后一个元素, [-2]
引用倒数第二个元素。在上面的例子中尝试一下。
您可以组合标识符、子表达式和索引表达式来访问JSON元素。
Result
切片¶
切片允许您选择数组的连续子集。如果您曾经在python中使用过切片,那么您已经知道如何使用JMESPath切片。在最简单的形式中,可以指定起始索引和结束索引。结束索引是您所做的第一个索引 not 希望包括在切片中。让我们看看一些例子。首先,给定一个0到9的整数数组,让我们选择数组的前半部分:
Result
此切片结果包含元素0、1、2、3和4。不包括索引5处的元素。如果要选择数组的后半部分,可以使用以下表达式:
Result
上面的两个例子可以缩短。如果 start
或 step
值被省略,它被假定为数组的开始或结束。例如:
Result
尝试修改上面的示例,使其仅包含数组元素的后半部分,而不指定 10
.
切片的一般形式是 [start:stop:step]
. 到目前为止,我们已经了解了 [start:stop]
形式。默认情况下 step
价值是 1
,这意味着包含 start
和 stop
价值观。但是,我们可以使用step值跳过元素。例如,只从数组中选择偶数元素。
Result
还要注意在这个例子中我们省略了 start
以及 stop
值,即使用 0
对于 start
价值,以及 10
对于 stop
价值观。在本例中,表达式 [::2]
等于 [0:10:2]
.
关于切片的最后一件事是,就像索引单个值一样,所有值都可以是负数。如果 step
值为负,则按相反的顺序创建切片。例如:
Result
上面的表达式以相反的顺序创建一个切片。
如果您想了解切片如何工作的所有详细信息,请查看 section in the JMESPath specification .
预测¶
投影是JMESPath的关键特性之一。它允许您将表达式应用于元素集合。有五种投影:
列出投影
切片投影
物体投影
展平投影
过滤投影
列表和切片投影¶
A wildcard expression 创建一个列表投影,它是一个JSON数组上的投影。这最好用一个例子来说明。假设我们有一个描述一个人的JSON文档,每个数组元素都是一个JSON对象,它有一个 first
, last
和 age
钥匙。假设我们想要一份名单上所有的名字。
Result
在上面的示例中, first
表达式(它只是一个标识符)应用于 people
数组。结果被收集到一个JSON数组中,并作为表达式的结果返回。表达式可以比基本表达式更复杂 identifier
.例如,表达式 foo[*].bar.baz[0]
会投射出 bar.baz[0]
中每个元素的表达式 foo
数组。
在使用投影时,有几点要记住。这些将在 wildcard expressions 一节,但要点是:
预测评估分为两个步骤。左侧(LHS)创建一个初始值的JSON数组。投影的右侧(RHS)是要为左侧创建的JSON数组中的每个元素投影的表达式。在计算左手侧和/或右手侧时,每种投影类型的语义略有不同。
如果表达式投影到单个数组元素上的结果是
null
,则从收集的结果集中忽略该值。可以使用管道表达式停止投影(稍后讨论)。
列表投影仅对JSON数组有效。如果值不是列表,则表达式的结果是
null
.
你可以在上面的演示中试试这个。注意如何 people[*].first
只包含三个元素,尽管人员数组有四个元素。这是因为最后一个元素, {{"missing": "different"}}
评估到 null
当表达式 first
已应用,并且 null
值不会添加到收集的结果数组中。如果你试试这个表达式 foo[*].bar
您将看到 null
,因为与 foo
key是一个JSON对象,而不是一个数组,列表投影只为JSON数组定义。
切片投影与列表投影几乎相同,只是左侧是对切片求值的结果,它可能不包括原始列表中的所有元素:
Result
物体投影¶
列表投影是为JSON数组定义的,而对象投影是为JSON对象定义的。可以使用创建对象投影 *
语法。这将创建JSON对象的值列表,并将投影的右侧投影到值列表上。
Result
在上面的示例中, *
创建一个JSON数组,该数组包含和 ops
JSON对象。投影的右侧, numArgs
,然后应用于JSON数组,从而得到 [2, 3]
. 下面是一个示例演练,演示了一个实现如何 潜在地 实现对对象投影的求值。首先,物体投影可以分解为两个部分,左手边(LHS)和右手边(RHS):
LHS :
ops
RHS :
numArgs
首先,评估LHS以创建要投影的初始阵列:
evaluate(ops, inputData) -> [{"numArgs": 2}, {"numArgs": 3},
{"variadic": True}]
然后将RHS应用于数组中的每个元素:
evaluate(numArgs, {numArgs: 2}) -> 2
evaluate(numArgs, {numArgs: 3}) -> 3
evaluate(numArgs, {variadic: true}) -> null
任何 null
值不包括在最终结果中,因此整个表达式的结果是 [2, 3]
.
展平投影¶
JMESPath表达式中可以使用多个投影。对于列表/对象投影,在投影中创建投影时,原始文档的结构将保留。例如,让我们来看看表达式 reservations[*].instances[*].state
. 此表达式表示顶级键 reservations
以数组作为值。对于每个数组元素,投射 instances[*].state
表达式。在每个列表元素中,都有一个 instances
键本身就是一个值,我们为列表中的每个列表元素创建一个子投影。下面是一个例子:
Result
这个表达式的结果是 [["running", "stopped"], ["terminated", "running"]]
,这是一个列表列表。外部列表来自 reservations[*]
,而内部列表是 state
创建自 instances[*]
::
1st r0 r1
2nd i0 i1 i0 i1
[["running", "stopped"], ["terminated", "running"]]
如果我们只需要实例的所有状态的列表呢?我们最理想的结果是 ["running", "stopped", "terminated", "running"]
. 在这种情况下,我们不关心实例属于哪个保留,我们只需要一个状态列表。
这是一个问题 Flatten Projection 解决方案。要获得所需的结果,可以使用 []
而不是 [*]
要展开列表: reservations[].instances[].state
. 试着换衣服 [*]
到 []
在上面的表达式中查看结果是如何变化的。
而 spec 更详细地说,这是一个简单的经验法则,用于“展平”操作符, []
,是不是:
它将子列表展平到父列表中(不是递归的,只是一个级别)。
它将创建一个投影,因此展平投影RHS上的任何内容都将投影到新创建的展平列表上。
你也可以用 []
单凭一己之力就可以把名单压平:
Result
如果你再把表达式的结果展平, [][]
,你会得到一个结果 [0, 1, 2, 3, 4, 5, 6, 7]
. 在上面的例子中尝试一下。
过滤投影¶
到目前为止,我们已经看到:
列表/切片投影
物体投影
展平投影
计算投影的RHS是滤波器的一种基本类型。如果针对单个元素计算的表达式结果导致 null
,则从最终结果中排除元素。
过滤投影允许您过滤投影的左侧 之前 计算投影的RHS。
例如,假设我们有一个机器列表,每个机器都有一个 name
和A state
. 我们想要所有正在运行的机器的名称。在伪代码中,这将是:
result = []
foreach machine in inputData['machines']
if machine['state'] == 'running'
result.insert_at_end(machine['name'])
return result
可以使用过滤器投影来实现这一点:
Result
试着换衣服 running
到 stopped
在上面的例子中。也可以删除 .name
如果您只需要具有指定状态的每台机器的整个JSON对象,则在表达式的末尾。
筛选器表达式是为数组定义的,具有通用形式 LHS [? <expression> <comparator> <expression>] RHS
. 这个 filter expression spec详细说明了可用的比较器及其工作原理,但支持标准比较器,即 ==, !=, <, <=, >, >=
.
管道表达式¶
投影是JMESPath中的一个重要概念。但是,有时投影语义 not 你想要什么。一个常见的情况是当您想要操作 结果 而不是将表达式投射到数组中的每个元素上。例如,表达式 people[*].first
将为您提供一个数组,其中包含人员数组中每个人的名字。如果你想要列表中的第一个元素呢?如果你试过了 people[*].first[0]
你刚刚评估的 first[0]
对于people数组中的每个元素,由于没有为字符串定义索引,最终结果将是空数组, []
. 要获得所需的结果,可以使用管道表达式, <expression> | <expression>
,表示投影必须停止。如下例所示:
Result
在上面的示例中,列表投影的RHS是 first
. 当遇到管道时,到该点的结果将传递给管道表达式的RHS。管道表达式的计算结果为:
evaluate(people[*].first, inputData) -> ["James", "Jacob", "Jayden"]
evaluate([0], ["James", "Jacob", "Jayden"]) -> "James"
MultiSelect¶
到目前为止,我们已经研究了JMESPath表达式,这些表达式有助于将JSON文档缩减为您感兴趣的元素。下一个概念, multiselect lists 和 multiselect hashes 允许您创建JSON元素。这允许您创建JSON文档中不存在的元素。multiselect列表创建一个列表,multiselect散列创建一个JSON对象。
这是一个多选择列表的示例:
Result
在上面的表达式中 [name, state.name]
部分是一个多选列表。它说要创建一个包含两个元素的列表,第一个元素是 name
表达式,第二个元素是 state.name
. 因此,每个list元素将创建一个双元素列表,整个表达式的最终结果是两个元素列表的列表。
与投影不同,表达式的结果始终包含在内,即使结果为空。如果将上述表达式更改为 people[].[foo, bar]
每个两个元素列表 [null, null]
.
multiselect具有与multiselect列表相同的基本概念,只是它创建了一个散列而不是数组。使用上面的同一个例子,如果我们想创建一个有两个键的两个元素散列, Name
和 State
,我们可以用这个:
Result
功能¶
JMESPath支持函数表达式,例如:
Result
函数可用于以强大的方式转换和过滤数据。可以找到完整的函数列表 here 和 function expression 规范有完整的细节。
下面是一些函数的示例。
此示例打印 people
数组:
Result
函数也可以与过滤器表达式组合使用。在下面的示例中,JMESPath表达式查找 myarray
包含字符串的 foo
.
Result
这个 @
上例中的字符引用正在计算的当前元素 myarray
. 表达式 contains(@, `foo`)
将返回 true
如果 myarray
数组包含字符串 foo
.
而 function expression spec提供了所有细节,在使用函数时需要记住以下几点:
函数参数具有类型。如果函数的参数类型错误,则
invalid-type
将发生错误。有些函数可以进行类型转换 (to_string
,to_number
)以帮助将参数转换为其正确类型。如果使用错误数量的参数调用函数,则
invalid-arity
将会发生。
下一步¶
我们现在已经看到了JMESPath语言的概述。接下来要做的是:
见 JMESPath示例 . 您将看到超出教程范围的常见JMESPath表达式。您还将看到如何将多个特性组合在一起,以便最好地利用JMESPath表达式。
要真正开始使用JMESPath,请选择您选择的语言,并查看 JMESPath库 有关在所选语言中使用JMESPath的更多信息,请访问。
阅读 JMESPath Spec ,它有官方的ABNF语法和语言语义的全部细节。