介绍
JsonPath是一种能够提取部分JSON文档属性、对象、数组的语法,支持条件过滤、数学运算、字符串处理等功能。JsonPath与JSON文档就像 XPath 表达式与 XML 文档结合使用一样。
由于 JSON 结构通常是匿名的,并不一定和XML一样具有“根成员对象”,因此 JsonPath假定分配$给外层对象的抽象名称。JsonPath由用点分隔的表达式段(操作符)组成。 操作符可以是一个简单的词,如 JSON 值名称、*,也可以是括在方括号 [ ] 中的更复杂的构造。 括号段前的分隔点是可选的,也可以省略。下面是几种JsonPath的提取JSON文档内容语法:
| JsonPath | 描述 |
|---|---|
| $.object.name | 返回object.name的内容。 |
| $.object['name'] | 返回object.name的内容。 |
| $.object.['name'] | 返回object.name的内容。 |
| $.object.history.length() | 返回object.history数组元素的个数。 |
| $[?(@.name == 'Object')].price.first() | 返回第一个名为'Object'的对象的价格字段。 |
| $[?(@.price > 10)].length() | 返回price大于10的对象个数。 |
Jayway JsonPath是Stefan Goessner JsonPath的Java实现,是用于读取JSON文档的Java DSL。本文主要通过Jayway JsonPath来简单介绍JsonPath的使用语法,通过真实报文案例来进行操作。
支持的操作符
| 操作符 | 描述 |
|---|---|
$ | 查询的根节点对象,表示一个json的数据,可以是对象或数组 |
@ | 当前节点对象 |
* | 通配符,获取所有节点 |
.. | 递归查找,查找所有层次的属性值 |
<name> | 按名称匹配对象属性。 |
.<name> | 按照名称查找子节点 |
['<name>','<name>',...] | 可用查找多个节点 |
[<number>,<number>,...] | 按索引匹配数组元素,可同时查找多个数组元素 |
[start:end] | 按定义的范围匹配数组元素: |
<start>- 要匹配的第一个索引(包括)。 如果未指定,则匹配从头开始的所有数组元素。 如果为负数,则指定从数组末尾开始的偏移量。
<end>- 要匹配的最后一个索引(不包括)。 如果未指定,则匹配所有数组元素到最后。 如果为负数,则指定从数组末尾开始的偏移量。 | | [?(<expression>)] | 过滤表达式可匹配对象/数组元素,表达式的结果必须为布尔值 |
可以通过在 JSONPath 中添加 ~ 后缀来提取匹配的元素名称。 它返回匹配对象的名称或匹配数组项的字符串格式的索引。
过滤操作符
| 操作符 | 描述 |
|---|---|
| == | 等于 |
| != | 不等于 |
| < | 小于 |
| <= | 小于或等于 |
| > | 大于 |
| >= | 大于或等于 |
| =~ | 匹配正则表达式 [?(@.name =~ /foo.*?/i)] |
| in | 包含 [?(@.size in ['S', 'M'])] |
| nin | 不包含 |
| subsetof | 子集 [?(@.sizes subsetof ['S', 'M', 'L'])] |
| anyof | 交集 [?(@.sizes anyof ['M', 'L'])] |
| noneof | 不是交集 [?(@.sizes noneof ['M', 'L'])] |
| size | 左侧(数组或字符串)的大小应与右侧匹配 |
| empty | 左侧(数组或字符串)应该为空 |
支持的函数
可以在JsonPath表达式执行后进行调用,其输入值为表达式的结果。函数的输出看具体某个函数的含义。
| 函数 | 描述 | 返回值类型 |
|---|---|---|
| min() | 数值类型数组最小值 | Double |
| max() | 数值类型数组最大值 | Double |
| avg() | 数值类型数组平均值 | Double |
| stddev() | 数值类型数组标准差 | Double |
| length() | 数组长度 | Integer |
| sum() | 数值类型数组求和 | Double |
| keys() | 提取匹配的元素名称与~操作符功能一致 | Set<E> |
| concat(X) | 拼接 | 与入参相同 |
| append(X) | 把元素添加到JsonPath输出的数组中 | 与入参相同 |
| first() | 数组中的第一个元素 | 数组中元素类型 |
| last() | 数组中的最后一个元素 | 数组中元素类型 |
| index(X) | 提供索引为X的数组的元素,如果X为负数,则从后往前取 | 数组中元素类型 |
用一个复杂的接单报文来演示
https://jsonpath.com,这个在线网站可以用来验证JsonPath表达式,但是不支持函数,函数可以通过java代码来验证。
1String json ="{.....}"; 2Object read = JsonPath.read(json, "$..price.min()"); 3System.out.println(read); 4 5
示例报文
1{ 2 "address":"大良街道同兴路****", 3 "createTime":"2023-09-20 17:48:44", 4 "customerName":"培^_^", 5 "id":0, 6 "memberId":"ECP002000*****", 7 "mobile":"184^_^8547", 8 "extendMessage":{ 9 "clientNo":"testEBU516154", 10 "clientName":"广州网络科技有限公司", 11 "spSoNo":"test1976065878296", 12 "road":"011" 13 }, 14 "odOrderDetailList":[ 15 { 16 "id":1, 17 "productName":"白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款", 18 "quantity":1, 19 "productSku":"38fjjjj", 20 "price":189.6 21 }, 22 { 23 "id":2, 24 "productName":"测试SKU", 25 "quantity":3, 26 "productSku":"ESG03JJ1", 27 "price":200 28 } 29 ], 30 "totalPrice":0, 31 "volume":17318.4, 32 "extendInfo":{ 33 "templateInfo":[ 34 { 35 "code":"TP123", 36 "isPrint":1, 37 "type":2, 38 "printType":0 39 }, 40 { 41 "code":"TPABC", 42 "isPrint":1, 43 "type":4, 44 "printType":0 45 } 46 ], 47 "attrs":{ 48 "plateFormCode":"274" 49 }, 50 "senderName":"流苏", 51 "senderAddress":"广东省中山市南头镇永辉北路*****", 52 "paymentTime":"2023-09-20 17:22:31" 53 }, 54 "carrierName":"京东配送", 55 "provinceName":"广东", 56 "isConsumable":0, 57 "merchantType":"0", 58 "tags":[ 59 "a", 60 "b", 61 "c", 62 "d", 63 "e" 64 ] 65} 66 67 68
操作结果
| JsonPath | 结果 |
|---|---|
| $.extendMessage.clientName | "广州网络科技有限公司" |
| $.extendMessage['clientNo'] | "testEBU516154" |
| $.extendMessage | {"clientNo":"testEBU516154","clientName":"广州网络科技有限公司","spSoNo":"test1976065878296","road":"011"} |
| $.odOrderDetailList[0].productName | "白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款" |
| $.odOrderDetailList[-1].productName | "测试SKU" |
| $.odOrderDetailList.length() | 2 |
| $.tags[:] | ["a", "b", "c", "d", "e" ] |
| $.tags[2:] | ["c", "d", "e" ] |
| $.tags[:3] | ["a", "b", "c"] |
| $.tags[1:4] | ["b", "c", "d"] |
| $.tags[-2:] | ["d", "e"] |
| $.tags[:-3] | ["a", "b"] |
| $.tags[:-3].length() | 2 |
| $.odOrderDetailList[0,1].productName | "白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款", "测试SKU" |
| $.odOrderDetailList[1].[productName,price] | "测试SKU", 200 |
| $..id | 0,1,2 |
| $.odOrderDetailList[?(@.id == 4 - 0.4 * 5)].productSku | "ESG03JJ1" |
| $.odOrderDetailList[?(@.id == 1 | |
| $.extendInfo.templateInfo[?(!(@.type == 2))].code | "TPABC" |
| $.extendInfo.templateInfo[?((@.type != 2))].code | "TPABC" |
| $.odOrderDetailList[?(@.price > 190)].productName | "测试SKU" |
| $.odOrderDetailList[?(@.id> $.id)].productSku | ["38fjjjj","ESG03JJ1"] |
| $..[?(@.productSku)] | [{"id":1,"productName":"白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款","quantity":1,"productSku":"38fjjjj","price":189.6},{"id":2,"productName":"测试SKU","quantity":3,"productSku":"ESG03JJ1","price":200}] |
| $..tags.length() | 5 |
| $.odOrderDetailList[*].price.min() | 189.6 |
| $..price.max() | 200 |
作者:京东物流 马红岩
来源:京东云开发者社区 自猿其说 Tech 转载请注明来源
