JSON 路径查询:导航复杂的 JSON 结构
掌握 JSON 路径导航和查询。学习使用 JSONPath、jq 和路径查找工具从嵌套 JSON 中提取数据。
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# JSON 路径查询:导航复杂的 JSON 结构
JSON 路径是用于 JSON 的查询语言,类似于 XML 的 XPath。它允许您导航和从复杂的 JSON 结构中提取特定数据。
什么是 JSON 路径?
JSON 路径提供了一种标准化的方式来定位 JSON 文档中的特定数据。它在调试、数据提取和自动化中非常有用。
JSONPath 的优势
- 精确选择: 定位嵌套的特定值
- 查询过滤: 按条件选择数据
- 递归搜索: 在任何深度找到匹配项
- 转换数据: 在提取过程中修改数据
- 跨平台: 在许多编程语言中支持
JSONPath 语法
基本运算符
| 运算符 | 说明 | 例子 |
|--------|-----|------|
| $ | 根对象 | $ |
| . | 点符号(子对象) | $.store |
| [] | 方括号符号 | $['store'] |
| [n] | 数组索引 | $.books[0] |
| [] | 通配符(所有子项) | $.books[] |
| .. | 递归搜索 | $..price |
| [?()] | 过滤表达式 | $.books[?(@.price < 10)] |
| [start:end] | 数组切片 | $.books[0:2] |
示例 JSON
{
"书店": {
"书籍": [
{
"标题": "活着",
"作者": "余华",
"价格": 25.00,
"年份": 2018
},
{
"标题": "呐喊",
"作者": "鲁迅",
"价格": 20.00,
"年份": 2015
},
{
"标题": "边城",
"作者": "沈从文",
"价格": 18.00,
"年份": 2017
}
],
"地址": "北京市东城区"
},
"在线购买": {
"网站": "bookstore.com",
"配送": "全国"
}
}
路径示例
| 路径 | 说明 | 结果 |
|------|-----|------|
| $.书店.书籍[0].标题 | 第一本书的标题 | "活着" |
| $.书店.书籍[].价格 | 所有书的价格 | [25.00, 20.00, 18.00] |
| $.书店.书籍[?(@.价格 < 20)] | 价格低于 20 的书 | 边城 |
| $..作者 | 所有作者(任何深度) | ["余华", "鲁迅", "沈从文"] |
| $.书店.书籍[0:2] | 前两本书 | 活着、呐喊 |
过滤和选择
比较运算符
$.books[?(@.price > 20)] # 价格 > 20
$.books[?(@.price <= 20)] # 价格 <= 20
$.books[?(@.year == 2018)] # 年份等于 2018
$.books[?(@.author != "鲁迅")] # 作者不是鲁迅
逻辑运算符
$.books[?(@.price > 20 && @.year > 2015)] # 价格 > 20 且年份 > 2015
$.books[?(@.price < 20 || @.year == 2018)] # 价格 < 20 或年份为 2018
字符串匹配
$.books[?(@.title =~ /活/)] # 标题包含"活"
$.books[?(@.author.length > 2)] # 作者名字长度 > 2
递归搜索
找到所有特定字段
$..价格 # 找到所有价格字段
$..作者 # 找到所有作者
$..标题 # 找到所有标题
示例
对于上面的 JSON:
$..作者 # 返回: ["余华", "鲁迅", "沈从文"]
$..价格 # 返回: [25.00, 20.00, 18.00]
数组操作
索引和切片
$.books[0] # 第一本书
$.books[-1] # 最后一本书
$.books[0:2] # 第一和第二本书
$.books[1:] # 从第二本开始的所有书
$.books[-2:] # 最后两本书
使用通配符
$.books[].title # 所有书的标题
$.books[].price # 所有书的价格
$..books[].author # 任何深度的所有作者
使用 Big JSON Viewer
Big JSON Viewer 有内置的路径查找器。
使用步骤:- ✅ 自动生成路径
- ✅ 一键复制
- ✅ 处理超大文件
- ✅ 可视化树导航
- ✅ 搜索功能
jq 命令行工具
jq 是命令行 JSON 处理器,支持强大的路径查询。
安装
# macOS
brew install jq
# Ubuntu/Debian
sudo apt-get install jq
# Windows (Scoop)
scoop install jq
基本路径查询
# 单个字段
jq '.书店.书籍[0].标题' data.json
# 输出:"活着"
# 所有元素
jq '.书店.书籍[].标题' data.json
# 输出:
# "活着"
# "呐喊"
# "边城"
# 所有价格
jq '.书店.书籍[].价格' data.json
# 递归搜索
jq '.. | .作者? | select(. != null)' data.json
过滤
# 选择价格 < 20 的书
jq '.书店.书籍[] | select(.价格 < 20)' data.json
# 提取标题和价格
jq '.书店.书籍[] | {title: .标题, price: .价格}' data.json
# 过滤并排序
jq '.书店.书籍 | sort_by(.价格)' data.json
转换数据
# 收集所有标题
jq '.书店.书籍[].标题' data.json | jq -s .
# 创建新的 JSON 结构
jq '.书店.书籍 | map({title: .标题, author: .作者})' data.json
# 计数
jq '.书店.书籍 | length' data.json
高级查询
# 按条件分组
jq 'group_by(.年份)' data.json
# 获取第一个匹配项
jq '.书店.书籍 | map(select(.作者 == "鲁迅")) | .[0]' data.json
# 计算统计
jq '.书店.书籍 | {
平均价格: (map(.价格) | add / length),
总数: length,
最贵: max_by(.价格).标题
}' data.json
JavaScript JSONPath 库
quicktype JSONPath
npm install jsonpath-plus
使用:
const { JSONPath } = require('jsonpath-plus');
const data = {
书店: {
书籍: [
{ 标题: "活着", 价格: 25, 作者: "余华" },
{ 标题: "呐喊", 价格: 20, 作者: "鲁迅" },
{ 标题: "边城", 价格: 18, 作者: "沈从文" }
]
}
};
// 基本路径
const titles = JSONPath({
path: '$.书店.书籍[].标题',
json: data
});
console.log(titles); // ["活着", "呐喊", "边城"]
// 过滤
const cheapBooks = JSONPath({
path: '$.书店.书籍[?(@.价格 < 20)]',
json: data
});
console.log(cheapBooks); // 返回边城的数据
// 递归搜索
const allAuthors = JSONPath({
path: '$..作者',
json: data
});
console.log(allAuthors); // ["余华", "鲁迅", "沈从文"]
Python JSONPath
jsonpath-ng
pip install jsonpath-ng
使用:
from jsonpath_ng import parse
data = {
"书店": {
"书籍": [
{"标题": "活着", "价格": 25, "作者": "余华"},
{"标题": "呐喊", "价格": 20, "作者": "鲁迅"},
{"标题": "边城", "价格": 18, "作者": "沈从文"}
]
}
}
# 基本查询
jsonpath_expr = parse('$.书店.书籍[].标题')
titles = [match.value for match in jsonpath_expr.find(data)]
print(titles) # ['活着', '呐喊', '边城']
# 过滤查询
jsonpath_expr = parse('$.书店.书籍[?(@.价格 < 20)]')
cheap = [match.value for match in jsonpath_expr.find(data)]
print(cheap)
# 递归搜索
jsonpath_expr = parse('$..作者')
authors = [match.value for match in jsonpath_expr.find(data)]
print(authors) # ['余华', '鲁迅', '沈从文']
常见用例
提取 API 响应数据
# 从 API 获取并提取用户名
curl https://api.example.com/users | jq '.data[].name'
# 提取错误消息
curl https://api.example.com/error | jq '.errors[0].message'
数据验证
# 检查是否所有价格都 > 0
jq 'all(.书店.书籍[].价格 > 0)' data.json
# 查找缺失字段
jq '.书店.书籍[] | select(.作者 == null)' data.json
数据转换
# 转换为 CSV(与其他工具结合)
jq -r '.书店.书籍[] | [.标题, .作者, .价格] | @csv' data.json
# 转换为 SQL INSERT
jq -r '.书店.书籍[] | "INSERT INTO books VALUES (\(.标题), \(.价格));"' data.json
路径查找工具比较
| 工具 | 易用性 | 功能 | 最佳用途 |
|------|--------|------|---------|
| Big JSON Viewer | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 可视化查找 |
| jq | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 命令行强大 |
| 在线工具 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 快速查询 |
| IDE(VS Code) | ⭐⭐⭐⭐ | ⭐⭐⭐ | 开发时 |
| JavaScript 库 | ⭐⭐⭐ | ⭐⭐⭐⭐ | 应用内 |
最佳实践
1. 从简单开始
先从基本路径开始,逐步添加过滤条件。
# ✓ 简单开始
jq '.书籍[0]'
# ✓ 逐步添加
jq '.书籍[0].标题'
# ✓ 然后过滤
jq '.书籍[] | select(.价格 < 20)'
2. 测试小样本
在大文件上运行之前测试小的 JSON 样本。
3. 使用正确的工具
- 可视化探索: Big JSON Viewer
- 脚本化查询: jq 或 Python
- 应用集成: JavaScript 库
4. 保存常用查询
创建脚本或别名以便重用:
# ~/.bashrc 中的别名
alias get-book-titles='jq ".书店.书籍[].标题" data.json'
# 使用
get-book-titles
故障排除
路径返回 null
原因: 字段名或路径不匹配# 检查正确的字段名
jq 'keys' data.json
# 探索结构
jq '.' data.json | less
性能慢
对于大文件,使用流式处理:
# 对于 > 100MB 的文件
jq '.书籍[] | select(.价格 < 20)' huge.json > results.json
结论
JSON 路径查询是处理复杂数据的基本技能。无论您是调试 API 响应、提取配置值还是转换数据,掌握路径语法都会大大提高您的生产力。
快速参考
| 任务 | 命令 |
|------|------|
| 获取第一个元素 | $.[0] |
| 获取所有元素 | $.[*] |
| 按值过滤 | $.[]|select(.价格 < 20) |
| 递归搜索 | $..$ |
| 数组切片 | $.[0:3] |
现在您已准备好像专业人士一样查询 JSON!