更新时间:2023-05-22 GMT+08:00

JMESPath表达式的用法有哪些?

JMESPath表达式的用法如下:

  • 基本表达式
    • 标识符:

      最简单的JMESPath表达式是标识符,它在json对象中选择一个键:

      {"a": "foo", "b": "bar", "c": "baz"}

      对于如上的 json 内容,当表达式为"a" 时,可获取结果:"foo"。

      另请注意,如果指定一个不存在的键,KooCLI会提示错误告警信息并输出原json结果。

    • 子表达式:

      使用子表达式返回json对象中的嵌套值:

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

      对于如上的json内容,当表达式为"a.b.c.d" 时,可获取结果:"value"。

      如果指定是不存在的键,KooCLI会提示错误告警信息并输出原json结果。

    • 索引表达式:

      索引表达式允许您在列表中选择特定元素,起始索引位为0:

      ["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的主要特征之一。它允许用户将表达式应用于元素集合。投影共分为五种:列表投影,切片投影,对象投影,扁平投影,过滤投影。

    • 列表投影

      用通配符表达式创建列表投影,它是对json数组的投影。

      {
        "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]的最终数组。

      下面分步骤演示该对象投影的过程:

      1. 评估LHS以创建要投影的初始数组:

        评估(ops,原json数据)-> [{"numArgs": 2}, {"numArgs": 3},{"variadic": True}]

      2. 评估RHS应用于数组中的每个元素:

        评估(numArgs, {numArgs: 2}) -> 2

        评估(numArgs, {numArgs: 3}) -> 3

        评估(numArgs, {variadic: true}) -> null

      3. 任何空值都不包括在最终结果中,因此整个表达的结果是[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] 的结果。

    • 过滤投影

      过滤投影允许在评估投影的RHS之前过滤投影的 LHS:

      {
        "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。管道表达式处理的过程为:

    1. 评估(people[*].first, inputData) -> ["James", "Jacob", "Jayden"]
    2. 评估([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"
        }
      ]
  • 函数

    JMESPath支持函数表达式,例如:

    {
      "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结果。