JsonPath介绍及使用

  • Post author:
  • Post category:其他




1.介绍

JsonPath是一种简单的方法来提取给定JSON文档的部分内容。JsonPath有许多编程语言,如Javascript,Python和PHP,Java。

参考地址:

https://github.com/json-path/JsonPath



2.作用

JsonPath提供的json解析非常强大,它提供了类似正则表达式的语法,基本上可以满足所有你想要获得的json内容。如果可以使用JsonPath来解析json,以下的问题可以被解决:

2.1数据不使用特殊的脚本,可以在客户端交互的发现并取并获取。

2.2客户机请求的JSON数据可以减少到服务器上的相关部分,这样可以最大限度地减少服务器响应的带宽使用率。



3.操作符

符号 描述
$ 查询的根节点对象,用于表示一个json数据,可以是数组或对象
@ 过滤器断言(filter predicate)处理的当前节点对象,类似于java中的this字段
* 通配符,可以表示一个名字或数字
可以理解为递归搜索,Deep scan. Available anywhere a name is required.
.<name> 表示一个子节点
[‘<name>’ (, ‘<name>’)] 表示一个或多个子节点
[<number> (, <number>)] 表示一个或多个数组下标
[start:end] 数组片段,区间为[start,end),不包含end
[?(<expression>)] 过滤器表达式,表达式结果必须是boolean



4.函数

可以在路径的尾部调用,函数的输出是路径表达式的输出,该函数的输出是由函数本身所决定的。

函数 描述 输出
min() 提供数字数组的最小值 Double
max() 提供数字数组的最大值 Double
avg() 提供数字数组的平均值 Double
stddev() 提供数字数组的标准偏差值 Double
length() 提供数组的长度 Integer



5.过滤器运算符

过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器将是[?(@.age > 18)],其中@表示正在处理的当前项目。 可以使用逻辑运算符&&和||创建更复杂的过滤器。 字符串文字必须用单引号或双引号括起来([?(@.color == ‘blue’)] 或者 [?(@.color == “blue”)])。

操作符 描述
== left等于right(注意1不等于’1’)
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
=~ 匹配正则表达式[?(@.name =~ /foo.*?/i)]
in 左边存在于右边 [?(@.size in [‘S’, ‘M’])]
nin 左边不存在于右边
size (数组或字符串)长度
empty (数组或字符串)为空



6.实践



6.1引入maven依赖

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



6.2准备json

{
 
    "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,
 
            "author": "test"
        }
    },
    "expensive": 10
}



6.3读取json

/**
 * 需要解析的json串
 */
String json = "....";
 
 
/**
 * 读取json,这样的弊端就是每次都读取json,如果仅使用一次可以这样,多次使用不推荐
 * $.store.book[*].author 获取store下的book中author属性的值
 * "$..author" 获取store中author属性的值
 */
 List<String> authorsBook = JsonPath.read(json, "$.store.book[*].author");
 List<String> authorsAll = JsonPath.read(json, "$..author");
 System.out.println("authorsBook = " + authorsBook);
 //结果:authorsBook = ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"]
 System.out.println("authorsAll = " + authorsAll);
 //结果:authorsAll = ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien", "test"]

如果仅解析一次可以直接用上面的方法,否则用一下面

/**
 * 需要解析的json串
 */
String json = "....";
 
/**
 * 获取需要解析的json多次处理
 */
Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
 
String author0 = JsonPath.read(document, "$.store.book[0].author");
System.out.println("author0 = " + author0);
//结果:author0 = Nigel Rees
String author1 = JsonPath.read(document, "$.store.book[1].author");
System.out.println("author1 = " + author1);
//结果:author1 = Evelyn Waugh



6.4返回值类型

返回值可以为List、对象及时间类型等

String testJson = "{\"date_as_long\" : 1411455611975}";
/**
 * 返回值类型是时间对象
 * 结果:date = Tue Sep 23 15:00:11 CST 2014
 */
Date date = JsonPath.parse(testJson).read("$['date_as_long']", Date.class);
System.out.println("date = " + date);
 
/**
 * 返回类型为实体对象
 * "$.store.book[0]" 获取store的book中的第一个
 * 结果:book = {category='reference', author='Nigel Rees', title='Sayings of the Century', price=8}
 */
Book book = JsonPath.parse(json).read("$.store.book[0]",Book.class);
System.out.println("book = " + book);
 
/**
 * 返回类型为List
 * "$.store.book[*].author" 获取store的book中author属性值
 * 结果:typeList = ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
 */
List<String> typeList = ctx.read("$.store.book[*].author");
System.out.println("typeList = " + typeList);



6.5断言

创建断言有三种方式



方式一

/**
 * 断言,大白话就是通过表达式筛选出自己想要的数据
 * "$.store.book[?(@.price > 10)]" 从store的book筛选出price大于10
 * 结果: [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},
 * {"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
 */
List<Map<String, Object>> expensiveBooks = JsonPath.parse(json)
        .read("$.store.book[?(@.price > 10)]");
System.out.println("expensiveBooks = " + expensiveBooks);



方式二

注意占位符? 为路径中的过滤器。 当提供多个过滤器时,它们按照占位符数量与提供的过滤器数量相匹配的顺序应用。 您可以在一个过滤器操作[?,?]中指定多个谓词占位符,这两个谓词都必须匹配。

/**
 * 过滤器器断言
 * filter(where("category").is("fiction").and("price").lte(10D) 过滤出category=fiction并且price<=10
 */
Filter one = filter(
        where("category").is("fiction").and("price").lte(10D)
);
 
Filter two = filter(
        where("category").is("fiction").and("price").lte(8D)
);
 
/**
 * 结果:result1 = [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
 */
List<Map<String, Object>> result1 =
        JsonPath.parse(json).read("$.store.book[?]", one);
System.out.println("result1 = " + result1);
 
/**
 * 结果:result2 = []
 */
List<Map<String, Object>> result2 =
        JsonPath.parse(json).read("$.store.book[?,?]", one,two);
System.out.println("result2 = " + result2);



方式三

自定义断言。
/**
 * 自定义断言
 * "$.store.book[?].isbn" 查找store的book中isbn的属性值
 * 结果:books = ["0-553-21311-3","0-395-19395-8"]
 */
Predicate booksWithISBN = new Predicate() {
    @Override
    public boolean apply(PredicateContext ctx) {
        return ctx.item(Map.class).containsKey("isbn");
    }
};
 
List<Map<String, Object>> books =
        JsonPath.parse(json).read("$.store.book[?].isbn", List.class, booksWithISBN);
System.out.println("books = " + books);



6.6改变属性值

/**
 * 改变json中的某个属性值
 */
String newJson = JsonPath.parse(json).set("$['store']['book'][0]['author']", "Paul").jsonString();
 
System.out.println("newJson = " + newJson);



6.7调整配置


DEFAULT_PATH_LEAF_TO_NULL:


此选项使JsonPath对于缺少的叶子返回nul

l


ALWAYS_RETURN_LIST:


此选项配置JsonPath返回列表


ALWAYS_RETURN_LIST:


如果选项ALWAYS_RETURN_LIST存在,将返回一个空列表


ALWAYS_RETURN_LIST:


如果选项ALWAYS_RETURN_LIST不存在返回null

String testJsonConfig = "[\n" +
        "   {\n" +
        "      \"name\" : \"john\",\n" +
        "      \"gender\" : \"male\"\n" +
        "   },\n" +
        "   {\n" +
        "      \"name\" : \"ben\"\n" +
        "   }\n" +
        "]";
Configuration conf = Configuration.defaultConfiguration();
 
//结果:gender0 = male
//String gender0 = JsonPath.using(conf).parse(testJsonConfig).read("$[0]['gender']");
//System.out.println("gender0 = " + gender0);
//结果:抛PathNotFoundException
//String gender1 = JsonPath.using(conf).parse(testJsonConfig).read("$[1]['gender']");
//System.out.println("gender1 = " + gender1);
 
Configuration conf2 = conf.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
 
//结果:gender0 = male
String gender0 = JsonPath.using(conf2).parse(testJsonConfig).read("$[0]['gender']");
System.out.println("gender0 = " + gender0);
//结果:gender1 = null
String gender1 = JsonPath.using(conf2).parse(testJsonConfig).read("$[1]['gender']");
System.out.println("gender1 = " + gender1);



6.8其他写法

//The first two books:获取json中book数组的第1和第2两个个值
List<Object> authors6 = JsonPath.read(json, "$..book[0,1]");
 
//All books from index 0 (inclusive) until index 2 (exclusive):获取json中book数组的前两个区间值
List<Object> authors7 = JsonPath.read(json, "$..book[:2]");
 
//All books from index 1 (inclusive) until index 2 (exclusive):获取json中book数组的第2个值
List<Object> authors8 = JsonPath.read(json, "$..book[1:2]");
 
//Last two books:获取json中book数组的最后两个值
List<Object> authors9 = JsonPath.read(json, "$..book[-2:]");
 
//Book number two from tail:获取json中book数组的第3个到最后一个的区间值
List<Object> authors10 = JsonPath.read(json, "$..book[2:]");
 
//All books in store that are not "expensive":获取json中book数组中price<=expensive的所有值
List<Object> authors13 = JsonPath.read(json, "$..book[?(@.price <= $['expensive'])]");
 
//All books matching regex (ignore case):获取json中book数组中的作者以REES结尾的所有值(REES不区分大小写)
List<Object> authors14 = JsonPath.read(json, "$..book[?(@.author =~ /.*REES/i)]");
 
//The number of books:获取json中book数组的长度
List<Object> authors16 = JsonPath.read(json, "$..book.length()");



版权声明:本文为weixin_44150794原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。