Jayway JsonPath-提取JSON文档内容的Java DSL | 京东物流技术团队

介绍


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 JsonPathStefan 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代码来验证。

复制代码
String json ="{.....}";
Object read = JsonPath.read(json, "$..price.min()");
System.out.println(read);

示例报文

复制代码
{
    "address":"大良街道同兴路****",
    "createTime":"2023-09-20 17:48:44",
    "customerName":"培^_^",
    "id":0,
    "memberId":"ECP002000*****",
    "mobile":"184^_^8547",
    "extendMessage":{
        "clientNo":"testEBU516154",
        "clientName":"广州网络科技有限公司",
        "spSoNo":"test1976065878296",
        "road":"011"
    },
    "odOrderDetailList":[
        {
            "id":1,
            "productName":"白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款",
            "quantity":1,
            "productSku":"38fjjjj",
            "price":189.6
        },
        {
            "id":2,
            "productName":"测试SKU",
            "quantity":3,
            "productSku":"ESG03JJ1",
            "price":200
        }
    ],
    "totalPrice":0,
    "volume":17318.4,
    "extendInfo":{
        "templateInfo":[
            {
                "code":"TP123",
                "isPrint":1,
                "type":2,
                "printType":0
            },
            {
                "code":"TPABC",
                "isPrint":1,
                "type":4,
                "printType":0
            }
        ],
        "attrs":{
            "plateFormCode":"274"
        },
        "senderName":"流苏",
        "senderAddress":"广东省中山市南头镇永辉北路*****",
        "paymentTime":"2023-09-20 17:22:31"
    },
    "carrierName":"京东配送",
    "provinceName":"广东",
    "isConsumable":0,
    "merchantType":"0",
    "tags":[
        "a",
        "b",
        "c",
        "d",
        "e"
    ]
}

操作结果

JsonPath 结果
$.extendMessage.clientName "广州网络科技有限公司"
$.extendMessage'clientNo' "testEBU516154"
$.extendMessage {"clientNo":"testEBU516154","clientName":"广州网络科技有限公司","spSoNo":"test1976065878296","road":"011"}
$.odOrderDetailList0.productName "白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款"
$.odOrderDetailList-1.productName "测试SKU"
$.odOrderDetailList.length() 2
$.tags: "a", "b", "c", "d", "e"
$.tags2: "c", "d", "e"
$.tags:3 "a", "b", "c"
$.tags1:4 "b", "c", "d"
$.tags-2: "d", "e"
$.tags:-3 "a", "b"
$.tags:-3.length() 2
$.odOrderDetailList0,1.productName "白医生中频针灸理疗仪家用医院医用多功能颈椎肩周炎腰肌劳损电疗经络激光低频按摩器同款中频激光综合治疗仪 2023新款", "测试SKU"
$.odOrderDetailList1.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 转载请注明来源

相关推荐
吃饱了得干活10 小时前
Spring Cloud Gateway 微服务网关:路由、断言、过滤器
java·spring cloud
lwx5728011 小时前
探秘InnoDB:搞懂它的内存、线程、磁盘与日志刷盘策略
java·后端
Flynt13 小时前
从Spring Boot 4.0升到4.1,我在Maven和gRPC上栽了跟头
java·spring boot·后端
plainGeekDev14 小时前
Activity 间传值 → Navigation 参数
android·java·kotlin
Venuslite14 小时前
从 Unexpected token < 到 Extra data:一次讲清 JSON 解析错误的排查思路
json
plainGeekDev14 小时前
onActivityResult → ActivityResult API
android·java·kotlin
Sunia14 小时前
《AgentX 专栏》10-生产部署:3台2C4G云服务器把企业级Agent真正跑起来的完整方案
java·架构
ZhengEnCi15 小时前
J7A-高级Java工程师面试三道灵魂拷问-深度广度与工程素养的终极检验
java·后端
狼爷1 天前
吃透 Java Function 接口,搞定 99% 的 Stream 场景
java·函数式编程
祎雪双十Gy2 天前
从 DataX 的配置加载说起:我用 FastJson2 做了一个轻量级动态配置管理库
java·后端