JSONPath 快速上手

文章目录

1.简介

JSONPath 定义了一个字符串语法,用于从给定的JSON值中选择和提取 JSON (RFC 8259)值。

通俗来讲,JSONPath 是一种用于JSON数据的查询语言,类似于XML中的XPath。它通过特定的路径表达式,让你能够像在文件系统中导航目录一样,在JSON结构中查找和访问特定节点。

JSONPath 支持点(.)和方括号([])访问成员,$代表根元素,还支持通配符、数组切片、递归查找和过滤器表达式,有 JavaScript 、Python、Golang 等多种语言的实现库,让开发者能以简洁的方式处理复杂 JSON 数据。

2.核心语法详解

2.1 基本结构与符号

JSONPath表达式以$符号开头,表示JSON文档的根元素,类似于文件系统的根目录。

符号 含义 示例
$ 根对象 $ 表示整个JSON文档
.[] 子节点操作符 .store 或 ['store']
* 通配符 $.store.* 获取 store下的所有子节点
.. 递归下降 $..price递归查找所有price字段
@ 当前节点 在筛选表达式中使用
[] 下标操作 $.store.book[0]获取第一本书

2.2 路径表达方式

点表示法(更简洁):

js 复制代码
$.store.book[0].title

括号表示法(更灵活,支持特殊字符):

js 复制代码
$['store']['book'][0]['title']

2.3 数组切片与索引

JSONPath 支持灵活的数组成员访问:

表达式 含义 示例
[n] 选择第n个元素(从0开始) $.store.book[1]
[start:end] 选择从 start 到 end-1 的元素 $.store.book[0:2]
[start:] 从 start 到数组末尾 $.store.book[1:]
[:end] 从开始到 end-1 $.store.book[:2]
[-n] 倒数第 n 个元素 $.store.book[-1]

2.4 筛选表达式

JSONPath 最强大的功能之一是能够基于条件过滤数据:

js 复制代码
// 找到所有价格低于20的书籍
$.store.book[?(@.price < 20)]

// 找到朴灵作者的所有书籍
$.store.book[?(@.author == '朴灵')]

// 找到有"指南"关键词的书籍
$.store.book[?(@.title =~ /.*指南.*/)]

3.实际应用场景

场景1:API响应数据提取

js 复制代码
// API返回的复杂响应
const apiResponse = {
  "status": "success",
  "data": {
    "users": [
      {"id": 1, "name": "张三", "role": "admin", "active": true},
      {"id": 2, "name": "李四", "role": "user", "active": false},
      {"id": 3, "name": "王五", "role": "user", "active": true}
    ]
  }
};

// 提取所有活跃用户的名字
const expression = "$.data.users[?(@.active == true)].name";
// 结果: ["张三", "王五"]

场景2:配置文件的灵活读取

js 复制代码
// 应用配置文件
const config = {
  "app": {
    "name": "MyApp",
    "version": "2.1.0"
  },
  "database": {
    "hosts": [
      {"address": "primary.db.example.com", "port": 3306},
      {"address": "replica.db.example.com", "port": 3306}
    ],
    "credentials": {
      "username": "admin",
      "password": "secret"
    }
  }
};

// 获取所有数据库主机地址
const hosts = "$.database.hosts[*].address";
// 结果: ["primary.db.example.com", "replica.db.example.com"]

场景3:数据清洗与转换

js 复制代码
// 原始订单数据
const orders = {
  "orders": [
    {
      "id": 1001,
      "customer": "张三",
      "items": [
        {"product": "笔记本电脑", "price": 5999, "quantity": 1},
        {"product": "鼠标", "price": 89, "quantity": 2}
      ],
      "discount": 0.1
    },
    {
      "id": 1002,
      "customer": "李四",
      "items": [
        {"product": "键盘", "price": 299, "quantity": 1}
      ],
      "discount": 0
    }
  ]
};

// 计算每个订单的总金额
const orderTotals = "$.orders[*].items[*].price";
// 提取所有价格: [5999, 89, 299]

4.各语言中的实现

类似于 XPath,JSONPath 在主流编程语言中也都有成熟实现。

Go

go 复制代码
import "github.com/oliveagle/jsonpath"

res, err := jsonpath.JsonPathLookup(data, "$.store.book[?(@.price < 20)].title")

JavaScript/Node.js

js 复制代码
// 使用 jsonpath 库
const jp = require('jsonpath');

const result = jp.query(data, '$.store.book[?(@.price < 20)].title');

Python

py 复制代码
import jsonpath_ng

parser = jsonpath_ng.parse('$.store.book[?(@.price < 20)].title')
matches = parser.find(data)

Java

java 复制代码
import com.jayway.jsonpath.JsonPath;

List<String> titles = JsonPath.read(json, "$.store.book[?(@.price < 20)].title");

5.性能优化与最佳实践

  1. 缓存编译表达式:对于频繁使用的JSONPath表达式,预先编译可以提高性能:
js 复制代码
// Node.js示例
const compiledPath = jp.compile('$.store.book[?(@.price < 20)].title');
const result = compiledPath(data);
  1. 避免过度递归:..递归操作虽然方便,但在大型JSON文档中可能影响性能,尽量使用精确路径。

  2. 使用筛选器减少数据量:先筛选后提取,避免处理不必要的数据:

js 复制代码
// 不推荐 - 先提取所有再过滤
$.store.book[*].title

// 推荐 - 先过滤再提取
$.store.book[?(@.price < 20)].title
  1. 处理可能不存在的路径:使用安全访问或默认值:
js 复制代码
// 使用 || 提供默认值
$.store.book[?(@.price < 20)].title || '未知标题'

6.常见问题与解决方案

问题1:路径存在但返回null

js 复制代码
// 可能原因:数据类型不匹配
// 错误示例:book是数组却用对象方式访问
$.store.book.title  // book是数组,应使用 $.store.book[0].title

问题2:特殊字符处理

js 复制代码
{
  "data": {
    "user-name": "张三",
    "email.address": "zhangsan@example.com"
  }
}

// 使用括号表示法处理特殊字符
$['data']['user-name']
$['data']['email.address']

问题3:处理大型JSON时的内存问题

js 复制代码
// 使用流式处理或分页
// 许多JSONPath库支持回调或迭代器模式
jp.nodes(data, '$..largeArray[*]', function(node) {
    // 逐条处理,避免一次性加载全部
});

7.高级技巧与模式

1. 组合查询

js 复制代码
// 查找价格低于20且作者是朴灵的书籍
$.store.book[?(@.price < 20 && @.author == '朴灵')]

// 查找价格低于15或高于25的书籍
$.store.book[?(@.price < 15 || @.price > 25)]

2. 函数扩展

js 复制代码
// 长度函数
$.store.book[?(@.title.length() > 10)]

// 类型检查
$.store.book[?(@.price.type() == 'number')]

3. 结果集操作

js 复制代码
// 获取前N个结果
$.store.book[:3]

// 获取唯一值(需要实现支持)
$.store.book[*].author | unique()

8.总结

JSONPath是处理JSON数据的强大工具,它将复杂的数据提取任务简化为直观的路径表达式。

掌握JSONPath不仅能提高开发效率,还能使代码更加简洁易读。无论你是处理API响应、配置文件还是复杂的数据结构,JSONPath都能提供优雅的解决方案,让你在JSON数据的海洋中轻松航行,精准定位每一份需要的信息。


参考文献

jsonpath.com
RFC 9535 JSONPath: Query Expressions for JSON
JSON

相关推荐
带刺的坐椅2 个月前
snack4-jsonpath v4.0.2 发布
java·jsonpath
组合缺一2 个月前
全球首个支持 IETF JSONPath (RFC 9535) 标准的 Java 框架,Snack4-Jsonpath v4.0.0 发布
java·开发语言·json·jsonpath
AskHarries1 年前
一种用于JSON数据的查询语言JSONPath
java·后端·python·json·jsonpath
人生の三重奏1 年前
爬虫——同步与异步加载
爬虫·jsonpath·同步与异步·腾讯新闻
张三疯不疯1 年前
Java的JSONPath(fastjson)使用总结
java·jsonpath
京东云技术团队2 年前
Jayway JsonPath-提取JSON文档内容的Java DSL
java·jsonpath
YoLo-82 年前
02-2解析JsonPath
jsonpath
光仔December2 年前
【Python从入门到进阶】31、使用JSONPath解析淘票票网站地区接口数据
python爬虫·urllib·jsonpath·json解析·cookie