zoukankan      html  css  js  c++  java
  • jmespath(2)投影Projections

    投影

    投影是JMESPath的关键特性之一。它允许您将表达式应用于元素集合。有五种投影:

    • 列表投影
    • 切片投影
    • 对象投影
    • 展平投影
    • 过滤投影
       

    处理投影需要注意的点

    • 投影分为两个步骤。左侧(LHS)创建一个初始值的JSON数组。投影的右侧(RHS)是要为左侧创建的JSON数组中的每个元素投影的表达式。在计算左侧和/或右侧时,每个投影类型的语义略有不同。
    • 如果投射到单个数组元素上的表达式的结果为null,则从收集的结果集中忽略该值。
    • 可以使用管道表达式停止投影(稍后讨论)。
    • 列表投影仅对JSON数组有效。如果值不是列表,则表达式的结果为null。
       

    写法说明

    • []:将子列表展平到父列表中
    • .:取字典
    • *:遍历每个元素
       

    列表投影

    在一个列表中嵌套了字典,而且每一个元素都是一个json对象,它有2个key键,分别是first、last,如果你想拿到first下的所有value怎么办呢?

    import jmespath
    
    
    dic_1 = {
      "people": [
        {"first": "James", "last": "d"},
        {"first": "Jacob", "last": "e"},
        {"first": "Jayden", "last": "f"},
        {"missing": "different"}
      ],
      "foo": {"bar": "baz"}
    }
    path = jmespath.search("people[*].first", dic_1)
    print(path)
    
    # 运行结果
    ['James', 'Jacob', 'Jayden']
    

    在上面的示例中,people[*]代表people下所有的元素,people[*].first代表people下所有的元素中获取key为first的元素值,结果被收集到一个JSON数组中,并作为表达式的结果返回
    虽然people数组中有4个元素,但是最后一个{"missing": "different"}的值为null,并不会将null值添加到收集的结果数组中
     
    还有,列表投影仅对列表有效,如果值不是列表,比如是对象,那么表达式的结果为null

    import jmespath
    
    
    dic_1 = {
      "people": [
        {"first": "James", "last": "d"},
        {"first": "Jacob", "last": "e"},
        {"first": "Jayden", "last": "f"},
        {"missing": "different"}
      ],
      "foo": {"bar": "baz"}
    }
    path = jmespath.search("foo[*]", dic_1)
    print(path)
    
    # 结果
    None
    

    以上代码foo是一个对象,并不是列表,所以这里返回的是None
     

    切片投影

    切片投影几乎与列表投影相同,但左侧是评估切片的结果,该切片可能未包括原始列表中的所有元素

    import jmespath
    
    
    dic_1 = {
      "people": [
        {"first": "James", "last": "d"},
        {"first": "Jacob", "last": "e"},
        {"first": "Jayden", "last": "f"},
        {"missing": "different"}
      ],
      "foo": {"bar": "baz"}
    }
    path = jmespath.search("people[:2].first", dic_1)
    print(path)
    
    # 结果
    ['James', 'Jacob']
    

    这里是先从people数组中取出前二个变为[{"first": "James", "last": "d"},{"first": "Jacob", "last": "e"}],然后再取出字段为first的元素值
     

    对象投影

    列表投影是为JSON数组定义的,而对象投影是为JSON对象定义的。可以使用*语法创建对象投影。这将创建JSON对象的值列表,并将投影的右侧投影到值列表上。

    import jmespath
    
    
    dic_1 = {
      "ops": {
        "functionA": {"numArgs": 2},
        "functionB": {"numArgs": 3},
        "functionC": {"variadic": True}
      }
    }
    path = jmespath.search("ops.*.numArgs", dic_1)
    print(path)
    
    # 结果
    [2, 3]
    

    ops.*.numArgs中的通配符*我们可以看做一个分界线,分为左边和右边,即左边ops,右边numArgs
    第一步,左边初始化了一个可以投影的数组:

    evaluate(ops, inputData) -> [{"numArgs": 2}, {"numArgs": 3},
                                 {"variadic": True}]
    

    第二步,右边遍历数组里的每一个元素:

    evaluate(numArgs, {numArgs: 2}) -> 2
    evaluate(numArgs, {numArgs: 3}) -> 3
    evaluate(numArgs, {variadic: true}) -> null
    

    但是因为variadic这个key与 numArgs不匹配,所以返回的是null
    而对于null,是不会添加到最终返回的结果数组里的,所以最终结果只有[2, 3]
     

    展平投影

    JMESPath表达式中可以使用多个投影。在列表/对象投影的情况下,在投影中创建投影时保留原始文档的结构。
    例如,让我们以表达式reservations[*].instances[*].state为例。这个表达式表示顶级键保留有一个数组作为值。对于每个数组元素,投影实例[*].state表达式。在每个列表元素中,有一个实例键,它本身就是一个值,我们为列表中的每个列表元素创建一个子投影。下面是一个例子:

    import jmespath
    
    
    dic_1 = {
      "reservations": [
        {
          "instances": [
            {"state": "running"},
            {"state": "stopped"}
          ]
        },
        {
          "instances": [
            {"state": "terminated"},
            {"state": "running"}
          ]
        }
      ]
    }
    path = jmespath.search("reservations[*].instances[*].state", dic_1)
    print(path)
    
    # 结果
    [['running', 'stopped'], ['terminated', 'running']]
    

    此表达式的结果是[[“running”,“stopped”],[“terminated”,“running”]],其实最外层的[] 就是 reservations[*]创建的,而内部的每一个实例instances[*],也会各自再创建出投影列表,所以结果中最外层的[]里包含了2个子元素[]。
    如果我们只需要一个实例所有状态的列表呢?理想情况下,我们希望得到一个结果[“running”,“stopped”,“terminated”,“running”]。在这种情况下,我们不关心实例属于哪个保留,我们只需要一个状态列表。
    我们可以使用[]而不是[*]来展平列表,表达式:reservations[].instances[].state

    import jmespath
    
    
    dic_1 = {
      "reservations": [
        {
          "instances": [
            {"state": "running"},
            {"state": "stopped"}
          ]
        },
        {
          "instances": [
            {"state": "terminated"},
            {"state": "running"}
          ]
        }
      ]
    }
    path = jmespath.search("reservations[].instances[].state", dic_1)
    print(path)
    
    # 结果
    ['running', 'stopped', 'terminated', 'running']
    

    总结:

    • []将子列表展平到父列表中(不是递归的,只是一个级别)。
    • []会创建一个投影,因此展平投影右侧的任何内容都会投影到新创建的展平列表中。

    您也可以单独使用[]来展平列表:

    import jmespath
    
    
    dic_1 = [
      [0, 1],
      2,
      [3],
      4,
      [5, [6, 7]]
    ]
    path = jmespath.search("[]", dic_1)
    print(path)
    
    # 结果
    [0, 1, 2, 3, 4, 5, [6, 7]]
    

    可以看到,列表成功展开,[0, 1, 2, 3, 4, 5, [6, 7]] ,不是递归展开,只是同级,子列表[6, 7] 与列表其他元素同级。
    如果我们的表达式改为[][],则得到的结果为[0, 1, 2, 3, 4, 5, 6, 7]

    import jmespath
    
    
    dic_1 = [
      [0, 1],
      2,
      [3],
      4,
      [5, [6, 7]]
    ]
    path = jmespath.search("[][]", dic_1)
    print(path)
    
    # 结果
    [0, 1, 2, 3, 4, 5, 6, 7]
    

    过滤投影

    到目前为止,我们已经看到:

    • 列表/切片投影
    • 对象投影
    • 展平投影
       

    什么是过滤投影

    计算投影的右侧表达式(RHS)是一种基本类型的过滤器。如果表达式对单个元素求值的结果为null,则该元素将从最终结果中排除。
     

    过滤投影的作用

    过滤投影允许您在计算投影的右侧表达式(RHS)之前过滤投影的左侧LHS。
     

    案例

    例如,假设我们有一个机器列表,每个机器都有一个名称和一个状态。我们想要所有正在运行的机器的名称。在伪代码中,这将是:

    result = []
    foreach machine in inputData['machines']
      if machine['state'] == 'running'
        result.insert_at_end(machine['name'])
    return result
    

    以上是伪代码,接下来我们用python代码展示

    import jmespath
    
    
    dic_1 = {
      "machines": [
        {"name": "a", "state": "running"},
        {"name": "b", "state": "stopped"},
        {"name": "b", "state": "running"}
      ]
    }
    path = jmespath.search("machines[?state=='running'].name", dic_1)
    print(path)
    
    # 结果
    ['a', 'b']
    

    这里是过滤了左侧LHSmachines里state==running的元素,再取出已经过滤完成后name的值,放入JSON数组中
     

    总结

    筛选器表达式是为数组定义的,其一般形式为LHS [? <expression> <comparator> <expression>] RHS,比较的形式还有很多种,这里举出常用的几个:==, !=, <, <=, >, >=

  • 相关阅读:
    js获取盒子scrollTop
    获取浏览器宽度,自适应屏幕
    js切割字符串
    有向图的欧拉路径POJ2337
    欧拉回路和欧拉路径
    HDU 4462(暴力枚举)
    HDU 4455(dp)
    鸽巢原理入门
    HDU 4819 Mosaic(二维线段树)
    POJ 1330 Nearest Common Ancestors(LCA模板)
  • 原文地址:https://www.cnblogs.com/jiakecong/p/14389757.html
Copyright © 2011-2022 走看看