当前位置: 移动技术网 > IT编程>开发语言>Java > JsonPath操作JSON

JsonPath操作JSON

2020年07月22日  | 移动技术网IT编程  | 我要评论

引言

假设想要解析JSON对象且JSON的格式不固定,最开始的做法是转换Json对象为Map对象,然后一层层遍历Map(例如使用Gson),那么有没有类似XML中的xpath解析表达式的工具?最终发现了json-path工具。
参考链接:github json-path
Maven依赖:

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

该工具提供了类似XPATH的层级似的JSON解析功能,同时提供读取、写入的功能。

JsonPath语法

Operators

Operator Description
$ The root element to query. This starts all path expressions.
@ The current node being processed by a filter predicate.
* Wildcard. Available anywhere a name or numeric are required.
.. Deep scan. Available anywhere a name is required.
.<name> Dot-notated child
['<name>' (, '<name>')] Bracket-notated child or children
[<number> (, <number>)] Array index or indexes
[start:end] Array slice operator
[?(<expression>)] Filter expression. Expression must evaluate to a boolean value.

Functions

Functions can be invoked at the tail end of a path - the input to a function is the output of the path expression.
The function output is dictated by the function itself.

Function Description Output
min() Provides the min value of an array of numbers Double
max() Provides the max value of an array of numbers Double
avg() Provides the average value of an array of numbers Double
stddev() Provides the standard deviation value of an array of numbers Double
length() Provides the length of an array Integer
sum() Provides the sum value of an array of numbers Double

Filter Operators

Filters are logical expressions used to filter arrays. A typical filter would be [?(@.age > 18)] where @ represents the current item being processed. More complex filters can be created with logical operators && and ||. String literals must be enclosed by single or double quotes ([?(@.color == ‘blue’)] or [?(@.color == “blue”)]).

Operator Description
== left is equal to right (note that 1 is not equal to '1')
!= left is not equal to right
< left is less than right
<= left is less or equal to right
> left is greater than right
>= left is greater than or equal to right
=~ left matches regular expression [?(@.name =~ /foo.*?/i)]
in left exists in right [?(@.size in ['S', 'M'])]
nin left does not exists in right
subsetof left is a subset of right [?(@.sizes subsetof ['S', 'M', 'L'])]
anyof left has an intersection with right [?(@.sizes anyof ['M', 'L'])]
noneof left has no intersection with right [?(@.sizes noneof ['M', 'L'])]
size size of left (array or string) should match right
empty left (array or string) should be empty

JsonPath语法示例

Given the 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
        }
    },
    "expensive": 10
}

JsonPath Result
$.store.book[*].author] The authors of all books
$..author All authors
$.store.* All things, both books and bicycles
$.store..price The price of everything
$..book[2] The third book
$..book[-2] The second to last book
$..book[0,1] The first two books
$..book[:2] All books from index 0 (inclusive) until index 2 (exclusive)
$..book[1:2] All books from index 1 (inclusive) until index 2 (exclusive)
$..book[-2:] Last two books
$..book[2:] Book number two from tail
$..book[?(@.isbn)] All books with an ISBN number
$.store.book[?(@.price < 10)] All books in store cheaper than 10
$..book[?(@.price <= $['expensive'])] All books in store that are not "expensive"
$..book[?(@.author =~ /.*REES/i)] All books matching regex (ignore case)
$..* Give me every thing
$..book.length()/td> The number of books

JsonPath代码示例

解析并修改如下JSON(示例为Istio中的某个VirtualService定义):

{
  "kind": "VirtualService",
  "apiVersion": "networking.istio.io/v1alpha3",
  "metadata": {
    "name": "my-svc",
    "namespace": "tsp"
  },
  "spec": {
    "hosts": [
      "s106.tsp.svc.cluster.local",
      "my-svc.tsp.svc.cluster.local"
    ],
    "gateways": [
      "mesh",
      "my-svc"
    ],
    "http": [
      {
        "match": [
          {
            "headers": {
              "user-id": {
                "regex": "11|22|33"
              }
            },
            "uri": {
              "prefix": "/256"
            }
          }
        ],
        "rewrite": {
          "uri": "/my_svc"
        },
        "route": [
          {
            "destination": {
              "host": "s106.tsp.svc.cluster.local",
              "subset": "v257"
            }
          }
        ]
      },
      {
        "match": [
          {
            "uri": {
              "prefix": "/256"
            }
          }
        ],
        "rewrite": {
          "uri": "/my_svc"
        },
        "route": [
          {
            "destination": {
              "host": "s106.tsp.svc.cluster.local",
              "subset": "v256"
            }
          }
        ]
      },
      {
        "route": [
          {
            "destination": {
              "host": "s106.tsp.svc.cluster.local",
              "subset": "v256"
            }
          }
        ]
      }
    ],
    "tcp": null,
    "tls": null
  }
}
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.JsonPath;
import com.svc.mgt.utils.JsonUtils;
import net.minidev.json.JSONArray;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;

import java.util.Map;

import static com.jayway.jsonpath.Criteria.where;
import static com.jayway.jsonpath.Filter.filter;

/**
 * K8s查询结果Json转换 - 测试
 *
 * @Ahthor luohq
 * @Date 2020-07-20
 */

@RunWith(PowerMockRunner.class)  //使用PowerMockRunner运行时
@PowerMockIgnore({"javax.management.*"}) //忽略一些mock异常
public class K8sJsonResultTest {
    private static final Logger logger = LogManager.getLogger(K8sJsonResultTest.class);
    @Test
    public void testVsJson() {
        String vsResult = "...";
        /** JsonPath解析 */
        final DocumentContext ctx = JsonPath.parse(vsResult);
        
        /** 基础路由过滤器 - 包含http[].match 且 不包含有http[].match[0].headers*/
        Filter baseRouteFilter = filter(
                where("$.match").exists(true).and("$.match[0].headers").exists(false)
        );

        /** 读取属性(指定过滤器)*/
        JSONArray httpRoutes = ctx.read("$.spec.http[?]*", baseRouteFilter);
        for (Object httpRoute : httpRoutes) {
            String subset = JsonPath.read(httpRoute, "$.route[0].destination.subset");
            logger.info("baseRoute -> subset={}, httpRoute={}", subset, JsonPath.parse(httpRoute).jsonString());
        }
        /** 读取属性 */
        Map httpRouteObj = ctx.read("$.spec.http[0]");
        
        //替换user-id | product-id
        String headersJson = String.format("{\"user-id\": {\"regex\": \"%s\"},\"product-id\": {\"exact\":\"%s\"}}", "111|222", "12342");
        /** 设置属性 - 重置baseRoute中的match.headers(add添加数组元素、set设置属性、put新增或修改属性) */
        JsonPath.parse(httpRouteObj).put("$.match[0]", "headers", JsonUtils.fromJson(headersJson, Map.class));
        logger.info("svcRouteRule: {}", JsonPath.parse(httpRouteObj).jsonString());
        logger.info("vs.ctx={}", ctx.jsonString());

        /** 删除对象 - 清空 $.spec.http数组 */
        ctx.delete("$.spec.http.*");
        logger.info("vs.ctx={}", ctx.jsonString());

    }
    
}

运行结果:

2020-07-21 14:49:39.389 INFO [main][K8sJsonResultTest.java:146] - baseRoute -> subset=v256, httpRoute={"match":[{"uri":{"prefix":"/256"}}],"rewrite":{"uri":"/mx_tour_app"},"route":[{"destination":{"host":"s106.tsp.svc.cluster.local","subset":"v256"}}]}
2020-07-21 14:49:39.488 INFO [main][K8sJsonResultTest.java:154] - svcRouteRule: {"match":[{"headers":{"user-id":{"regex":"111|222"},"product-id":{"exact":"12342"}},"uri":{"prefix":"/256"}}],"rewrite":{"uri":"/mx_tour_app"},"route":[{"destination":{"host":"s106.tsp.svc.cluster.local","subset":"v257"}}]}
2020-07-21 14:49:39.488 INFO [main][K8sJsonResultTest.java:155] - vs.ctx={"kind":"VirtualService","apiVersion":"networking.istio.io/v1alpha3","metadata":{"name":"my-app","namespace":"tsp","selfLink":"/apis/networking.istio.io/v1alpha3/namespaces/tsp/virtualservices/my-app","uid":"368f02de-ac7b-11ea-b7d7-fa163e432d7e","resourceVersion":"194978865","generation":11,"creationTimestamp":"2020-06-12T07:06:18Z"},"spec":{"hosts":["s106.tsp.svc.cluster.local","my-app.tsp.svc.cluster.local","my-app-pre.xxxx.com"],"gateways":["mesh","my-app"],"http":[{"match":[{"headers":{"user-id":{"regex":"111|222"},"product-id":{"exact":"12342"}},"uri":{"prefix":"/256"}}],"rewrite":{"uri":"/mx_tour_app"},"route":[{"destination":{"host":"s106.tsp.svc.cluster.local","subset":"v257"}}]},{"match":[{"uri":{"prefix":"/256"}}],"rewrite":{"uri":"/mx_tour_app"},"route":[{"destination":{"host":"s106.tsp.svc.cluster.local","subset":"v256"}}]},{"route":[{"destination":{"host":"s106.tsp.svc.cluster.local","subset":"v256"}}]}],"tcp":null,"tls":null}}
2020-07-21 14:49:39.489 INFO [main][K8sJsonResultTest.java:160] - vs.ctx={"kind":"VirtualService","apiVersion":"networking.istio.io/v1alpha3","metadata":{"name":"my-app","namespace":"tsp","selfLink":"/apis/networking.istio.io/v1alpha3/namespaces/tsp/virtualservices/my-app","uid":"368f02de-ac7b-11ea-b7d7-fa163e432d7e","resourceVersion":"194978865","generation":11,"creationTimestamp":"2020-06-12T07:06:18Z"},"spec":{"hosts":["s106.tsp.svc.cluster.local","my-app.tsp.svc.cluster.local","my-app-pre.xxxx.com"],"gateways":["mesh","my-app"],"http":[],"tcp":null,"tls":null}}

本文地址:https://blog.csdn.net/luo15242208310/article/details/107487627

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网