Reputation: 31
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
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