Jmespath提取json元素之投影操作
一、列表和切片投影
通配符表达式创建一个列表投影,它是 JSON 数组上的一个投影。
1、非标准的字典格式
data不是一个标准的字典格式,其中包含列表
import jmespath
#这里data不是一个标准的字典格式,其中包含列表。
data = {
"people": [
{"first": "James", "last": "d"},
{"first": "Jacob", "last": "e"},
{"first": "Jayden", "last": "f"},
{"missing": "different"}
],
"foo": {"bar": "baz"}
}
parse_data = jmespath.search("people[*].first", data) # 提取people下所有元素的第一个元素
parse_data1 = jmespath.search("people[].first", data) # 提取people下所有元素的第一个元素
parse_data2 = jmespath.search("people[*].last", data) # 提取people下所有元素的第二个元素
parse_data3 = jmespath.search("people[:2].last", data) # 提取people下前两个元素的第二个元素
print(f"解析后的数据为:{parse_data}")
print(f"解析后的数据为:{parse_data1}")
print(f"解析后的数据为:{parse_data2}")
print(f"解析后的数据为:{parse_data3}")
结果:
解析后的数据为:['James', 'Jacob', 'Jayden']
解析后的数据为:['James', 'Jacob', 'Jayden']
解析后的数据为:['d', 'e', 'f']
解析后的数据为:['d', 'e']
2、标准的字典格式
import jmespath
#data是一个标准的字典格式
data = {
"ops": {
"functionA": {"numArgs": 2},
"functionB": {"numArgs": 3},
"functionC": {"variadic": True}
}
}
parse_data = jmespath.search("ops.*.numArgs", data) # 提取ops下所有含numArgs属性的元素值
parse_data1 = jmespath.search("ops.*.variadic", data) # 提取ops下所有含variadic属性的元素值
parse_data2 = jmespath.search("ops.functionA.numArgs", data) # 提取ops下functionA中numArgs属性的元素值
print(f"解析后的数据为:{parse_data}")
print(f"解析后的数据为:{parse_data1}")
print(f"解析后的数据为:{parse_data2}")
结果:
解析后的数据为:[2, 3]
解析后的数据为:[True]
解析后的数据为:2
二、压平投影
如果我们获得的响应结果是[[[“ running” ,“ stopped”] ,[“ terminated” ,“ running”] ,这是一个列表嵌套的列表。但是我只想要获得的是列表中的状态,所以需要将列表中的元素都提取出来,并保存在一个简单列表中(非嵌套列表)。此处,压平投影达到的效果就在于此。如下:
import jmespath
# data是多重嵌套的列表
data =[["running", "stopped"], ["terminated", ["terminated", "running"]]]
parse_data = jmespath.search("[]", data) # 单独使用[]来平滑一个列表
parse_data1 = jmespath.search("[][]", data) # 使用[][]来平滑一个两重嵌套的列表
print(f"解析后的数据为:{parse_data}")
print(f"解析后的数据为:{parse_data1}")
结果:
解析后的数据为:['running', 'stopped', 'terminated', ['terminated', 'running']]
解析后的数据为:['running', 'stopped', 'terminated', 'terminated', 'running']
如上所示,我们获得了理想中想要的结果,['running', 'stopped', 'terminated', 'terminated', 'running']。如果是多重嵌套呢?扩展操作如下:
import jmespath
# data是多重嵌套的列表
data = [
[0, 1],
2,
[3],
4,
[5, [6, 7]],
[5, [6, 7,[6, 7]]]
]
parse_data = jmespath.search("[]", data) # 单独使用[]来平滑一个列表
parse_data1 = jmespath.search("[][]", data) # 使用[][]来平滑一个两重嵌套的列表
parse_data2 = jmespath.search("[][][]", data) # 使用[][][]来平滑一个三重嵌套的列表
parse_data3 = jmespath.search("[].date", data) # data为列表中包含例表、字典时,使用[]来平滑一个列表并取字典key为date的值
parse_data4 = jmespath.search("[].date[]", data) # data为列表中包含例表、字典时,使用[]来平滑一个列表并取字典key为date的值,结果再平滑一个列表
print(f"解析后的数据为:{parse_data}")
print(f"解析后的数据为:{parse_data1}")
print(f"解析后的数据为:{parse_data2}")
结果:
解析后的数据为:[0, 1, 2, 3, 4, 5, [6, 7], 5, [6, 7, [6, 7]]]
解析后的数据为:[0, 1, 2, 3, 4, 5, 6, 7, 5, 6, 7, [6, 7]]
解析后的数据为:[0, 1, 2, 3, 4, 5, 6, 7, 5, 6, 7, 6, 7]
三、滤镜投影
表达式如下:
滤镜投影表达式: = "[?" expression "]"
常用过滤符号: = "<" / "<=" / "==" / ">=" / ">" / "!="
==, tests for equality.
!=, tests for inequality.
<, less than.
<=, less than or equal to.
>, greater than.
>=, greater than or equal to.
例如,假设我们有一个机器列表,每个机器都有一个名称和一个状态。我们想知道所有正在运行的机器的名称。而jmespath的滤镜投影操作相当于有判断语句进行过滤操作。具体如下:
import jmespath
data = {
"machines": [
{"name": "a", "state": "running"},
{"name": "b", "state": "stopped"},
{"name": "b", "state": "running"}
]
}
parse_data = jmespath.search("machines[*].state", data) # 获取所有机器machines的运行状态
parse_data1 = jmespath.search("machines[].name", data) # 获取所有机器machines的名称
parse_data2 = jmespath.search("machines[?state=='running'].name", data) # 获取所有运行状态为running的machines名称
parse_data3 = jmespath.search("machines[?state=='stopped'].name", data) # 获取所有运行状态为stopped的machines名称
print(f"获取所有机器machines的运行状态:{parse_data}")
print(f"获取所有机器machines的名称:{parse_data1}")
print(f"获取所有运行状态为running的machines名称:{parse_data2}")
print(f"获取所有运行状态为stopped的machines名称:{parse_data3}")
结果:
获取所有机器machines的运行状态:['running', 'stopped', 'running']
获取所有机器machines的名称:['a', 'b', 'b']
获取所有运行状态为running的machines名称:['a', 'b']
获取所有运行状态为stopped的machines名称:['b']
滤镜投影表达式:https://jmespath.org/specification.html#filterexpressions
四、管道表达式
有时候我们并不想获取所有的元素,而是只想取其中的一个元素,此时就需要用到管道表达式。比如,有很多本书,我们要获取所有价格大于等于50,并取第一本书名。如下,用两种方式取获取第一本书,且价格大于等于50元。
import jmespath
data = {
"books": [
{
"name": "西游记",
"price": "30",
"publisher": "人民出版社"
},
{
"name": "乔布斯传",
"price": "40",
"publisher": "中信出版社"
},
{
"name": "人类简史",
"price": "50",
"publisher": "人人出版社"
},
{
"name": "红楼梦",
"price": "60",
"publisher": "牛牛出版社"
}
]
}
parse_data = jmespath.search("books[?price>='50'].name", data) # 获取所有价格大于等于50的书名
parse_data1 = jmespath.search("books[?price>='50'].name | [0]", data) # 获取所有价格大于等于50,并取第一本书名
parse_data2 = jmespath.search("books[?price>='50'].name", data) # 获取所有价格大于等于50,并取第一本书名
print(f"获取所有价格大于等于50的书名:{parse_data}")
print(f"获取所有价格大于等于50,并取第一本书名:{parse_data1}") # 用jmespath表达式取第一个元素值
print(f"获取所有价格大于等于50,并取第一本书名:{parse_data2[0]}") # 用列表的下标去取第一个元素值
结果:
获取所有价格大于等于50的书名:['人类简史', '红楼梦']
获取所有价格大于等于50,并取第一本书名:人类简史
获取所有价格大于等于50,并取第一本书名:人类简史
五、多选
比如利用筛选条件获取所有想要的元素,但这还不是我们最终想要的,我们还想要利用它组合成新的组合,此时利用多选即可达到目的。比如获取到价格大于等于50的书名,再将书和价格重新组合成一个新的列表。如下:
import jmespath
data = {
"books": [
{
"name": "西游记",
"price": "30",
"publisher": "人民出版社"
},
{
"name": "乔布斯传",
"price": "40",
"publisher": "中信出版社"
},
{
"name": "人类简史",
"price": "50",
"publisher": "人人出版社"
},
{
"name": "红楼梦",
"price": "60",
"publisher": "牛牛出版社"
}
]
}
parse_data = jmespath.search("books[?price>='50'].{Name:name,Price:price}", data) # 获取所有价格大于等于50的书名,并重新组合程一个新的列表
parse_data1 = jmespath.search("books[?price<'50'].{Name:name,Price:price}", data) # 获取所有价格小于50的书名,并重新组合程一个新的列表
print(f"获取所有价格大于等于50的书名,并重新组合程一个新的列表:{parse_data}")
print(f"获取所有价格小于50的书名,并重新组合程一个新的列表:{parse_data1}")
结果:
获取所有价格大于等于50的书名,并重新组合程一个新的列表:[{'Name': '人类简史', 'Price': '50'}, {'Name': '红楼梦', 'Price': '60'}]
获取所有价格小于50的书名,并重新组合程一个新的列表:[{'Name': '西游记', 'Price': '30'}, {'Name': '乔布斯传', 'Price': '40'}]
六、链接地址
1、https://jmespath.org/tutorial.html
2、https://pypi.org/project/jmespath/
3、过滤:https://jmespath.org/specification.html#filterexpressions