飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • JSON

    • JSON 是什么
    • JSON 的六种数据类型
    • 对象(Object)
    • 数组(Array)
    • 字符串(String)
    • 数字(Number)
    • 布尔值和 Null
    • 字符编码与转义
    • JSON 语法规则
    • 综合应用示例
  • JSONPath

    • JSONPath 是什么
    • 根标识符和基本路径
    • 名称选择器
    • 索引选择器
    • 通配符选择器
    • 数组切片选择器
    • 过滤器选择器(上)
    • 过滤器选择器(下)
    • 后代段
    • 函数扩展
    • JSONPath 综合实战

后代段

什么是后代段?

后代段(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
$..name5 个 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 人
$..age28、35、30、24所有层级中的 age
$..[?@.age > 30]{"name":"翼王","age":35}所有层级中年龄>30的对象

后代段的访问顺序

后代段遍历时遵循以下规则:

  1. 先访问父节点,再访问子节点(深度优先)
  2. 数组按索引顺序访问
  3. 对象内部顺序不固定(因为 JSON 对象本身无序)

示例

{
  "a": [{"b": 1}, {"c": 2}]
}

查询 $..* 的访问顺序:

  1. 先访问根的后代:[{"b":1},{"c":2}]
  2. 再访问数组元素:{"b":1}、{"c":2}
  3. 再访问对象值: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 数组$..hobbies4 个数组
所有爱好(字符串)$..hobbies[*]钓鱼、看科幻小说、健身、改装车、手账、盲盒、插画、烘焙
所有数组第 1 个元素$..[0]技术部对象、航仔对象、钓鱼、图妹对象、手账

常见错误

错误写法问题正确写法
$.... 后面必须跟选择器$..* 或 $..name
$. .name中间有空格$..name
$..members.name后代段后不能直接链式点$..members[*].name

一句话总结

提示

.. 是递归查找,不管多深都能找到。$..name 找所有叫 name 的字段,$..* 找所有值。父节点先于子节点出现,数组有序,对象无序。记住:.. 后面必须跟选择器!

上一页
过滤器选择器(下)
下一页
函数扩展