使用JsonPath提取JSON的例子

1,070 阅读3分钟

学习使用Jayway的JsonPath从JSON文档中提取信息。JsonPath类似于XML文档的Xpath。本教程将通过JsonPath的语法和一些例子来更好地理解它的用法。

目录

  1. 1.设置JsonPath
  2. 2.一个简单的例子
  3. 3.JsonPath 语法
  4. 4.JsonPath谓词
  5. 5.自定义配置
  6. 6.结语

1.设置JsonPath

如果没有加入JsonPath,请将其加入到应用程序中。我们可以在Maven资源库中找到JsonPath的最新版本

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

通常情况下,我们会从API响应或应用程序中的任何其他来源获取JSON文档。但在这个例子中,我们是在读取JSON文件

{
  "widget": {
    "debug": "on",
    "window": {
      "title": "Client Info",
      "name": "client_info",
      "width": 500,
      "height": 500,
      "padding": [10,10,10,50],
      "locations" : [
        { "name": "header", "display": "true" },
        { "name": "footer", "display": "true" },
        { "name": "sidebar", "display": "false" }
      ]
    }
  }
}

如果我们要写一个Junit测试,我们可以在setup()方法中把JSON读成一个字符串

static String json;

@BeforeAll
public static void setup() {
  try {
    URL fileUrl = TestJsonPathExpressions.class.getClassLoader().getResource("widget.json");
    File file = new File(fileUrl.getFile());
    json = new String(Files.readAllBytes(file.toPath()));
  } catch (Exception e) {
    e.printStackTrace();
  }
}

2.一个简单的例子

在深入研究语法之前,让我们从一个简单的例子开始,看看如何从给定文件中提取信息。在下面的例子中,我们提取widget的标题名称,并验证其预期值。

@Test
public void testGetWidgetTitle_ThenSuccess(){

  String widgetTitle = JsonPath.read(json, "$.widget.window.title");
  Assertions.assertEquals("Client Info", widgetTitle);
}

3.JsonPath 语法

3.1.符号

JsonPath支持两种表示节点的符号:点和括号。在下面的例子中,两个表达式都指向同一个节点

  • $.widget.window.title //圆点符号
  • $['widget']['window']['title'] //括号表示法

3.2.操作符

JsonPath支持许多操作符,可以用来表示JSON文档中的特定节点或范围。

  • $ 代表根节点。所有的路径表达式都以它开始。
  • @ 代表当前正在处理的节点。它与一个过滤器谓词一起使用。在下面的例子中,我们要找到所有显示为true的位置
@Test
public void testGetDisplayLocations_ThenSuccess(){

  List<String> locations = JsonPath.read(json, "$.widget.window.locations[?(@.display == 'true')].name");
  Assertions.assertTrue(List.of("header", "footer").containsAll(locations));
}
  • * 代表当前范围内的所有节点。例如,下面的表达式返回所有的位置,而不考虑显示属性。
@Test
public void testGetAllDisplayLocations_ThenSuccess(){

  List<String> locations = JsonPath.read(json, "$.widget.window.locations[*].name");
  Assertions.assertTrue(List.of("header", "footer", "sidebar").containsAll(locations));
}
  • [start:end] 将数组中的元素起点索引切到终点索引。
@Test
public void testFirstDisplayLocation_ThenSuccess(){

  List<String> locations = JsonPath.read(json, "$.widget.window.locations[0,1].name");
  Assertions.assertTrue(List.of("header", "footer").containsAll(locations));
}

3.3.函数

JsonPath提供了内置的函数来支持一些常见的操作,如:sum(),min(),max(),avg(),stddev(),length(),keys(),concat(input)和append(input)。

在下面的例子中,我们要为小组件找到最大的padding值。

@Test
public void testLargestPadding_ThenSuccess(){

  Double largestPadding = JsonPath.read(json, "$.widget.window.padding.max()");
  Assertions.assertEquals(50, largestPadding);
}

4.JsonPath谓词

谓词有助于根据提供的条件过滤一个数组的节点。当我们想只提取那些符合特定标准的数组项目时,这很有用。

我们已经在上一节中看到了内联谓词的例子。

List<String> locations = JsonPath.read(json, "$.widget.window.locations[?(@.display == 'true')].name");

让我们用com.jayway.jsonpath.Predicate 类重写同一个谓词。注意在*'location[?]'*中使用了? 字符,暗示了要应用的谓词的位置。

@Test
public void testGetTrueDisplayLocationsWithPredicate_ThenSuccess(){

  Predicate displayEnabled = new Predicate() {
    @Override
    public boolean apply(PredicateContext ctx) {
      return ctx.item(Map.class).get("display").toString().equalsIgnoreCase("true");
    }
  };

  List<String> locations = JsonPath.read(json, "$.widget.window.locations[?].name", displayEnabled);
  Assertions.assertTrue(List.of("header", "footer").containsAll(locations));
}

注意,我们可以在一个表达式中传递多个谓词和占位符。当提供多个谓词时,它们将按顺序应用,其中占位符的数量必须与提供的谓词的数量相匹配。在下面的例子中,我们要传递两个谓词widgetEnableddisplayEnabled

JsonPath.read(json, "$.widget.window[?].locations[?].name", widgetEnabled, displayEnabled);

5.自定义配置

JsonPathOption 枚举提供了几个选项来定制默认配置。

  • Option.AS_PATH_LIST返回评价路径而不是值。
  • Option.DEFAULT_PATH_LEAF_TO_NULL为缺少的节点返回null
  • Option.ALWAYS_RETURN_LIST 即使表达式评估的是一个值,也会返回一个List
  • Option.SUPPRESS_EXCEPTIONS在运行时抑制所有异常。
  • Option.REQUIRE_PROPERTIES在评估不确定的路径时,需要路径中定义的属性。

要将配置传递给JsonPath对象,请使用其using() 方法。在下面的例子中,我们正在获取一个单一的值,但它被作为一个列表返回。

@Test
public void testConfiguration_ThenSuccess(){

  Configuration configuration = Configuration
      .builder()
      .options(ALWAYS_RETURN_LIST, SUPPRESS_EXCEPTIONS)
      .build();

  List<String> locations = JsonPath
      .using(configuration)
      .parse(json).read("$.widget.window.locations[0].name");
  Assertions.assertTrue(List.of("header").containsAll(locations));
}

6.结语

在这个JsonPath教程中,我们学会了根据我们的需要来设置和配置JsonPath。我们学习了JsonPath的语法,包括记号、符号和运算符的例子。我们还经历了几个例子,通过使用谓词的过滤器从JSON文档中提取信息。

学习愉快!!

源代码在Github上

这个帖子有帮助吗?

如果你喜欢这篇文章,请告诉我们。这是我们改进的唯一方法。

没有

相关帖子。

  1. JSON.simple - 读取和写入JSON
  2. REST-assured HTTP POST和PUT实例
  3. Python JSON - 读取一个JSON文件
  4. Python JSON - 读取一个JSON字符串
  5. Python JSON--将JSON追加到文件中
  6. Python JSON--自定义类的序列化