JMESPath由浅入深完全入门教程(自用)
JMESPath 完全学习指南 v3.0
1. 简介与安装
什么是JMESPath?
JMESPath(JSON Matching Expression Path)是一种查询语言,用于从JSON文档中提取和转换数据。类似于XPath用于XML,JMESPath专门为JSON设计。
重要说明
本教程基于标准JMESPath规范,严格按照循序渐进的方式介绍每个概念。每个新语法或符号都会在使用前进行完整介绍。
标准功能标记: 🔵 标准JMESPath功能
扩展功能标记: 🟡 部分实现支持的扩展功能
限制说明标记: ⚠️ 功能限制或注意事项
安装
pip install jmespath
Python基础用法
import jmespath
data = {
"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"age→25email→"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.age→null(属性不存在)user.profile.bio→null(中间路径不存在)
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]→1matrix[1][2]→6matrix[-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)→3length(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)→78max(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')→truecontains(tags, 'a')→true
starts_with() / ends_with() 🔵
说明: 检查前缀/后缀
{"filename": "document.pdf"}
starts_with(filename, 'doc')→trueends_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(@)→9data.numbers | sum(@)→31
11.2 投影后使用函数
示例 1: 提取后聚合
{
"orders": [
{"id": 1, "amount": 100},
{"id": 2, "amount": 200},
{"id": 3, "amount": 150}
]
}
查询表达式:
orders[*].amount | sum(@)→450orders[*].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}
]
}
}
练习查询:
-
获取所有员工姓名:
company.employees[*].name- 结果:
["Alice", "Bob", "Charlie", "David"]
-
获取活跃员工:
company.employees[?active]
-
获取工程部门员工的薪资:
company.employees[?dept == 'Engineering'].salary- 结果:
[75000, 85000]
-
计算活跃员工的平均薪资:
company.employees[?active].salary | avg(@)- 结果:
63333.33
-
获取薪资最高的员工:
max_by(company.employees, &salary)
-
创建员工摘要:
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"]
}
]
}
}
复杂查询示例:
-
获取所有电子产品的名称和价格:
store.inventory[?category == 'Electronics'].{name: name, price: price} -
找出缺货的产品:
store.inventory[?stock == `0`].name -
计算所有产品的总库存价值:
store.inventory[*].[price * stock] | sum(@)⚠️ 注意:标准JMESPath不支持算术运算,这需要扩展支持
-
获取包含"computer"标签的产品:
store.inventory[?contains(tags, 'computer')].name -
找出价格在25到300之间的产品:
store.inventory[?price >= `25` && price <= `300`] -
按价格排序并获取最便宜的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"]}
]
}
]
}
聚合查询:
-
获取所有团队名称:
departments[*].teams[*].name -
统计每个部门的团队数量:
departments[*].{dept: name, team_count: length(teams)} -
获取所有员工(扁平化):
departments[*].teams[*].members[] -
找出成员最多的团队:
max_by(departments[*].teams[], &length(members))
13. 功能限制 ⚠️
13.1 标准JMESPath不支持的功能
- 算术运算: 不支持 +, -, *, /
- 条件表达式: 不支持 if-else 或三元运算符
- 正则表达式: 标准规范不包含正则支持
- 自定义函数: 需要通过编程语言扩展
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 ParseError
def safe_search(expr, data, default=None):
try:
result = jmespath.search(expr, data)
return result if result is not None else default
except 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()
学习建议
- 按照章节顺序学习,不要跳跃
- 每个概念都动手实践
- 使用 https://jmespath.org/ 在线测试
- 参考快速参考卡复习语法

浙公网安备 33010602011771号