JSONPath解析

访问我的博客


前言

在工作中,经常会遇到从一串 JSON 中提取一个或多个字段的情况,常用的做法就是将其反序列化为 JSONObject 对象,然后从对象中获取,如果是 JSONArray 就进行迭代获取,总之比较麻烦。可以使用 JsonPath 快速提取所需信息。

JSONPATH 简明语法

JsonPath 描述
$ 根节点
@ 当前节点
.or[] 子节点
.. 选择所有符合条件的节点
* 所有节点
[] 迭代器标示,如数组下标
[,] 支持迭代器中做多选
[start🔚step] 数组切片运算符
?() 支持过滤操作
() 支持表达式计算

尝试 JsonPath 前提准备

maven 工程引入 jsonpath 的依赖

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.4.0</version>
</dependency>

有人说,FastJson 自带了 JSONPath,为什么不用要用这个呢?我只能回 FastJson 确实很好用,但是 FastJson 的 JsonPath 是真难用!

JsonPath 简单入门版

给定一串 JSON 如下所示:

{
  "store": {
    "book": [
      {
        "category": "文学",
        "author": "曹雪芹",
        "title": "红楼梦",
        "price": 47.20
      },
      {
        "category": "心理",
        "author": "凯利·麦格尼格尔",
        "title": "自控力",
        "price": 30.20
      },
      {
        "category": "励志",
        "author": "史蒂芬·柯维",
        "title": "高效能人士的七个习惯",
        "isbn": "7515326395",
        "price": 51
      },
      {
        "category": "小说",
        "author": "毛姆",
        "title": "月亮与六便士",
        "isbn": "7533936027",
        "price": 19.50
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

需要按照条件提取信息

public class JsonPathExample {
    public static void main(String[] args) throws IOException {
        // 读取上面的那串 JSON 
        File file = new File(JsonPathExample.class.getClassLoader().getResource("store.json").getPath());
        String storeJson = FileUtils.readFileToString(file);
        
        // 注意使用 JsonPath ,不要使用 FastJson 的 JSONPath
        // 输出第一本书的作者
        println(JsonPath.read(storeJson, "$.store.book[0].author").toString());
        // 输出结果: 曹雪芹

        // 输出所有书的作者
        println(JsonPath.read(storeJson, "$.store.book[*].author").toString());
        // 输出结果: ["曹雪芹","凯利·麦格尼格尔","史蒂芬·柯维","毛姆"]

        // 输出分类为文学的书信息
        println(JsonPath.read(storeJson, "$.store.book[?(@.category =='文学')]").toString());
        // 输出结果: [{"author":"曹雪芹","price":47.2,"category":"文学","title":"红楼梦"}]

        // 输出价格大于 50 的书
        println(JsonPath.read(storeJson, "$.store.book[?(@.price > 50)]").toString());
        // 输出结果: [{"author":"史蒂芬·柯维","price":51,"isbn":"7515326395","category":"励志","title":"高效能人士的七个习惯"}]

        // 输出 book[*] 中包含 isbn 的书
        println(JsonPath.read(storeJson, "$.store.book[?(@.isbn)]").toString());
        // 输出结果: [{"author":"史蒂芬·柯维","price":51,"isbn":"7515326395","category":"励志","title":"高效能人士的七个习惯"},{"author":"毛姆","price":19.5,"isbn":"7533936027","category":"小说","title":"月亮与六便士"}]

        // 输出 json 中所有的 price
        println(JsonPath.read(storeJson, "$..price").toString());
        // 输出结果: [19.95,47.2,30.2,51,19.5]
    }

    private static void println(String str) {
        System.out.println(str);
    }
}

以上基本上,简单提取需要 JSON 中的信息便已经足够了,以下为扩展内容,也是我在工作中使用到的。

JsonPath 复杂结构版

给定一串 JSON 如下所示

{
  "bookId": 7333,
  "volumeDetailList": [
    {
      "title": "卷一 恢弘世界",
      "volumeId": 28585,
      "chapterDetailList": [
        {
          "chapterId": 11719110,
          "free": true,
          "name": "第1章 上九天",
          "price": 0,
          "words": 1678,
          "contentId": 2930434
        },
        {
          "chapterId": 1719111,
          "free": true,
          "name": "第2章:揽月",
          "price": 0,
          "words": 2390,
          "contentId": 2930444
        }
      ]
    },
    {
      "title": "卷二 在人家",
      "volumeId": 285852,
      "chapterDetailList": [
        {
          "chapterId": 1719120,
          "free": false,
          "name": "第3章:千年后之始",
          "price": 19,
          "words": 2989,
          "contentId": 29540933
        },
        {
          "chapterId": 17133111,
          "free": false,
          "name": "第4章:破冰而生",
          "price": 30,
          "words": 3409,
          "contentId": 29540988
        }
      ]
    }
  ]
}

读取需要的相关信息

public class JsonPathExample2 {
    public static void main(String[] args) throws IOException {
        // 用于读取上面的那串 JSON
        File file = new File(JsonPathExample2.class.getClassLoader().getResource("chapterlist.json").getPath());
        String chapterlistJson = FileUtils.readFileToString(file);

        // 得到书的所有卷名称
        println(JsonPath.read(chapterlistJson, "$..title").toString());
        // 输出结果: ["卷一 恢弘世界","卷二 在人家"]

        // 得到书的所有章节名称
        println(JsonPath.read(chapterlistJson, "$..name").toString());
        // 输出结果: ["第1章 上九天","第2章:揽月","第3章:千年后之始","第4章:破冰而生"]

        // 上面两个非常简单,下面这个需要注意 volumeDetailList 与 chapterDetailList 都是数组,且是数组嵌套
        // 得到 chapterId 为 17133111 的 contentId
        println(JsonPath.read(chapterlistJson, "$.volumeDetailList[*].chapterDetailList[?(@.chapterId == '17133111')].contentId").toString());
        // 简化写法
        println(JsonPath.read(chapterlistJson, "$..[?(@.chapterId == '17133111')].contentId").toString());
        // 输出结果: 29540988
    }

    private static void println(String str) {
        System.out.println(str);
    }
}

常用JsonPath在线解析工具网站

这两个网站都可以在线写 JsonPath 语句,可以用来校验写的是否正确而不用去跑代码程序,比较方便

参考文章

小结

在工作中使用到的时候,也不熟悉 JsonPath 的语法,写出了比较复杂的 JsonPath,但是在写这篇博客的时候,又写了一般,发现了有很多自己写的 JsonPath 语句是可以精简的,比如倒数第二条 JsonPath 语句可以精简为它下面那句。

在输出的时候,可以发现自己认知中不足之处,写博客还是能给自己带来很多好处的,希望自己能够笔耕不息~

posted @ 2018-08-15 22:21  WeJan1  阅读(742)  评论(0编辑  收藏  举报