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

4、函数:https://jmespath.org/specification.html#functions

posted @ 2020-09-13 22:11  xyztank  阅读(217)  评论(0编辑  收藏  举报