
# 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。
  函数可用于以强大的方式转换和过滤数据。完整的函数列表请参考[内置函数列表](https://support.huaweicloud.com/hcli_faq/hcli_23_002_02.html)。
  以下是一些函数示例：
  此示例打印了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结果。
   
 
