JMESPath表达式的用法有哪些?
JMESPath表达式的用法如下:
- 基本表达式
- 标识符:
最简单的JMESPath表达式是标识符,它在json对象中选择一个键:
{"a": "foo", "b": "bar", "c": "baz"}
对于如上的 json 内容,当表达式为"a" 时,可获取结果:"foo"。
另请注意,如果指定一个不存在的键,KooCLI会提示错误告警信息并输出原json结果。
- 子表达式:
{"a": {"b": {"c": {"d": "value"}}}}
对于如上的json内容,当表达式为"a.b.c.d" 时,可获取结果:"value"。
如果指定是不存在的键,KooCLI会提示错误告警信息并输出原json结果。
- 索引表达式:
["a", "b", "c", "d", "e", "f"]
对于如上的json内容,当表达式为"[1]" 时,可获取结果:"b"。
如果指定了大于列表的索引,KooCLI会提示错误告警信息并输出原json结果。用户也可以使用负索引从列表末尾到索引。 [-1]指列表中的最后一个元素,[-2]指倒数第二个元素。
- 可以将标识符、子表达式和索引表达式组合在一起,以访问 json 元素:
{"a": { "b": { "c": [ {"d": [0, [1, 2]]}, {"d": [3, 4]} ] } }}
对于如上的json内容,当表达式为"a.b.c[0].d[1][0]" 时,可获取结果:1。
- 标识符:
- 切片
切片的一般形式是[开始:停止:步长]。一般多使用默认步长值1,故其形式也可以是[开始:停止]。切片允许用户选择数组的连续子集。在JMESPath最简单的形式中,用户可以指定起始索引和结束索引。结尾索引的值不会被包含在结果中:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
对于如上的json内容,当表达式为"[0:5]" 时,可获取如下结果:
[ 0, 1, 2, 3, 4 ]
此切片结果包含索引 0、1、2、3和4的元素。不包括索引5中的元素。
当表达式为"[5:10]" 时,可获取如下结果:
[ 5, 6, 7, 8, 9 ]
上面的两个例子中的表达式可以缩短。如果省略了开始或停止值,则默认从数组的第一个元素开始或至最后一个元素停止。例如:
当表达式为"[:5]" 时,可获取如下结果:
[ 0, 1, 2, 3, 4 ]
默认情况下,步长值为1,这意味着选择了在开始和停止值范围内的每个元素。用户也可以使用步长跳过元素。例如,仅从数组中选择偶数元素:当表达式为"[::2]" 时,可获取如下结果:[ 0, 2, 4, 6, 8 ]
另需注意,在此示例中,省略了开始和停止值,这意味着使用0表示开始值,10用于停止值。在此示例中,表达式 [::2]等于[0:10:2]。
如果步长为负值,则切片按相反顺序创建。例如:当表达式为"[::-1]" 时,可获取如下结果:
[ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]
- 投影
投影是JMESPath的主要特征之一。它允许用户将表达式应用于元素集合。投影共分为五种:列表投影,切片投影,对象投影,扁平投影,过滤投影。
- 列表投影
{ "people": [ {"first": "James", "last": "d"}, {"first": "Jacob", "last": "e"}, {"first": "Jayden", "last": "f"}, {"missing": "different"} ], "foo": {"bar": "baz"} }
对于如上的json内容,当表达式为"people[*].first"时,可获取如下结果:
[ "James", "Jacob", "Jayden" ]
在上面的示例中,表达式中的“first”应用于people数组中的每个元素。结果被收集到一个json数组中并作为表达式的结果返回。例如,表达式foo[*].bar.baz[0]会将 bar.baz[0]表达式投影到foo数组中的每个元素。
使用投影时需要记住如下要点:
- 投影被评估为两个步骤。左侧 (LHS) 创建初始值的json数组。投影的右侧 (RHS) 是为左侧创建的json数组中的每个元素进行投影的表达式。在评估左侧与右侧时,每种投影类型的语义略有不同。
- 如果投影到单个数组元素上的表达式的结果为null,则该值将从收集的结果集中省略。
- 您可以使用管道表达式(稍后讨论)停止投影。
- 列表投影仅对json数组有效。如果左侧 (LHS) 无法创建初始值的json数组,KooCLI会提示错误告警信息并输出原json结果。
注意 people[*].first 的结果只包含三个元素,即使people数组有四个元素。这是因为应用表达式时,最后一个元素{"missing": "different"}的值为null,故未将null值添加到收集的结果数组中;如果尝试使用表达式 foo[*].bar,KooCLI会提示错误告警信息并输出原json结果,因为与foo键关联的值是一个json对象,而不是一个数组。
- 切片投影
切片投影几乎与列表投影相同,不同之处在于左侧是切片的计算结果,它可能不包括原始列表中的所有元素:
{ "people": [ {"first": "James", "last": "d"}, {"first": "Jacob", "last": "e"}, {"first": "Jayden", "last": "f"}, {"missing": "different"} ], "foo": {"bar": "baz"} }
对于如上的json内容,当表达式为"people[:2].first" 时,可获取如下结果:
[ "James", "Jacob" ]
- 对象投影
列表投影是为json数组定义的,而对象投影是为json对象定义的。用户可以使用“*”创建对象投影。这将创建json对象的值列表,并将投影的右侧投影到值列表上。
{ "ops": { "functionA": {"numArgs": 2}, "functionB": {"numArgs": 3}, "functionC": {"variadic": true} } }
对于如上的json内容,当表达式为"ops.*.numArgs" 时,可获取如下结果:
[ 2, 3 ]
对象投影可以分解为两个部分,左侧 (LHS) 为“ops”,右侧 (RHS)为“numArgs”。在上面的示例中,“*”创建了一个与LHS的值"ops"所对应的json对象关联的json数组。然后将投影的RHS的值“numArgs”应用于json数组,从而生成[2, 3]的最终数组。
下面分步骤演示该对象投影的过程:
- 扁平投影
在JMESPath表达式中可以使用多个投影。在列表/对象投影的情况下,在上一个投影中创建下一个投影时,会保留原始的数据结构:
{ "reservations": [ { "instances": [ {"state": "running"}, {"state": "stopped"} ] }, { "instances": [ {"state": "terminated"}, {"state": "running"} ] } ] }
对于如上的json内容,当表达式为"reservations[*].instances[*].state" 时,意思是:顶级键“reservations”的值为数组,对于reservations数组中的每个元素,投影instances[*].state表达式;在数组reservations的每个元素中,都有键“instances”的值为数组,为instances数组中的每个元素投影state表达式。可获取如下结果:
[ [ "running", "stopped" ], [ "terminated", "running" ] ]
它是一个嵌套列表。外部列表来自reservations[*]的投影,内部列表是从instances[*]创建的state的投影。
如果不关心“instances”属于哪个“reservations”,只关心所有“state”的列表时该怎么处理?即希望结果为:
[ "running", "stopped", "terminated", "running" ]
这就是扁平投影解决的问题。要获得所需的结果,可以使用“[]”而不是“[*]”来扁平化列表,即:表达式为"reservations[].instances[].state"。
使用展平运算符“[]”的要点是:
- 它将子列表展平到父列表中(不是递归的,只作用于一个层级)。
- 它会创建一个投影,因此扁平投影的RHS上的任何内容都会投影到新创建的扁平列表上。
用户也可以单独使用“[]”来展平列表:
[ [0, 1], 2, [3], 4, [5, [6, 7]] ]
对于如上的json内容,当表达式为"[]" 时,可获取如下结果:
[ 0, 1, 2, 3, 4, 5, [ 6, 7 ] ]
如果希望再次将结果的内容展平,当表达式为"[][]" 时,则会获得 [0、1、2、3、4、5、6、7] 的结果。
- 过滤投影
{ "machines": [ {"name": "a", "state": "running"}, {"name": "b", "state": "stopped"}, {"name": "b", "state": "running"} ] }
对于如上的json内容,当表达式为"machines[?state=='running'].name" 时,可获取如下结果:
[ "a", "b" ]
过滤表达式是为数组定义的,具有一般形式LHS[?<表达式><比较符><表达式>]RHS。该过滤表达式支持的比较符有:==, !=, <, <=, >, >=。
- 列表投影
- 管道表达式
投影是JMESPath中的一个重要概念。但是,有时投影结果并不理想。一个常见的场景是当用户想要对投影的结果进行运算,而不是仅将表达式投影到数组中的每个元素上。例如:
{ "people": [ {"first": "James", "last": "d"}, {"first": "Jacob", "last": "e"}, {"first": "Jayden", "last": "f"}, {"missing": "different"} ], "foo": {"bar": "baz"} }
表达式people[*].first将为您提供一个数组,其中包含people数组中每个人的名字。如果想要该数组中的第一个元素怎么办?倘若使用表达式people[*].first[0],将只是为people数组中的每个元素计算first[0],并且因为没有为字符串定义索引,最终结果将是一个空数组“[]”。要得到所需的结果,可以使用管道表达式<表达式> | <表达式>。对于如上的json内容,当表达式为"people[*].first | [0]" 时,可获取结果:"James"。
在上面的例子中,列表投影的RHS是“first”。遇到管道时,结果将传递给管道表达的RHS。管道表达式处理的过程为:
- 评估(people[*].first, inputData) -> ["James", "Jacob", "Jayden"]
- 评估([0], ["James", "Jacob", "Jayden"]) -> "James"
- 多选
多选分为多选列表和多选哈希。多选允许您创建json数据中不存在的元素。其中:多选列表创建一个列表,多选哈希创建一个json对象。
- 多选列表
{ "people": [ { "name": "a", "state": {"name": "up"} }, { "name": "b", "state": {"name": "down"} }, { "name": "c", "state": {"name": "up"} } ] }
对于如上的json内容,当表达式为"people[].[name,state.name]" 时,可获取如下结果:
[ [ "a", "up" ], [ "b", "down" ], [ "c", "up" ] ]
在上面的表述中,[name,state.name]部分是多选列表。该表达式表示要创建两个元素的列表,第一个元素是针对列表元素评估name表达式的结果,第二个元素是评估state.name的结果。因此,每个列表元素都会创建一个双元素列表,整个表达式的最终结果是一个包含两个元素列表的列表。
与投影不同,表达式的结果始终包含在内,即使结果为空。如果将上述表达式更改为people[].[foo,bar],每个双元素列表将是[null, null]:
[ [ null, null ], [ null, null ], [ null, null ] ]
- 多选哈希
多选哈希与多选列表的基本思想相同,只是它创建的是散列而不是数组:
{ "people": [ { "name": "a", "state": {"name": "up"} }, { "name": "b", "state": {"name": "down"} }, { "name": "c", "state": {"name": "up"} } ] }
对于如上的json内容,当表达式为"people[].{Name:name,State:state.name}" 时,可获取如下结果:
[ { "Name": "a", "State": "up" }, { "Name": "b", "State": "down" }, { "Name": "c", "State": "up" } ]
- 多选列表
- 函数
{ "people": [ { "name": "b", "age": 30, "state": {"name": "up"} }, { "name": "a", "age": 50, "state": {"name": "down"} }, { "name": "c", "age": 40, "state": {"name": "up"} } ] }
对于如上的json内容,当表达式为"length(people)" 时,可获取结果:3。
函数可用于以强大的方式转换和过滤数据。完整的函数列表请参考内置函数列表。
以下是一些函数示例:
此示例打印了people数组中年龄最大的人的姓名:
{ "people": [ { "name": "b", "age": 30 }, { "name": "a", "age": 50 }, { "name": "c", "age": 40 } ] }
对于如上的json内容,当表达式为"max_by(people,&age).name" 时,可获取结果:"a"。
函数也可以与过滤表达式结合使用。在下面的示例中,JMESPath表达式查找myarray数组中包含字符串“foo”的所有元素:
{ "myarray": [ "foo", "foobar", "barfoo", "bar", "baz", "barbaz", "barfoobaz" ] }
对于如上的json内容,当表达式为"myarray[?contains(@,'foo')==`true`]" 时,可获取如下结果:
[ "foo", "foobar", "barfoo", "barfoobaz" ]
上面示例中的“@”字符指的是“myarray”中正在评估的当前元素。如果myarray数组中的当前元素包含字符串“foo”,则表达式contains(@,`foo`)将返回true。
使用函数时需要注意以下几点:
- 函数参数有类型限制。如果函数的参数类型错误,KooCLI会提示错误告警信息并输出原json结果。有些函数可以进行类型转换(to_string、to_number)以帮助将参数转换为正确的类型。
- 函数参数有个数限制。如果调用函数时入参个数错误,KooCLI会提示错误告警信息并输出原json结果。