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

    • 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 综合实战

函数扩展

什么是函数扩展?

函数扩展(Function Extension) 是 JSONPath 提供的内置函数,可以在过滤器表达式中调用,实现更强大的查询能力。

RFC 9535 定义了 5 个标准函数:

函数作用参数类型结果类型
length()计算长度ValueTypeValueType(数字)
count()计算节点数量NodesTypeValueType(数字)
match()正则完全匹配ValueType, ValueTypeLogicalType
search()正则子串匹配ValueType, ValueTypeLogicalType
value()提取单个节点的值NodesTypeValueType

length() 函数

length() 计算字符串长度、数组元素个数或对象成员个数。

示例 JSON

{
  "employees": [
    {"name": "航仔", "hobbies": ["钓鱼", "看科幻小说", "深夜撸串"]},
    {"name": "翼王", "hobbies": ["健身", "改装车"]},
    {"name": "图妹", "hobbies": ["手账"]},
    {"name": "鸣哥", "hobbies": []}
  ],
  "slogan": "愿你朝华相顾,愿你前程似锦。"
}

length() 查询

查询目标JSONPath结果说明
标语长度$[?length(@.slogan) > 10]整个 JSON标语长度>10
爱好>=3个的员工$.employees[?length(@.hobbies) >= 3]航仔航仔有3个爱好
爱好=2个的员工$.employees[?length(@.hobbies) == 2]翼王翼王有2个爱好
爱好=0个的员工$.employees[?length(@.hobbies) == 0]鸣哥鸣哥没有爱好

💡 length(@.hobbies) 对数组返回元素个数,对字符串返回字符数,对对象返回成员数。


count() 函数

count() 计算节点列表中有多少个节点。

示例 JSON

{
  "departments": [
    {
      "name": "技术部",
      "members": [{"name": "航仔"}, {"name": "翼王"}, {"name": "凌叔"}]
    },
    {
      "name": "产品部",
      "members": [{"name": "图妹"}, {"name": "星宇"}]
    },
    {
      "name": "运营部",
      "members": [{"name": "鸣哥"}, {"name": "雁姐"}, {"name": "波比"}, {"name": "云吞"}]
    }
  ]
}

count() 查询

查询目标JSONPath结果说明
成员>=3的部门$.departments[?count(@.members) >= 3]技术部、运营部技术部3人,运营部4人
成员=2的部门$.departments[?count(@.members) == 2]产品部产品部2人
成员>5的部门$.departments[?count(@.members) > 5](空)没有部门超过5人

💡 count(@.members) 返回 members 数组里的节点数量。注意:count 的参数必须是 NodesType(节点列表),不能直接传数字或字符串。


match() 函数

match() 用正则表达式检查字符串是否完全匹配。

示例 JSON

{
  "employees": [
    {"name": "航仔", "phone": "13800138000"},
    {"name": "翼王", "phone": "13900139000"},
    {"name": "图妹", "phone": "13700137000"},
    {"name": "鸣哥", "phone": "020-88888888"}
  ]
}

match() 查询

查询目标JSONPath结果说明
手机号以 138 开头$.employees[?match(@.phone, '138.*')]航仔138 开头
手机号以 139 开头$.employees[?match(@.phone, '139.*')]翼王139 开头
固话(带横线)$.employees[?match(@.phone, '.*-.*')]鸣哥包含横线

💡 match() 是"完全匹配",字符串必须整体符合正则表达式。正则语法遵循 I-Regexp(RFC 9485)。


search() 函数

search() 用正则表达式检查字符串中是否包含匹配的子串(不需要完全匹配)。

search() vs match()

函数匹配方式示例
match()完全匹配match("abc", "a.*") → true
search()子串搜索search("abc", "b") → true

示例 JSON

{
  "employees": [
    {"name": "航仔", "personality": "沉稳靠谱,话不多但代码干净"},
    {"name": "翼王", "personality": "霸气外露,技术独裁但护犊子"},
    {"name": "图妹", "personality": "急性子,原型图画到半夜"},
    {"name": "鸣哥", "personality": "社牛,公司团建气氛组"}
  ]
}

search() 查询

查询目标JSONPath结果说明
性格描述含"技术"$.employees[?search(@.personality, '技术')]翼王翼王描述中有"技术"
性格描述含"牛"$.employees[?search(@.personality, '牛')]鸣哥鸣哥是"社牛"
性格描述含"半夜"$.employees[?search(@.personality, '半夜')]图妹图妹"画到半夜"

💡 search() 比 match() 更宽松,只要字符串里包含匹配的部分就行。


value() 函数

value() 将节点列表转换为单个值,但只有当节点列表里恰好有 1 个节点时才成功。

示例

{
  "store": {
    "bicycle": {"color": "red", "price": 399},
    "book": {"color": "blue", "price": 29}
  }
}
$[?value(@..color) == "red"]

⚠️ value() 的使用场景比较特殊,日常查询中不如其他函数常用。如果节点列表为空或有多个节点,返回 Nothing。


函数使用规则

良类型检查

JSONPath 要求函数的使用必须是良类型的:

函数参数要求常见错误
length()参数必须是 ValueTypelength(@.*) ❌(@.* 是 NodesType)
count()参数必须是 NodesTypecount(1) ❌(1 不是节点列表)
match()两个参数都必须是 ValueType(字符串)match(@.*, 'a') ❌
search()两个参数都必须是 ValueType(字符串)同上

正确 vs 错误

✅ $[?length(@.slogan) > 10]           // 正确
❌ $[?length(@.*) < 3]                // 错误:@.* 是节点列表
✅ $[?count(@.*) == 1]                // 正确
❌ $[?count(1) == 1]                  // 错误:1 不是节点列表
✅ $[?match(@.phone, '138.*')]         // 正确
❌ $[?match(@.*, 'a')]                 // 错误:@.* 是节点列表

实战:飞翔科技函数综合查询

示例 JSON

{
  "departments": [
    {
      "name": "技术部",
      "members": [
        {"name": "航仔", "hobbies": ["钓鱼", "看科幻小说", "深夜撸串"], "phone": "13800138000"},
        {"name": "翼王", "hobbies": ["健身", "改装车", "收藏机械键盘"], "phone": "13900139000"},
        {"name": "凌叔", "hobbies": ["泡茶", "养鹦鹉"], "phone": "13700137000"},
        {"name": "空少", "hobbies": ["穿搭", "探店", "拍vlog"], "phone": "13600136000"},
        {"name": "风速", "hobbies": ["竞速游戏", "魔方", "收集跑鞋"], "phone": "13500135000"}
      ]
    },
    {
      "name": "产品部",
      "members": [
        {"name": "图妹", "hobbies": ["手账", "盲盒", "奶茶测评"], "phone": "13800138111"},
        {"name": "星宇", "hobbies": ["天文", "indie游戏"], "phone": "13900139222"},
        {"name": "靓晴", "hobbies": ["插画", "烘焙", "逛展"], "phone": "13700137333"}
      ]
    }
  ]
}

综合查询

查询目标JSONPath结果
爱好>=3个的员工$.departments[*].members[?length(@.hobbies) >= 3]航仔、翼王、空少、风速、图妹、靓晴
部门成员>=4人$.departments[?count(@.members) >= 4]技术部
手机号 138 开头的员工$.departments[*].members[?match(@.phone, '138.*')]航仔、图妹
爱好含"游戏"的员工$.departments[*].members[?search(@.hobbies, '游戏')]风速(竞速游戏)、星宇(indie游戏)

一句话总结

提示

length() 算长度,count() 数节点,match() 完全正则匹配,search() 子串正则匹配。注意参数类型要对,节点列表和值不能混用!

上一页
后代段
下一页
JSONPath 综合实战