Rostislav Titov
Rostislav Titov

Reputation: 31

How to search an array using JSONPath in Java?

I'd like to write a unit test for a web service using json-path-assert. Given this JSON:

[ 
  ["Some short name","Some parent","Some name"],
  ["Some short name 2","Some parent 2","Some name 2"] 
]

I'd like to check that the parent of "Some name 2" is "Some parent 2". I cannot change the structure of JSON since it is dictated by a third-party library.

Here's the JSONPath expression I came up with:

$..[?(@[2] == 'Some name 2')][1]

This expression works fine and gives returns the expected result ('Some parent 2') in this JSON tool. However when using it in Java using the JSONPath library I get an empty result instead of the correct value:

import com.jayway.jsonpath.JsonPath;
import org.junit.Test;

public class TestJSONPath
{
  @Test
  public void testJsonPath() {
     String json = "[[\"Some short name\",\"Some parent\",\"Some name\"]," +
       "[\"Some short name 2\",\"Some parent 2\",\"Some name 2\"]]";

     System.out.println(JsonPath.read(json, "$[1][1]"));    // OK, returns 'Some parent 2'
     System.out.println(JsonPath.read(json, "$..[?(@[2] == 'Some name 2')][1]")); // Not OK, returns an empty list
 }
}

Here's my 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>test</groupId>
  <artifactId>test</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.jayway.jsonpath</groupId>
      <artifactId>json-path</artifactId>
      <version>2.1.0</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.jayway.jsonpath</groupId>
      <artifactId>json-path-assert</artifactId>
      <version>2.1.0</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Could you please help me with ideas how to overcome this issue?

Upvotes: 2

Views: 26223

Answers (1)

Meiko Rachimow
Meiko Rachimow

Reputation: 4724

This could work: $[?(@[2] == 'Some name 2')][1]

Background:

If you try the "original" JSONPath implementation written by Stefan Goessner, the following expression returns the expected array:

$..[?(@[2] == 'Some name 2')] (a descendant where value at index 2 is 'Some name 2')

===> ["Some parent 2"]

It is interesting... try these expressions with jayway, Goessners-JSON-lib or jsonquerytool :

"$..*" //list of all descendants (both child-arrays + elements in arrays)
"$.*" //list of all direct children (both child arrays)
"$" //actual element (the array itself)

Stefan Goessner's JavaScript library returns the same as the "jayway" implementation. But "jsonquerytool" gives false for $ - which is definitively wrong. $ is "the root object/element".

And for $..* this is the same result with all three implementations:

[
    [
        "Some short name",
        "Some parent",
        "Some name"
    ],
    [
        "Some short name 2",
        "Some parent 2",
        "Some name 2"
    ],
    "Some short name",
    "Some parent",
    "Some name",
    "Some short name 2",
    "Some parent 2",
    "Some name 2"
]

So $..[?(@[2] == 'Some name 2')] should match the array at index '1'... in my opinion, jayway is doing it wrong.

With JSONPath square brackets operate on the object or array addressed by the previous path fragment. (see http://goessner.net/articles/JsonPath/)

Goessner is the inventor of JSONPath - so his implementation is doing it the right way!!! 😎 summary: jsonquerytool's and jayway's implementations are wrong.

Surprisingly this query is working as expected in all implementations (although $ is false in jsonquerytool)

$[?(@[2] == 'Some name 2')][1]

also this version works:

$.[?(@[2] == 'Some name 2')][1]

Upvotes: 5

Related Questions