前言
做接口自动化,断言是比不可少的。如何快速巧妙的提取断言数据就成了关键,当然也可以提高用例的编写效率。笔者在工作中接触到了JMESPath
,那到底该如何使用呢?带着疑惑一起往下看。
JMESPath
是啥?
JMESPath 是一种用于查询和转换 JSON 数据的简洁、强大的查询语言。它提供了一种灵活的方式来从复杂的 JSON 结构中提取所需的数据,并支持各种操作和函数,以满足不同的查询需求。
JMESPath
如何使用?
在使用 JMESPath 查询 JSON 数据之前,我们需要安装 jmespath
库。安装命令如下:
pip install jmespath
简单路径表达式
假设我们有以下的 JSON 数据:
data = {
"name": "Alice",
"age": 25,
"email": "alice@example.com"
}
我们想要从中提取 "name"
属性的值。使用 JMESPath,我们可以编写以下代码:
import jmespath
expression = "name"
result = jmespath.search(expression, data)
print(result) # 输出:Alice
这里,我们定义了一个路径表达式 "name"
,然后使用 jmespath.search()
函数将该表达式应用于数据 data
上。结果会被存储在 result
变量中,并输出为 "Alice"
。
嵌套属性访问
当 JSON 数据具有嵌套结构时,可以使用点号 .
连接多个属性名来表示深层的属性访问。考虑以下 JSON 数据:
data = {
"person": {
"name": "Alice",
"age": 25,
"email": "alice@example.com"
}
}
我们要提取 "name"
属性,可以使用以下路径表达式:
expression = "person.name"
result = jmespath.search(expression, data)
print(result) # 输出:Alice
这里,我们将属性名 "person"
和 "name"
使用点号 .
连接起来,表示深层的属性访问。
复杂嵌套查询
假设我们有一个包含学生信息和他们的课程成绩的更复杂的 JSON 数据,如下所示:
data = {
"students": [
{
"name": "Alice",
"courses": [
{"name": "Math", "score": 95},
{"name": "English", "score": 88}
]
},
{
"name": "Bob",
"courses": [
{"name": "Math", "score": 75},
{"name": "English", "score": 92}
]
}
]
}
现在,假设我们想要获取每个学生的数学成绩。可以通过以下表达式实现:
expression = "students[].courses[?name == 'Math'].score"
再次执行查询并打印结果:
result = jmespath.search(expression, data)
print(result)
输出结果将是一个包含每个学生数学成绩的列表:
[[95], [75]]
列表索引
对于 JSON 中的列表属性,可以使用方括号 [index]
来指定索引位置来检索数据。假设我们有以下 JSON 数据:
data = {
"fruits": ["apple", "banana", "cherry"]
}
我们想要提取第二个元素,即 "banana"
。可以使用以下路径表达式:
expression = "fruits[1]"
result = jmespath.search(expression, data)
print(result) # 输出:banana
这里,我们使用方括号 [1]
来指定索引位置,表示提取第二个元素。
过滤器
JMESPath 提供了过滤器功能,使我们能够根据特定条件筛选出符合要求的数据。过滤器使用方括号 [?]
,后跟过滤条件。考虑以下 JSON 数据:
data = {
"users": [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
{"name": "Charlie", "age": 28}
]
}
我们想要提取年龄大于 25 岁的用户对象。可以使用以下路径表达式进行过滤:
expression = "users[?age > `25`]"
result = jmespath.search(expression, data)
print(result)
输出结果为:
[ {"name": "Bob", "age": 30}, {"name": "Charlie", "age": 28}]
这里,我们使用了过滤器 [?age > 25]
,表示只选择满足条件的用户对象。
合并操作
JMESPath 还支持合并操作符 []
,用于将多个查询结果合并成一个列表。假设我们想要获取所有学生的所有课程名称。可以使用合并操作符 []
来实现:
data = {
"students": [
{
"name": "Alice",
"courses": [
{"name": "Math", "score": 95},
{"name": "English", "score": 88}
]
},
{
"name": "Bob",
"courses": [
{"name": "Math", "score": 75},
{"name": "English", "score": 92}
]
}
]
}
获取所有学生的所有课程名称:
expression = "students[].courses[].name"
result = jmespath.search(expression, data)
print(result)
输出结果为:
['Math', 'English', 'Math', 'English']
排序和切片
JMESPath 还支持对查询结果进行排序和切片操作。假设我们想要按学生年龄进行降序排序。可以使用排序函数 sort()
和逆序函数 reverse()
来实现:
data = {
"students": [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 22},
{"name": "Charlie", "age": 21}
]
}
得到按年龄降序排列的学生列表:
expression = "students | sort_by(@, &age) | reverse(@)"
result = jmespath.search(expression, data)
print(result) # [{'name': 'Bob', 'age': 22}, {'name': 'Charlie', 'age': 21}, {'name': 'Alice', 'age': 20}]
切片
data = {
"fruits": ["apple", "banana", "cherry"]
}
利用切片获取第一个元素
import jmespath
data = {
"fruits": ["apple", "banana", "cherry"]
}
expression = "fruits[0:1]"
result = jmespath.search(expression, data)
print(result) # ['apple']
管道
使用管道符号(|),将当前节点的结果传到管道符右侧继续投影。
data = {
"students": [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 22},
{"name": "Charlie", "age": 21}
]
}
获取所有的姓名:
expression = "students[*].name"
result = jmespath.search(expression, data)
print(result) # ['Alice', 'Bob', 'Charlie']
如果在此基础上想要得到Bob
这个值。我们尝试使用索引:
expression = "students[*].name[1]"
result = jmespath.search(expression, data)
print(result) # []
发现执行结果是一个空列表,这个时候怎么办呢?使用管道表达式, |
expression = "students[*].name | [1]"
内置函数
计算列表长度
data = {
"students": [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 22},
{"name": "Charlie", "age": 21}
]
}
expression = "length(students)" # 也可以这样写expression = "students | length(@)"
result = jmespath.search(expression, data)
print(result) # 3
length
就是jmespath
内置的函数。
当然还有一些其他常用的内置函数,比如:
starts_with(str, prefix)
: 检查字符串是否以指定前缀开头。ends_with(str, suffix)
: 检查字符串是否以指定后缀结尾。contains(str, substring)
: 检查字符串是否包含子字符串。length(arr)
: 返回数组的长度。
最后
jmespath
确实很强大,通过逐步学习和实践,可以更好地掌握 JMESPath 的功能和灵活性。