zoukankan      html  css  js  c++  java
  • 基于java对jsonpath的初步学习

    1. 介绍

    类似于XPath在xml文档中的定位,JsonPath表达式通常是用来路径检索或设置Json的。

    2. 语法(操作符)

    操作员 描述
    $ 要查询的根元素。用于表示一个json数据,可以是数组或对象
    @ 过滤器断言(filter predicate)处理的当前节点对象,类似于java中的this字段
    * 通配符,可以表示一个名字或数字
    .. 可以理解为递归搜索,深层扫描。可在任何需要名称的地方使用。
    .<name> 表示一个子节点
    ['<name>' (, '<name>')] 表示一个或多个子节点
    [<number> (, <number>)] 表示一个或多个数组下标
    [start:end] 数组片段,区间为[start,end),不包含end
    [?(<expression>)] 过滤表达式。表达式必须计算为布尔值。

    2. 语法(函数)

    可以在JsonPath表达式执行后进行调用,其输入值为表达式的结果。

    功能 描述 输出量
    min() 提供数值类型数组的最小值 Double
    max() 提供数值类型数组的最大值 Double
    avg() 提供数值类型数组的平均值 Double
    stddev() 提供数值类型数组的标准偏差值 Double
    length() 提供数值类型数组的长度 Integer
    sum() 提供数值类型数组的总和 Double

    2. 语法(过滤器)

    过滤器是用于过滤数组的逻辑表达式,一个通常的表达式形如:[?(@.age > 18)],可以通过逻辑表达式&&或||组合多个过滤器表达式,例如[?(@.price < 10 && @.category == ‘fiction’)],字符串必须用单引号或双引号包围,例如[?(@.color == ‘blue’)] or [?(@.color == “blue”)]

    操作符 描述
    == 等于符号,但数字1不等于字符1(note that 1 is not equal to ‘1’)
    != 不等于符号
    < 小于符号
    <= 小于等于符号
    > 大于符号
    >= 大于等于符号
    =~ 判断是否符合正则表达式,例如[?(@.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 判空符号

    3. 官方示例参考

    {
        "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表达式 说明
    $.store.book[*].author 所有书籍的作者
    $..author 所有作者
    $.store.* 所有东西,包括书籍和自行车
    $.store..price 所有东西的价格
    $..book[2] 第三本书
    $..book[-2] 倒数第二本书
    $..book[0,1] 前两本书
    $..book[:2] All 从索引0(含)到索引2(不含)的图书
    $..book[1:2] 从索引1(含)到索引2(不含)的图书
    $..book[-2:] 最后两本书
    $..book[2:] 从尾数第二本书
    $..book[?(@.isbn)] 所有带有ISBN号的图书
    $.store.book[?(@.price < 10)] 商店中所有价格低于10书籍
    $..book[?(@.price <= $['expensive'])] 商店中所有非“昂贵”的图书
    $..book][?(@.author =~ /.*REES/i)] 所有与正则表达式匹配的书籍(忽略大小写)
    $..* 所有数据

    4. javaDemo 测试

    新建maven项目最终的pom.xml文件如下

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.demo</groupId>
        <artifactId>studyJsonPath</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <!--   jsonpath jar包     -->
            <dependency>
                <groupId>com.jayway.jsonpath</groupId>
                <artifactId>json-path</artifactId>
                <version>2.4.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-io</artifactId>
                <version>1.3.2</version>
            </dependency>
    
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-nop</artifactId>
                <version>1.7.2</version>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>jsonpathDemo</finalName>
            <plugins>
                <!-- java编译插件 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
    
            </plugins>
        </build>
    </project>
    

    测试用的json文件如上

    使用JsonPath的最简单,最直接的方法是通过静态readAPI。

    import com.jayway.jsonpath.JsonPath;
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
            String json = FileUtils.readFileToString(file);
    
            List<String> authors = JsonPath.read(json, "$.store.book[*].author");
            System.out.println(authors);
        }
    }
    

    如果仅是单次使用是OK的,如果是多次使用的话,为了避免每次解析json都需要调用JsonPath.read(...),你可以先解析json

    import com.jayway.jsonpath.Configuration;
    import com.jayway.jsonpath.JsonPath;
    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
            String json = FileUtils.readFileToString(file);
    
            Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
    
            String author0 = JsonPath.read(document, "$.store.book[0].author");
            String author1 = JsonPath.read(document, "$.store.book[1].author");
            System.out.println(author0);
            System.out.println(author1);
        }
    }
    

    JsonPath还提供了流式的API。这也是最灵活的一种。

    import com.jayway.jsonpath.JsonPath;
    import com.jayway.jsonpath.ReadContext;
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
            String json = FileUtils.readFileToString(file);
    
            ReadContext ctx = JsonPath.parse(json);
    
            List<String> authorsOfBooksWithISBN = ctx.read("$.store.book[?(@.isbn)].author");
            List<Map<String, Object>> expensiveBooks = JsonPath
    //                .using(configuration)
                    .parse(json)
                    .read("$.store.book[?(@.price > 10)]", List.class);
            System.out.println(authorsOfBooksWithISBN);
            System.out.println(expensiveBooks);
        }
    }
    

    默认情况下,MappingProvider SPI提供了一个简单的对象映射器。这使您可以指定所需的返回类型,并且MappingProvider将尝试执行映射。在下面的示例中,演示了Long和Date之间的映射。

    import com.jayway.jsonpath.JsonPath;
    import java.io.IOException;
    import java.util.Date;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            String json = "{"date_as_long" : 1411455611975}";
            Date date = JsonPath.parse(json).read("$['date_as_long']", Date.class);
            System.out.println(date);
        }
    }
    

    如果将JsonPath配置为使用JacksonMappingProvider或GsonMappingProvider,您甚至可以将JsonPath输出直接映射到POJO。

    先修改pom.xml,添加如下依赖

      <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.16</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.5</version>
            </dependency>
    

    新建bean文件

    import lombok.AllArgsConstructor;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author john
     * @date 2020/4/8 - 18:13
     */
    @Slf4j
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class Book {
        private String category;
        private String author;
        private String title;
        private String isbn;
        private double price;
    }
    
    

    进行测试

    import cn.demo.bean.Book;
    import com.jayway.jsonpath.Configuration;
    import com.jayway.jsonpath.JsonPath;
    import com.jayway.jsonpath.Option;
    import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
    import com.jayway.jsonpath.spi.json.JsonProvider;
    import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
    import com.jayway.jsonpath.spi.mapper.MappingProvider;
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    import java.util.EnumSet;
    import java.util.Set;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
            String json = FileUtils.readFileToString(file);
            Configuration.setDefaults(new Configuration.Defaults() {
    
                private final JsonProvider jsonProvider = new JacksonJsonNodeJsonProvider();
                private final MappingProvider mappingProvider = new JacksonMappingProvider();
    
                @Override
                public JsonProvider jsonProvider() {
                    return jsonProvider;
                }
    
                @Override
                public MappingProvider mappingProvider() {
                    return mappingProvider;
                }
    
                @Override
                public Set<Option> options() {
                    return EnumSet.noneOf(Option.class);
                }
            });
    
            Book book = JsonPath.parse(json).read("$.store.book[0]", Book.class);
            System.out.println(book);
        }
    }
    

    要获取完整的泛型类型信息,请使用TypeRef。

    import com.jayway.jsonpath.Configuration;
    import com.jayway.jsonpath.JsonPath;
    import com.jayway.jsonpath.Option;
    import com.jayway.jsonpath.TypeRef;
    import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
    import com.jayway.jsonpath.spi.json.JsonProvider;
    import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
    import com.jayway.jsonpath.spi.mapper.MappingProvider;
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    import java.util.EnumSet;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
            String json = FileUtils.readFileToString(file);
            Configuration.setDefaults(new Configuration.Defaults() {
    
                private final JsonProvider jsonProvider = new JacksonJsonNodeJsonProvider();
                private final MappingProvider mappingProvider = new JacksonMappingProvider();
    
                @Override
                public JsonProvider jsonProvider() {
                    return jsonProvider;
                }
    
                @Override
                public MappingProvider mappingProvider() {
                    return mappingProvider;
                }
    
                @Override
                public Set<Option> options() {
                    return EnumSet.noneOf(Option.class);
                }
            });
            TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {};
    
            List<String> titles = JsonPath.parse(json).read("$.store.book[*].title", typeRef);
            System.out.println(titles);
        }
    }
    

    向json中指定位置添加内容

    import com.jayway.jsonpath.DocumentContext;
    import com.jayway.jsonpath.JsonPath;
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    
    /**
     * @author john
     * @date 2020/4/8 - 17:31
     */
    public class JsonPathStudyDemo {
        public static void main(String[] args) throws IOException {
            File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
            String json = FileUtils.readFileToString(file);
            DocumentContext document = JsonPath.parse(json).put("$.store.book[*]", "kind", "paper");
    
            System.out.println(document.jsonString());
        }
    }
    

    5. 参考

    JsonPath教程

    JSONPath-简单入门

    JsonPath的用法

    jsonpath github

  • 相关阅读:
    RFID学习
    [从jQuery看JavaScript]-变量与作用域链
    Javascript中最常用的61个经典技巧[转]
    再读《被神化的框架》
    jquery动态分页
    如果你不知道这11款常见的Web应用程序框架 就说明你out了
    [从jQuery看JavaScript]-匿名函数与闭包
    [从jQuery看JavaScript]-注释(comments)
    周末大礼:jQuery技巧总结
    jQuery Form插件详解
  • 原文地址:https://www.cnblogs.com/ifme/p/12661894.html
Copyright © 2011-2022 走看看