<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺談JsonPath

          共 22007字,需瀏覽 45分鐘

           ·

          2022-11-21 12:59

          JsonPath,類似于XPath在XML中的作用。其提供了對Json格式數(shù)據(jù)的解析能力

          abstract.png

          操作符

          $

          查詢的根節(jié)點(diǎn),其中根節(jié)點(diǎn)可以是數(shù)組或?qū)ο?/p>

          figure 1.jpeg

          .或 ['name']

          在JsonPath表達(dá)式可以使用點(diǎn)語法、括號語法來訪問子節(jié)點(diǎn)

          figure 2.jpeg

          ..

          可進(jìn)行遞歸搜索

          figure 3.jpeg

          ['name'(, 'name')]

          對于括號語法而言,其還支持訪問多個子節(jié)點(diǎn)

          figure 4.jpeg

          [(,)]

          針對數(shù)組元素的索引操作符,其中0為起始索引。負(fù)數(shù)索引表示數(shù)組中倒數(shù)第幾個元素,例如,-1表示倒數(shù)第一個元素,-2表示倒數(shù)第2個元素

          figure 5.jpeg

          [start:end]

          針對數(shù)組元素的切片操作符,其表示獲取索引在[start,end)區(qū)間范圍的元素。顯然這里是左閉右開區(qū)間

          figure 6.jpeg

          特別地,當(dāng)start省略時,默認(rèn)為0;當(dāng)end省略時,則可以獲取數(shù)組中剩余部分的全部元素。但二者不可同時省略

          figure 7.jpeg

          此外,在切片操作符中同樣支持負(fù)數(shù)索引

          figure 8.jpeg

          *

          通配符,在任何需要名稱、數(shù)字的地方都可以使用

          figure 9.jpeg

          @

          用于下文所述過濾器表達(dá)式當(dāng)中,用于指代過濾器當(dāng)前正在處理的節(jié)點(diǎn)對象。其效果類似于Java中的this關(guān)鍵字

          [?()]

          過濾器表達(dá)式,表達(dá)式結(jié)果必須是布爾值。下圖即是一個典型的使用過濾器對數(shù)組元素進(jìn)行過濾的示例

          figure 10.jpeg

          其中過濾器支持地操作符,常見地有:

          • 「==」 :判斷是否相等
          • 「!=」 :判斷是否不相等
          • 「<」 :判斷是否小于
          • 「<=」 :判斷是否小于等于
          • 「>」 :判斷是否大于
          • 「>=」 :判斷是否大于等于
          • 「=~」 :判斷左側(cè) 是否 匹配右側(cè)的正則。例如:[? (@.age =~ /\d+/)]
          • 「in」 :判斷左側(cè) 是否 存在于 右側(cè)的集合中。例如:[? (@.size in ['S','M','L'])]
          • 「nin」 :判斷左側(cè) 是否 不存在于 右側(cè)的集合中。例如:[? (@.size nin ['S','M','L'])]
          • 「subsetof」 :判斷左側(cè) 是否為 右側(cè)集合的子集。例如:[? (@.sizes subsetof ['S','M','L'])]
          • 「anyof」 :判斷左側(cè) 是否與 右側(cè)集合 存在交集。例如:[? (@.sizes anyof ['S','M','L'])]
          • 「noneof」 :判斷左側(cè) 是否與 右側(cè)集合 無交集。例如:[? (@.sizes noneof ['S','M','L'])]
          • 「size」 :判斷左側(cè) 數(shù)組長度 或 字符串長度 是否為 指定值。例如:[? (@.name size 3)]

          此外對于部分而言,還可以使用邏輯運(yùn)算符:&&與、||或、!非。以此構(gòu)建更復(fù)雜的表達(dá)式

          figure 11.jpeg

          基于Java的實(shí)踐——Jayway JsonPath

          Jayway JsonPath則提供了Java版本的實(shí)現(xiàn),方便開發(fā)者進(jìn)行集成使用。只需引入下述依賴即可

          <!--Json Path-->
          <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <version>2.7.0</version>
          </dependency>

          為了便于后續(xù)行文演示方便,這里準(zhǔn)備了一個較為復(fù)雜的Json數(shù)據(jù)

          {
              "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
                  },
                  "clothes":[
                      {
                          "name":"牛仔褲",
                          "sizes":"S",
                          "price":94
                      },
                      {
                          "name":"背心",
                          "sizes":"M",
                          "price":48
                      },
                      {
                          "name":"裙子",
                          "sizes":["S""M"],
                          "price":1.24
                      },
                      {
                          "name":"羊毛衫",
                          "sizes":["XS""XL"],
                          "price":78.99
                      },
                      {
                          "name":"Polo衫",
                          "sizes":["XS""XL""M"],
                          "price":18.99
                      }
                  ]
              },
              "expensive":10
          }

          快速入門

          Jayway JsonPath 非常方便,開箱即用

          public class Demo1 {

              private String 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},\"clothes\":[{\"name\":\"牛仔褲\",\"sizes\":\"S\",\"price\":94},{\"name\":\"背心\",\"sizes\":\"M\",\"price\":48},{\"name\":\"裙子\",\"sizes\":[\"S\",\"M\"],\"price\":1.24},{\"name\":\"羊毛衫\",\"sizes\":[\"XS\",\"XL\"],\"price\":78.99},{\"name\":\"Polo衫\",\"sizes\":[\"XS\",\"M\",\"XL\"],\"price\":18.99}]},\"expensive\":10}\n";

              /**
               * 每次讀取時均會解析
               */

              @Test
              public void start1() {
                  List<String> authors = JsonPath.read(json, "$.store.book[*].author");
                  System.out.println("authors :" + authors);
              }

              /**
               * 多次讀取路徑時, 避免重復(fù)解析
               */

              @Test
              public void start2() {
                  Object document = Configuration.defaultConfiguration()
                          .jsonProvider()
                          .parse(json);

                  List<String> prices = JsonPath.read(document, "$.store.book[*].price");
                  List<String> names = JsonPath.read(document, "$.store.clothes[*].name");

                  System.out.println("prices :" + prices);
                  System.out.println("names :" + names);
              }

          }

          其中,start1的方式適用于僅僅需要讀取1次數(shù)據(jù);而start2則通過先解析后讀取的方式,適用于多次讀取的場景。避免start1方式重復(fù)解析帶來損耗

          figure 12.jpeg

          反序列化

          在Jayway JsonPath中提供了多種JsonProvider,其中默認(rèn)的為JsonSmartJsonProvider。這里我們期望能夠直接對讀取的數(shù)據(jù)進(jìn)行反序列化,這里我們選用JacksonJsonProvider,此時要求jackson-databind依賴的版本至少為2.4.5。故這里我們先添加Jackson依賴

          <!--Jackson-->
          <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.7</version>
          </dependency>

          Demo如下所示

          import com.jayway.jsonpath.Configuration;
          import com.jayway.jsonpath.JsonPath;
          import com.jayway.jsonpath.ReadContext;
          import com.jayway.jsonpath.TypeRef;
          import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;

          public class Demo1 {

              private String 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},\"clothes\":[{\"name\":\"牛仔褲\",\"sizes\":\"S\",\"price\":94},{\"name\":\"背心\",\"sizes\":\"M\",\"price\":48},{\"name\":\"裙子\",\"sizes\":[\"S\",\"M\"],\"price\":1.24},{\"name\":\"羊毛衫\",\"sizes\":[\"XS\",\"XL\"],\"price\":78.99},{\"name\":\"Polo衫\",\"sizes\":[\"XS\",\"M\",\"XL\"],\"price\":18.99}]},\"expensive\":10}\n";

              @Test
              public void start3() {
                  // 使用 JacksonJsonProvider 實(shí)現(xiàn)反序列化
                  Configuration conf = Configuration
                          .builder()
                          .mappingProvider( new JacksonMappingProvider() )
                          .build();

                  ReadContext ctx = JsonPath.using( conf )
                          .parse(json);

                  TypeRef<List<Book>> typeRef = new TypeRef<List<Book>>() {};
                  List<Book> books = ctx.read("$.store.book[*]", typeRef);

                  books.forEach( System.out::println );
              }

          }

          @AllArgsConstructor
          @NoArgsConstructor
          @Builder
          @Data
          class Book {
              private String category;

              private String title;

              private String author;

              private Double price;

              private String isbn;
          }

          效果如下所示

          figure 13.jpeg

          過濾器謂詞

          前面提到JsonPath中支持過濾器表達(dá)式,為此在Jayway JsonPath中提供了相應(yīng)的謂詞過濾器。具體地,我們可以使用內(nèi)聯(lián)謂詞、Filter謂詞、自定義謂詞3種方式進(jìn)行實(shí)踐。其中對于Filter謂詞、自定義謂詞而言,需要在jsonpath字符串中使用占位符?來代替所傳遞的過濾器謂詞。如果jsonpath字符串中使用多個占位符?,則應(yīng)按相應(yīng)順序傳入過濾器謂詞參數(shù)

          import com.jayway.jsonpath.*;
          import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
          import static com.jayway.jsonpath.Criteria.where;
          import static com.jayway.jsonpath.Filter.filter;

          public class Demo2 {

              private String 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},\"clothes\":[{\"name\":\"牛仔褲\",\"sizes\":\"S\",\"price\":94},{\"name\":\"背心\",\"sizes\":\"M\",\"price\":48},{\"name\":\"裙子\",\"sizes\":[\"S\",\"M\"],\"price\":1.24},{\"name\":\"羊毛衫\",\"sizes\":[\"XS\",\"XL\"],\"price\":78.99},{\"name\":\"Polo衫\",\"sizes\":[\"XS\",\"M\",\"XL\"],\"price\":18.99}]},\"expensive\":10}\n";

              /**
               * Predicate Filter 謂詞過濾器
               */

              @Test
              public void usePredicateFilter() {
                  // 使用 JacksonJsonProvider 實(shí)現(xiàn)反序列化
                  Configuration conf = Configuration
                          .builder()
                          .mappingProvider( new JacksonMappingProvider() )
                          .build();
                  ReadContext ctx = JsonPath.using( conf )
                          .parse(json);
                  
                  // 方式1 : 內(nèi)聯(lián)謂詞
                  TypeRef<List<Clothes>> typeRef = new TypeRef<List<Clothes>>() {};
                  List<Clothes> clothes1 = ctx.read("$.store.clothes[?( @.price>50 || @.sizes anyof ['M'] ) ]", typeRef);
                  System.out.println("-------------- clothes1 ---------------");
                  clothes1.forEach( System.out::println );

                  // 方式2 : Filter謂詞
                  Filter filter = filter( where("price").gt(50) )
                      .or( where("sizes").anyof( Arrays.asList("M") ) );
                  // 使用謂詞的占位符?
                  Clothes[] clothes2 = ctx.read("$.store.clothes[?]", Clothes[].classfilter);
                  System.out.println("-------------- clothes2 ---------------");
                  for (Clothes clothes : clothes2) {
                      System.out.println(clothes);
                  }

                  // 方式3 : 自定義謂詞
                  Predicate rule = ctx1 -> {
                       Map map = ctx1.item( Map.class );
                       boolean b1 = false;
                       Object priceObj =  map.getOrDefault("price",null);
                       if( priceObj!=null ) {
                           String priceStr = priceObj.toString();
                           Double price = 0d;
                           try {
                               price = Double.parseDouble( priceStr );
                           } catch (Exception e) {
                           }
                           b1 = price > 50d;
                       }

                       boolean b2 = false;
                       Object sizes = map.getOrDefault("sizes"null);
                       if( sizes!=null && sizes instanceof List ) {
                           List<String> sizeList = (List<String>) sizes;
                           List<String> targetList = Arrays.asList("M");
                           for (String size : sizeList) {
                               if( targetList.contains(size) ) {
                                   b2 = true;
                                   break;
                               }
                           }
                       }

                       return b1 || b2;
                  };

                  // 使用謂詞的占位符?
                  Clothes[] clothes3 = ctx.read("$.store.clothes[?]", Clothes[].classrule);
                  System.out.println("-------------- clothes3 ---------------");
                  for (Clothes clothes : clothes3) {
                      System.out.println(clothes);
                  }
              }
          }

          @AllArgsConstructor
          @NoArgsConstructor
          @Builder
          @Data
          class Clothes {
              private String name;

              private Double price;

              private Object sizes;
          }

          效果如下所示

          figure 14.jpeg

          瀏覽 94
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷婷久久婷婷 | 操逼国产高清无码 | av无码中文字幕 www.久久99 | 好看的印度三色电费 | 五月丁香久久婷婷 |