后代段
什么是后代段?
后代段(Descendant Segment) 用双点 .. 表示,意思是"递归查找所有后代"。
它就像在一栋大楼里喊"所有叫这个名字的人,不管你在哪一层,都出来!"
基本语法
$..name // 递归查找所有 name 字段
$..['name'] // 括号表示法
$..* // 递归查找所有值
$..[0] // 递归查找所有数组的第 1 个元素
💡
..和.的区别:
.只深入一层..深入所有层级,递归查找
..name 递归查找指定名称
示例 JSON
{
"company": "广州飞翔科技",
"techLead": {
"name": "翼王",
"department": "技术部",
"personality": {
"trait": "霸气外露",
"description": "技术独裁但护犊子"
}
},
"productManager": {
"name": "图妹",
"department": "产品部"
},
"departments": [
{"name": "技术部", "headcount": 5},
{"name": "产品部", "headcount": 3},
{"name": "运营部", "headcount": 4}
]
}
递归查询 name
| JSONPath | 结果 | 说明 |
|---|---|---|
$..name | "翼王"、"图妹"、"技术部"、"产品部"、"运营部" | 所有层级中叫 name 的值 |
💡
$..name不管name在哪个层级,全部找出来:
techLead.name→ "翼王"productManager.name→ "图妹"departments[0].name→ "技术部"departments[1].name→ "产品部"departments[2].name→ "运营部"
对比:. 只能找一层
| JSONPath | 结果 | 说明 |
|---|---|---|
$.name | (空) | 根对象没有 name 字段 |
$.techLead.name | "翼王" | 只找到这一层的 name |
$..name | 5 个 name | 递归找到所有层的 name |
..* 递归查找所有值
..* 是最"暴力"的查询,它会返回 JSON 中几乎所有值(除了根节点本身)。
示例
{
"o": {"j": 1, "k": 2},
"a": [5, 3]
}
| JSONPath | 结果 | 说明 |
|---|---|---|
$..* | {"j":1,"k":2}、[5,3]、1、2、5、3 | 所有后代值 |
💡 结果顺序有约束:父节点必须在子节点之前出现。但对象内部的顺序不固定。
.. 结合索引和过滤器
后代段不仅可以跟名称,还可以跟索引、通配符、过滤器:
示例 JSON
{
"departments": [
{
"name": "技术部",
"members": [
{"name": "航仔", "age": 28},
{"name": "翼王", "age": 35}
]
},
{
"name": "产品部",
"members": [
{"name": "图妹", "age": 30},
{"name": "星宇", "age": 24}
]
}
]
}
各种后代查询
| JSONPath | 结果 | 说明 |
|---|---|---|
$..[0] | {"name":"技术部",...}、{"name":"航仔",...}、{"name":"图妹",...} | 所有数组的第 1 个元素 |
$..members | 两个 members 数组 | 所有叫 members 的字段 |
$..members[0] | {"name":"航仔","age":28}、{"name":"图妹","age":30} | 每个 members 数组的第 1 人 |
$..age | 28、35、30、24 | 所有层级中的 age |
$..[?@.age > 30] | {"name":"翼王","age":35} | 所有层级中年龄>30的对象 |
后代段的访问顺序
后代段遍历时遵循以下规则:
- 先访问父节点,再访问子节点(深度优先)
- 数组按索引顺序访问
- 对象内部顺序不固定(因为 JSON 对象本身无序)
示例
{
"a": [{"b": 1}, {"c": 2}]
}
查询 $..* 的访问顺序:
- 先访问根的后代:
[{"b":1},{"c":2}] - 再访问数组元素:
{"b":1}、{"c":2} - 再访问对象值:
1、2
实战:飞翔科技递归查询
示例 JSON
{
"company": "广州飞翔科技",
"departments": [
{
"name": "技术部",
"members": [
{"name": "航仔", "position": "后端开发", "hobbies": ["钓鱼", "看科幻小说"]},
{"name": "翼王", "position": "架构师", "hobbies": ["健身", "改装车"]}
]
},
{
"name": "产品部",
"members": [
{"name": "图妹", "position": "产品经理", "hobbies": ["手账", "盲盒"]},
{"name": "靓晴", "position": "UI设计师", "hobbies": ["插画", "烘焙"]}
]
}
]
}
查询练习
| 查询目标 | JSONPath | 结果 |
|---|---|---|
| 所有员工姓名 | $..members[*].name | 航仔、翼王、图妹、靓晴 |
| 递归找所有 name | $..name | 技术部、产品部、航仔、翼王、图妹、靓晴 |
| 所有 position | $..position | 后端开发、架构师、产品经理、UI设计师 |
| 所有 hobbies 数组 | $..hobbies | 4 个数组 |
| 所有爱好(字符串) | $..hobbies[*] | 钓鱼、看科幻小说、健身、改装车、手账、盲盒、插画、烘焙 |
| 所有数组第 1 个元素 | $..[0] | 技术部对象、航仔对象、钓鱼、图妹对象、手账 |
常见错误
| 错误写法 | 问题 | 正确写法 |
|---|---|---|
$.. | .. 后面必须跟选择器 | $..* 或 $..name |
$. .name | 中间有空格 | $..name |
$..members.name | 后代段后不能直接链式点 | $..members[*].name |
一句话总结
提示
.. 是递归查找,不管多深都能找到。$..name 找所有叫 name 的字段,$..* 找所有值。父节点先于子节点出现,数组有序,对象无序。记住:.. 后面必须跟选择器!