目录
- 多层嵌套响应介绍
- JSONPath 语法
- JSONPath 使用
课程目标
- 掌握从多层嵌套响应体的中提取字段。
- 掌握 JSONPath 的语法知识。
- 掌握如何对复杂的 JSON 类型的响应体完成断言。
思考
如果要从一个非常复杂的 json 结构中,提取数据信息,你通常是怎么提取的?
多层嵌套结构
// - 层级多。
// - 嵌套关系复杂。
{
"errcode": 0,
"errmsg": "ok",
"userid": "zhangsan",
"name": "张三",
"department": [1, 2],
"order": [1, 2],
"position": "后台工程师",
"mobile": "13800000000",
"gender": "1",
"email": "zhangsan@gzdev.com",
"biz_mail": "zhangsan@qyycs2.wecom.work",
"is_leader_in_dept": [1, 0],
"direct_leader": ["lisi", "wangwu"],
"avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"thumb_avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/100",
"telephone": "020-123456",
"alias": "jackzhang",
"address": "广州市海珠区新港中路",
"open_userid": "xxxxxx",
"main_department": 1,
"extattr": {
"attrs": [
{
"type": 0,
"name": "文本名称",
"text": {
"value": "文本"
}
},
{
"type": 1,
"name": "网页名称",
"web": {
"url": "http://www.test.com",
"title": "标题"
}
}
]
},
"status": 1,
"qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
"external_position": "产品经理",
"external_profile": {
"external_corp_name": "企业简称",
"wechat_channels": {
"nickname": "视频号名称",
"status": 1
},
"external_attr": [
{
"type": 0,
"name": "文本名称",
"text": {
"value": "文本"
}
},
{
"type": 1,
"name": "网页名称",
"web": {
"url": "http://www.test.com",
"title": "标题"
}
},
{
"type": 2,
"name": "测试app",
"miniprogram": {
"appid": "wx8bd80126147dFAKE",
"pagepath": "/index",
"title": "my miniprogram"
}
}
]
}
}
## 多层嵌套结构字段提取
场景 方式
提取 errcode 对应的值 res["errcode"]
提取 title 对应的值 res["extattr"]["external_profile"]["external_attr"][1]["web"]["title"]
提取 type 为 0 的 name 编码实现
提取 attrs 下的所有的 name 编码实现
![image|800x246](upload://wbgp5Up9FPVLWyr7PFV241Muj60.jpeg)
## JSONPath 简介
在 JSON 数据中定位和提取特定信息的查询语言。
JSONPath 使用类似于 XPath 的语法,使用路径表达式从 JSON 数据中选择和提取数据。
相比于传统的提取方式,更加灵活,并且支持定制化。
## JSONPath 对比
场景 对应实现 JSONPath 实现
提取 errcode 对应的值 res["errcode"] $.errcode
提取 title 对应的值 res["extattr"]["external_profile"]["external_attr"][1]["web"]["title"] 等 $..title
提取 type 为 0 的 name 编码实现 $..external_attr[?(@.type==0)].name
提取 attrs 下的所有的 name 编码实现 $..attrs..name
![image|800x315](upload://eFzz2RWQGTVro6nFv3GUKq3UZrh.jpeg)
## JSONPath 如何使用
语法知识。
第三方库调用。
## JSONPath 语法
符号 描述
$ 查询的根节点对象,用于表示一个 json 数据,可以是数组或对象
@ 过滤器(filter predicate)处理的当前节点对象
* 通配符
. 获取子节点
.. 递归搜索,筛选所有符合条件的节点
?() 过滤器表达式,筛选操作
[start:end] 数组片段,区间为[start,end),不包含 end
[A]或[A,B] 迭代器下标,表示一个或多个数组下标
![image|800x365](upload://iq2Prk739eO4CQcslmREQb5iknb.jpeg)
## JSONPath 的练习环境
https://jsonpath.hogwarts.ceshiren.com/
{
“store”: {
“book”: [
{
“category”: “reference”,
“author”: “Nigel Rees”,
“title”: “Sayings of the Century”,
“price”: 8.95
},
{
“category”: “fiction”,
“author”: “Evelyn Waugh”,
“title”: “Sword of Honour”,
“price”: 12.99
},
{
“category”: “fiction”,
“author”: “Herman Melville”,
“title”: “Moby Dick”,
“isbn”: “0-553-21311-3”,
“price”: 8.99
},
{
“category”: “fiction”,
“author”: “J. R. R. Tolkien”,
“title”: “The Lord of the Rings”,
“isbn”: “0-395-19395-8”,
“price”: 22.99
}
],
“bicycle”: {
“color”: “red”,
“price”: 19.95
}
},
“expensive”: 10
}
## JSONPath 练习题目
获取所有书籍的作者
获取所有作者
获取 store 下面的所有内容
获取所有的价格
获取第三本书
获取所有包含 isbn 的书籍
获取所有价格小于 10 的书
获取所有书籍的数量
## JSONPath 练习
需求 JsonPath
所有书籍的作者 $.store.book[*].author
所有作者 $..author
store 下面的所有内容 $.store.*
所有的价格 $.store..price
第三本书 $..book[2]
所有包含 isbn 的书籍 $..book[?(@.isbn)]
所有价格小于 10 的书 $.store.book[?(@.price < 10)]
所有书籍的数量 $..book.length
![image|721x418](upload://xHuNq4zcqUnDTWYjlWdN5QQJhPC.jpeg)
## JSONPath 与代码结合(Python)
环境安装:pip install jsonpath
具体的使用。
jsonpath.jsonpath(源数据对象, jsonpath表达式)
## JSONPath 与代码结合(Java)
2.8.0
com.jayway.jsonpath
json-path
${json-path.version}
public class TestJsonpath {
@Test
void jsonpathRes(){
String jsonData = “{"username":"hogwarts","password":"test12345","code":""}”;
String res = given()
.body(jsonData)
.when()
.post(“https://httpbin.hogwarts.ceshiren.com/post”)
.then()
.extract().response().getBody().asString();
// 第一种获取方式
DocumentContext context = JsonPath.parse(res);
ArrayList codeList = context.read(“$…code”);
// 第二种获取方式
// ArrayList codeList2 = JsonPath.read(res, “$…code”);
}
}
## 总结
源码地址(Java)
[点击查看演示源码地址](http://gitlab.stuq.ceshiren.com)
## 附录:完整依赖配置
UTF-8
11
5.9.2
3.11.0
3.0.0
5.3.0
2.8.0
2.21.0
1.9.19
2.12.0
https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline
org.junit
junit-bom
${junit.jupiter.version}
pom
import
<!-- junit 相关依赖下载-->
<!-- junit5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- junit5-suite -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<!-- 用做兼容老版本 -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<!-- rest-assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
<scope>compile</scope>
</dependency>
<!-- json path 解析json文件 -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${json-path.version}</version>
</dependency>
<!-- allure报告-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>${allure.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
org.apache.maven.plugins
maven-surefire-plugin
${maven-surefire-plugin.version}
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
org.junit.jupiter
junit-jupiter-engine
${junit.jupiter.version}
org.junit.vintage
junit-vintage-engine
${junit.jupiter.version}
org.apache.maven.plugins
maven-compiler-plugin
${maven.compiler.version}
true