管道表达式
投影是 JMESPath 中的一个重要概念。但是,有时投影语义不是您想要的。一个常见的场景是当您想要对投影的结果进行运算而不是将表达式投影到数组中的每个元素上时。例如,表达式 people[* ].first将为您提供一个数组,其中包含 people 数组中每个人的名字。如果您想要该列表中的第一个元素怎么办?如果您尝试people[*].first[0],您只是对 people 数组中的每个元素计算first[0],并且由于没有为字符串定义索引,最终结果将是一个空数组,[]. 要实现所需的结果,您可以使用管道表达式 < expression> | < expression>,表示必须停止投影,这在下面的示例中显示
import jmespath
dict1 = {
"people": [
{"first": "James", "last": "d"},
{"first": "Jacob", "last": "e"},
{"first": "Jayden", "last": "f"},
{"missing": "different"}
],
"foo": {"bar": "baz"}
}
#取出key为first的第一个元素
#(1)
req1 = jmespath.search('people[*].first[0]',dict1)
print(req1) #[]
req2 = jmespath.search('people[*].first | [0]',dict1) print(req2) # James
在上面的例子中,列表投影的 RHS 是first。当遇到管道时,到该点的结果将传递给管道表达式的 RHS。管道表达式计算如下:
evaluate(people[*].first, dict1) -> ["James", "Jacob", "Jayden"]
evaluate([0], ["James", "Jacob", "Jayden"]) -> "James"
多选
到目前为止,我们已经了解了 JMESPath 表达式,这些表达式有助于将 JSON 文档缩减为您感兴趣的元素。
下一个概念, 多选列表和 多选散列允许您创建 JSON 元素。这允许您创建 JSON 文档中不存在的元素。多选列表创建一个列表,多选哈希创建一个 JSON 对象。
这是多选列表的示例:
import jmespath
dict1 = {
"people": [
{
"name": "a",
"state": {"name": "up"}
},
{
"name": "b",
"state": {"name": "down"}
},
{
"name": "c",
"state": {"name": "up"}
}
]
}
req1 = jmespath.search("people[].[name,state.name]",dict1)
print(req1) #[['a', 'up'], ['b', 'down'], ['c', 'up']]
req2 = jmespath.search("people[].[bar,state.bar]",dict1)
print(req2) #[[None, None], [None, None], [None, None]]
在上面的表达式中,[name, state.name]部分是一个多选列表。它说要创建一个包含两个元素的列表,第一个元素是针对列表元素评估name表达式的结果,第二个元素是评估state.name的结果。因此,每个列表元素都会创建一个双元素列表,整个表达式的最终结果是一个包含两个元素列表的列表。
与投影不同,表达式的结果始终包含在内,即使结果为空。如果将上述表达式更改为people[].[bar,state.bar]每两个元素列表将是[[None, None], [None, None], [None, None]]
多选与多选列表的基本思想相同,只是它创建的是散列而不是数组。使用上面的相同示例,如果我们想要创建一个具有两个键Name和 State的两元素哈希,我们可以使用:
import jmespath
dict1 = {
"people": [
{
"name": "a",
"state": {"name": "up"}
},
{
"name": "b",
"state": {"name": "down"}
},
{
"name": "c",
"state": {"name": "up"}
}
]
}
# 多选哈希
req3 = jmespath.search("people[].{Name: name, State: state.name}",dict1)
print(req3) # [{'Name': 'a', 'State': 'up'}, {'Name': 'b', 'State': 'down'}, {'Name': 'c', 'State': 'up'}]