当前位置: 首页 > news >正文

JMESPath由浅入深完全入门教程(自用)

JMESPath 完全学习指南 v3.0

目录
  • JMESPath 完全学习指南 v3.0
    • 1. 简介与安装
      • 什么是JMESPath?
      • 重要说明
      • 安装
      • Python基础用法
    • 第一部分:基础语法
    • 2. 标识符和属性访问 🔵
      • 2.1 基本标识符
      • 2.2 嵌套访问
      • 2.3 特殊字符处理
      • 2.4 空值处理
    • 3. 数组索引 🔵
      • 3.1 基本索引
      • 3.2 嵌套数组索引
    • 4. 切片操作 🔵
      • 4.1 基本切片
      • 4.2 负索引切片
      • 4.3 反向切片
    • 5. 投影 🔵
      • 5.1 列表投影 [*]
      • 5.2 对象投影 *
      • 5.3 扁平化投影 []
      • 5.4 切片投影
    • 6. 多选 🔵
      • 6.1 多选列表
      • 6.2 多选哈希
    • 第二部分:高级特性
    • 7. 特殊符号 🔵
      • 7.1 当前节点 @
      • 7.2 表达式引用 &
      • 7.3 字面量 `
    • 8. 管道表达式 | 🔵
      • 8.1 基本管道
      • 8.2 管道与投影组合
    • 9. 过滤表达式 🔵
      • 9.1 基本过滤
      • 9.2 比较运算符
      • 9.3 字符串比较
      • 9.4 逻辑运算符
      • 9.5 使用当前节点过滤
    • 10. 函数 🔵
      • 10.1 类型和长度函数
        • type() 🔵
        • length() 🔵
      • 10.2 数组函数
        • sort() 🔵
        • reverse() 🔵
        • min() / max() 🔵
        • sum() 🔵
        • avg() 🔵
      • 10.3 对象函数
        • keys() 🔵
        • values() 🔵
        • merge() 🔵
      • 10.4 字符串函数
        • contains() 🔵
        • starts_with() / ends_with() 🔵
        • join() 🔵
      • 10.5 转换函数
        • to_string() / to_number() 🔵
        • to_array() 🔵
        • not_null() 🔵
      • 10.6 高级函数(使用表达式引用)
        • sort_by() 🔵
        • min_by() / max_by() 🔵
    • 11. 组合使用:管道与函数
      • 11.1 管道与函数
      • 11.2 投影后使用函数
      • 11.3 过滤后使用函数
    • 12. 综合练习
      • 12.1 数据转换练习
      • 12.2 复杂数据处理
      • 12.3 嵌套数据聚合
    • 13. 功能限制 ⚠️
      • 13.1 标准JMESPath不支持的功能
      • 13.2 扩展功能 🟡
    • 14. Python集成最佳实践
      • 14.1 性能优化
      • 14.2 错误处理
      • 14.3 批量处理
    • 15. 快速参考
      • 基础语法
      • 投影
      • 多选
      • 特殊符号
      • 过滤
      • 常用函数
      • 学习建议


1. 简介与安装

什么是JMESPath?

JMESPath(JSON Matching Expression Path)是一种查询语言,用于从JSON文档中提取和转换数据。类似于XPath用于XML,JMESPath专门为JSON设计。

重要说明

本教程基于标准JMESPath规范,严格按照循序渐进的方式介绍每个概念。每个新语法或符号都会在使用前进行完整介绍。

标准功能标记: 🔵 标准JMESPath功能
扩展功能标记: 🟡 部分实现支持的扩展功能
限制说明标记: ⚠️ 功能限制或注意事项

安装

pip install jmespath

Python基础用法

import jmespathdata = {"name": "John","age": 30,"city": "New York"
}# 基础查询
result = jmespath.search('name', data)
print(result)  # "John"

第一部分:基础语法

2. 标识符和属性访问 🔵

2.1 基本标识符

语法说明:

  • 直接使用属性名访问对象的属性
  • 标识符可以包含字母、数字、下划线(不能以数字开头)
  • 大小写敏感

示例 1: 简单属性访问

{"name": "Alice","age": 25,"email": "alice@example.com"
}

查询表达式:

  • name"Alice"
  • age25
  • email"alice@example.com"

2.2 嵌套访问

语法说明:

  • 使用点号.连接多个标识符访问嵌套属性
  • 格式:parent.child.grandchild

示例 1: 两层嵌套

{"user": {"name": "Bob","profile": {"bio": "Developer","location": "Seattle"}}
}

查询表达式:

  • user.name"Bob"
  • user.profile.bio"Developer"
  • user.profile.location"Seattle"

2.3 特殊字符处理

语法说明:

  • 包含特殊字符的键需要用双引号包围
  • 特殊字符包括:-.@$、空格、数字开头等

示例 1: 特殊字符键名

{"first-name": "John","last.name": "Doe","123abc": "starts with number","user name": "Alice Bob"
}

查询表达式:

  • "first-name""John"
  • "last.name""Doe"
  • "123abc""starts with number"
  • "user name""Alice Bob"

2.4 空值处理

语法说明:

  • 访问不存在的属性返回null
  • 路径中任何部分为null时,整个表达式返回null

示例 1: 空值处理

{"user": {"name": "John"}
}

查询表达式:

  • user.agenull (属性不存在)
  • user.profile.bionull (中间路径不存在)

3. 数组索引 🔵

3.1 基本索引

语法说明:

  • 使用方括号[index]访问数组元素
  • 正索引从0开始
  • 负索引从末尾开始,-1是最后一个元素
  • 超出范围返回null

示例 1: 数组索引访问

{"fruits": ["apple", "banana", "cherry", "date"]
}

查询表达式:

  • fruits[0]"apple"
  • fruits[1]"banana"
  • fruits[-1]"date"
  • fruits[-2]"cherry"
  • fruits[10]null

3.2 嵌套数组索引

语法说明:

  • 可以连续使用索引访问多维数组
  • 格式:array[i][j]

示例 1: 二维数组

{"matrix": [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
}

查询表达式:

  • matrix[0][0]1
  • matrix[1][2]6
  • matrix[-1][-1]9

4. 切片操作 🔵

4.1 基本切片

语法说明:

  • 格式:[start:stop:step]
  • start: 起始索引(包含)
  • stop: 结束索引(不包含)
  • step: 步长
  • 任何部分都可以省略

示例 1: 切片操作

{"numbers": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}

查询表达式:

  • numbers[0:3][0, 1, 2]
  • numbers[2:5][2, 3, 4]
  • numbers[::2][0, 2, 4, 6, 8]
  • numbers[:][0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

4.2 负索引切片

示例 1: 使用负索引

{"letters": ["a", "b", "c", "d", "e", "f"]
}

查询表达式:

  • letters[-3:]["d", "e", "f"]
  • letters[:-2]["a", "b", "c", "d"]

4.3 反向切片

语法说明:

  • 使用负步长实现反向

示例 1: 反向操作

{"items": [1, 2, 3, 4, 5]
}

查询表达式:

  • items[::-1][5, 4, 3, 2, 1]
  • items[::-2][5, 3, 1]

5. 投影 🔵

5.1 列表投影 [*]

语法说明:

  • [*]符号对数组中的每个元素应用后续表达式
  • 返回结果数组

示例 1: 列表投影

{"users": [{"name": "Alice", "age": 25},{"name": "Bob", "age": 30},{"name": "Charlie", "age": 35}]
}

查询表达式:

  • users[*].name["Alice", "Bob", "Charlie"]
  • users[*].age[25, 30, 35]

5.2 对象投影 *

语法说明:

  • *符号对对象的所有值应用后续表达式
  • 返回值的数组

示例 1: 对象投影

{"departments": {"sales": {"count": 10, "budget": 50000},"engineering": {"count": 25, "budget": 100000},"hr": {"count": 5, "budget": 30000}}
}

查询表达式:

  • departments.*.count[10, 25, 5]
  • departments.*.budget[50000, 100000, 30000]

5.3 扁平化投影 []

语法说明:

  • []符号扁平化嵌套数组
  • 将多层数组展平为单层

示例 1: 扁平化

{"groups": [{"members": ["Alice", "Bob"]},{"members": ["Charlie", "David"]}]
}

查询表达式:

  • groups[*].members[]["Alice", "Bob", "Charlie", "David"]

5.4 切片投影

语法说明:

  • 切片结果可以继续应用投影

示例 1: 切片后投影

{"items": [{"id": 1, "value": 10},{"id": 2, "value": 20},{"id": 3, "value": 30}]
}

查询表达式:

  • items[0:2].value[10, 20]

6. 多选 🔵

6.1 多选列表

语法说明:

  • 使用[expression1, expression2, ...]创建新数组
  • 每个表达式的结果成为数组元素

示例 1: 多选列表

{"person": {"name": "John","age": 30,"city": "New York"}
}

查询表达式:

  • person.[name, age]["John", 30]
  • person.[name, city]["John", "New York"]

6.2 多选哈希

语法说明:

  • 使用{key1: expression1, key2: expression2}创建新对象

示例 1: 多选哈希

{"user": {"firstName": "Jane","lastName": "Doe","age": 28}
}

查询表达式:

  • user.{name: firstName, years: age}{"name": "Jane", "years": 28}

第二部分:高级特性

7. 特殊符号 🔵

7.1 当前节点 @

语法说明:

  • @符号代表当前处理的节点
  • 在管道和过滤表达式中使用

示例 1: 在过滤中使用@

{"numbers": [10, 20, 30, 40, 50]
}

查询表达式:

  • numbers[?@ > \25`][30, 40, 50]`

⚠️ 注意: 这里的反引号`用于创建字面量(将在后面详细介绍)

7.2 表达式引用 &

语法说明:

  • &符号创建表达式引用
  • 主要用于排序和比较函数

示例 1: 表达式引用

{"data": [{"x": 3, "y": 2},{"x": 1, "y": 4}]
}

此符号将在函数章节中详细使用。

7.3 字面量 `

语法说明:

  • 反引号`创建字面量值
  • 用于在表达式中表示常量

示例 1: 字面量使用

{"values": [1, 2, 3, 4, 5]
}

查询表达式:

  • values[?@ > \3`][4, 5]`
  • values[?@ == \1`][1]`

8. 管道表达式 | 🔵

8.1 基本管道

语法说明:

  • 使用|将前一个表达式的结果作为后一个表达式的输入
  • 格式:expression1 | expression2

示例 1: 简单管道

{"data": {"users": [{"name": "Alice"},{"name": "Bob"},{"name": "Charlie"}]}
}

查询表达式:

  • data.users | [0]{"name": "Alice"}
  • data.users | [0].name"Alice"

8.2 管道与投影组合

示例 1: 管道后投影

{"wrapper": {"items": [1, 2, 3, 4, 5]}
}

查询表达式:

  • wrapper.items | [0:3][1, 2, 3]

9. 过滤表达式 🔵

9.1 基本过滤

语法说明:

  • 使用[?expression]过滤数组
  • expression必须是布尔表达式
  • 返回满足条件的元素

示例 1: 布尔属性过滤

{"users": [{"name": "Alice", "active": true},{"name": "Bob", "active": false},{"name": "Charlie", "active": true}]
}

查询表达式:

  • users[?active] → 返回active为true的用户
  • users[?!active] → 返回active为false的用户

9.2 比较运算符

语法说明:

  • == 等于
  • != 不等于
  • < 小于
  • <= 小于等于
  • > 大于
  • >= 大于等于

示例 1: 数值比较

{"products": [{"name": "Laptop", "price": 1200},{"name": "Mouse", "price": 25},{"name": "Keyboard", "price": 75}]
}

查询表达式:

  • products[?price < \100`]` → 价格小于100的产品
  • products[?price >= \75`]` → 价格大于等于75的产品

9.3 字符串比较

示例 1: 字符串相等

{"items": [{"type": "book", "title": "Python Guide"},{"type": "video", "title": "JS Tutorial"},{"type": "book", "title": "Java Basics"}]
}

查询表达式:

  • items[?type == 'book'] → 所有书籍

9.4 逻辑运算符

语法说明:

  • && 逻辑与
  • || 逻辑或
  • ! 逻辑非

示例 1: 组合条件

{"products": [{"name": "A", "price": 50, "inStock": true},{"name": "B", "price": 150, "inStock": false},{"name": "C", "price": 75, "inStock": true}]
}

查询表达式:

  • products[?price < \100` && inStock]` → 价格低于100且有货
  • products[?price > \100` || !inStock]` → 价格高于100或无货

9.5 使用当前节点过滤

示例 1: 简单数组过滤

{"numbers": [5, 10, 15, 20, 25, 30]
}

查询表达式:

  • numbers[?@ > \15`][20, 25, 30]`
  • numbers[?@ <= \20`][5, 10, 15, 20]`

10. 函数 🔵

10.1 类型和长度函数

type() 🔵

说明: 返回值的类型

{"value": 42, "text": "hello"}
  • type(value)"number"
  • type(text)"string"

length() 🔵

说明: 返回数组、对象或字符串的长度

{"items": [1, 2, 3], "text": "Hello"}
  • length(items)3
  • length(text)5

10.2 数组函数

sort() 🔵

说明: 排序数组

{"numbers": [3, 1, 4, 1, 5]}
  • sort(numbers)[1, 1, 3, 4, 5]

reverse() 🔵

说明: 反转数组

{"items": [1, 2, 3]}
  • reverse(items)[3, 2, 1]

min() / max() 🔵

说明: 最小/最大值

{"scores": [85, 92, 78, 95]}
  • min(scores)78
  • max(scores)95

sum() 🔵

说明: 求和

{"values": [10, 20, 30]}
  • sum(values)60

avg() 🔵

说明: 平均值

{"grades": [80, 90, 100]}
  • avg(grades)90

10.3 对象函数

keys() 🔵

说明: 获取对象的键

{"user": {"name": "John", "age": 30}}
  • keys(user)["name", "age"]

values() 🔵

说明: 获取对象的值

{"user": {"name": "John", "age": 30}}
  • values(user)["John", 30]

merge() 🔵

说明: 合并对象

{"obj1": {"a": 1}, "obj2": {"b": 2}}
  • merge(obj1, obj2){"a": 1, "b": 2}

10.4 字符串函数

contains() 🔵

说明: 检查包含关系

{"text": "Hello World", "tags": ["a", "b"]}
  • contains(text, 'World')true
  • contains(tags, 'a')true

starts_with() / ends_with() 🔵

说明: 检查前缀/后缀

{"filename": "document.pdf"}
  • starts_with(filename, 'doc')true
  • ends_with(filename, '.pdf')true

join() 🔵

说明: 连接数组为字符串

{"words": ["Hello", "World"]}
  • join(' ', words)"Hello World"

10.5 转换函数

to_string() / to_number() 🔵

说明: 类型转换

{"num": 42, "str": "123"}
  • to_string(num)"42"
  • to_number(str)123

to_array() 🔵

说明: 转换为数组

{"value": "single"}
  • to_array(value)["single"]

not_null() 🔵

说明: 返回第一个非null值

{"a": null, "b": "value"}
  • not_null(a, b)"value"

10.6 高级函数(使用表达式引用)

sort_by() 🔵

说明: 按表达式排序
语法: sort_by(array, &expression)

{"users": [{"name": "Charlie", "age": 35},{"name": "Alice", "age": 25},{"name": "Bob", "age": 30}]
}
  • sort_by(users, &age) → 按年龄排序的数组
  • sort_by(users, &name) → 按名字排序的数组

min_by() / max_by() 🔵

说明: 按表达式获取最小/最大元素

{"products": [{"name": "A", "price": 100},{"name": "B", "price": 50},{"name": "C", "price": 150}]
}
  • min_by(products, &price){"name": "B", "price": 50}
  • max_by(products, &price){"name": "C", "price": 150}

11. 组合使用:管道与函数

现在我们已经学习了所有基础概念,可以将它们组合使用。

11.1 管道与函数

示例 1: 管道传递给函数

{"data": {"numbers": [3, 1, 4, 1, 5, 9, 2, 6]}
}

查询表达式:

  • data.numbers | sort(@)[1, 1, 2, 3, 4, 5, 6, 9]
  • data.numbers | max(@)9
  • data.numbers | sum(@)31

11.2 投影后使用函数

示例 1: 提取后聚合

{"orders": [{"id": 1, "amount": 100},{"id": 2, "amount": 200},{"id": 3, "amount": 150}]
}

查询表达式:

  • orders[*].amount | sum(@)450
  • orders[*].amount | avg(@)150

11.3 过滤后使用函数

示例 1: 条件聚合

{"sales": [{"product": "A", "amount": 100, "region": "North"},{"product": "B", "amount": 200, "region": "South"},{"product": "C", "amount": 150, "region": "North"}]
}

查询表达式:

  • sales[?region == 'North'].amount | sum(@)250

12. 综合练习

12.1 数据转换练习

原始数据:

{"company": {"employees": [{"name": "Alice", "dept": "Engineering", "salary": 75000, "active": true},{"name": "Bob", "dept": "Sales", "salary": 60000, "active": true},{"name": "Charlie", "dept": "Engineering", "salary": 85000, "active": false},{"name": "David", "dept": "HR", "salary": 55000, "active": true}]}
}

练习查询:

  1. 获取所有员工姓名:

    • company.employees[*].name
    • 结果:["Alice", "Bob", "Charlie", "David"]
  2. 获取活跃员工:

    • company.employees[?active]
  3. 获取工程部门员工的薪资:

    • company.employees[?dept == 'Engineering'].salary
    • 结果:[75000, 85000]
  4. 计算活跃员工的平均薪资:

    • company.employees[?active].salary | avg(@)
    • 结果:63333.33
  5. 获取薪资最高的员工:

    • max_by(company.employees, &salary)
  6. 创建员工摘要:

    • company.employees[*].{name: name, department: dept}

12.2 复杂数据处理

数据结构:

{"store": {"inventory": [{"id": "P001","name": "Laptop","category": "Electronics","price": 999,"stock": 5,"tags": ["computer", "portable"]},{"id": "P002","name": "Mouse","category": "Electronics","price": 25,"stock": 50,"tags": ["computer", "accessory"]},{"id": "P003","name": "Notebook","category": "Stationery","price": 5,"stock": 200,"tags": ["paper", "writing"]},{"id": "P004","name": "Monitor","category": "Electronics","price": 299,"stock": 0,"tags": ["computer", "display"]}]}
}

复杂查询示例:

  1. 获取所有电子产品的名称和价格:

    store.inventory[?category == 'Electronics'].{name: name, price: price}
    
  2. 找出缺货的产品:

    store.inventory[?stock == `0`].name
    
  3. 计算所有产品的总库存价值:

    store.inventory[*].[price * stock] | sum(@)
    

    ⚠️ 注意:标准JMESPath不支持算术运算,这需要扩展支持

  4. 获取包含"computer"标签的产品:

    store.inventory[?contains(tags, 'computer')].name
    
  5. 找出价格在25到300之间的产品:

    store.inventory[?price >= `25` && price <= `300`]
    
  6. 按价格排序并获取最便宜的3个产品:

    sort_by(store.inventory, &price)[0:3].name
    

12.3 嵌套数据聚合

数据:

{"departments": [{"name": "Engineering","teams": [{"name": "Backend", "members": ["Alice", "Bob"]},{"name": "Frontend", "members": ["Charlie", "David", "Eve"]}]},{"name": "Sales","teams": [{"name": "Direct", "members": ["Frank", "Grace"]},{"name": "Channel", "members": ["Henry"]}]}]
}

聚合查询:

  1. 获取所有团队名称:

    departments[*].teams[*].name
    
  2. 统计每个部门的团队数量:

    departments[*].{dept: name, team_count: length(teams)}
    
  3. 获取所有员工(扁平化):

    departments[*].teams[*].members[]
    
  4. 找出成员最多的团队:

    max_by(departments[*].teams[], &length(members))
    

13. 功能限制 ⚠️

13.1 标准JMESPath不支持的功能

  1. 算术运算: 不支持 +, -, *, /
  2. 条件表达式: 不支持 if-else 或三元运算符
  3. 正则表达式: 标准规范不包含正则支持
  4. 自定义函数: 需要通过编程语言扩展

13.2 扩展功能 🟡

以下功能在部分实现中可用:

  • split() - 字符串分割
  • group_by() - 分组
  • unique() - 去重
  • map() - 映射函数

使用前请确认你的JMESPath实现是否支持。


14. Python集成最佳实践

14.1 性能优化

import jmespath# 好的做法:编译表达式
expression = jmespath.compile('users[?age > `30`].name')
result = expression.search(data)# 不好的做法:每次都解析
result = jmespath.search('users[?age > `30`].name', data)

14.2 错误处理

import jmespath
from jmespath.exceptions import ParseErrordef safe_search(expr, data, default=None):try:result = jmespath.search(expr, data)return result if result is not None else defaultexcept ParseError:return default

14.3 批量处理

def batch_extract(data, expressions):"""批量提取多个值"""results = {}for key, expr in expressions.items():results[key] = jmespath.search(expr, data)return results# 使用示例
queries = {'total_users': 'length(users)','active_count': 'length(users[?active])','user_names': 'users[*].name'
}
results = batch_extract(data, queries)

15. 快速参考

基础语法

标识符:        field, user.name
特殊字符键:    "field-name", "123abc"
索引:          array[0], array[-1]
切片:          array[0:5], array[::2], array[::-1]

投影

列表投影:      array[*].field
对象投影:      object.*.field
扁平化:        array[]
切片投影:      array[0:3].field

多选

多选列表:      [field1, field2]
多选哈希:      {key1: field1, key2: field2}

特殊符号

当前节点:      @
表达式引用:    &expression
字面量:        `value`
管道:          expression | expression

过滤

基本过滤:      array[?condition]
比较:          ==, !=, <, <=, >, >=
逻辑:          &&, ||, !

常用函数

类型:          type(), length()
数组:          sort(), reverse(), min(), max(), sum(), avg()
对象:          keys(), values(), merge()
字符串:        contains(), starts_with(), ends_with(), join()
高级:          sort_by(), min_by(), max_by()
转换:          to_string(), to_number(), to_array(), not_null()

学习建议

  1. 按照章节顺序学习,不要跳跃
  2. 每个概念都动手实践
  3. 使用 https://jmespath.org/ 在线测试
  4. 参考快速参考卡复习语法
http://www.gsyq.cn/news/843.html

相关文章:

  • 我的2025新版泛目录站群探索之旅:智能化SEO的新世界 - 蚂蚁站群
  • 高效管理多站点的秘密武器:站群管理软件实战分享 - 蚂蚁站群
  • 基于 Dify on DMS 快速构建客服对话数据质检服务,完成任务可领取积分、定制手办等好礼!
  • PCTA/PCTP学习笔记-TiDB 数据库核心原理与架构
  • 镜像站群CMS使用手记 - 蚂蚁站群
  • 多站点管理:批量站群建站软 - 蚂蚁站群
  • Aivilization Ai小镇体验
  • JH-ViewInspector - Android 控件ID/控件详情获取工具
  • 2024-2025学年第二学期教务处助教工作总结
  • CSRF
  • 【日记】拜托,丝之歌不开挂真的能打得过吗(975 字)
  • 2025天津大学预推免机试题解
  • 数据挖掘与隐私:你真的匿名了吗?
  • 饮酒其五
  • 简单的sql注入方法
  • socket重定义错误
  • 实用的软件
  • 使用-Jest-测试-VueJS-组件-全-
  • 基于C#实现照片条形码识别
  • 虚拟内存不足怎么解决?虚拟内存不足的原因及解决方法
  • Tekla门钢边柱节点源码
  • 由于裁剪的图片较小
  • 周总结报告6
  • ubuntu22.04安装cuda11.8+python3.12+pytorch2.6.0
  • 自己改造的一个ES的Reindex开源工具
  • CF1379
  • 备战软考4
  • P11364 [NOIP2024] 树上查询
  • pb9新建“项目”选项卡中文说明
  • 场论笔记(一)哈密顿算子的总结