通用技术 [jsonpath] 如何按条件查找元素的结果的第一个节点

bauul · 2018年05月08日 · 最后由 bauul 回复于 2019年12月06日 · 4558 次阅读

缘由

由于之前做的测试服务,让同事们在浏览器中编写测试用例,JSON格式的
在编写上下文依赖的用例的时候,出现这样的问题,
我们希望通过 jsonpath 定位一个符合条件的结果时,不能获得我们想要的结果

{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    },
    "expensive": 10
}

查找节点

JsonPath.read(s, "$..book[?(@.isbn)]")
JsonPath.read(s, "$..book[?(@.isbn)][1]")

结果

"JsonPath.read(s, "$..book[?(@.isbn)]")":[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
"JsonPath.read(s, "$..book[?(@.isbn)])[1]"":[]

从结果来看直接加 [1] 并没有用,并且尝试了类似 xpath 的语法,也不支持

解决的思路

  • 由于使用了 jsonpath,所以找到它的源码,可以尝试从源码入手,增加这个功能,代价较大,耗时不确定
  • 因为返回值是一个 json 数组,那么就可以再次解析,然后获取它的第一个元素,这样做既解决了问题,并且修改代价较小
Object isbnBookArrayObject = JsonPath.read(s, "$..book[?(@.isbn)]");
JsonPath.parse(isbnBookArrayObject.toString()).read("$.[0]"))

参考

jsonpath github
sonpath 初探

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 7 条回复 时间 点赞

挺好的思路
我的想法是 把 json 转为对象再处理,是不是更灵活通用一些

可以搞个 java 版本的爬虫

Mr_Peace 回复

在代码里写,是可以的,但是把它做成通用的,参数化的话,需要看下怎么做好点

tttttttttggggg 回复

这个工作量就大了😜

用 fastjson 的 jsonpath 可以支持,比如下面的例子能够获取过滤器后的第一个元素
$.data[?(@.name== '123' )][0].no

taurusbb 回复

嗯嗯,已经解决了,感谢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册