© Jeff Friesen 2019
Jeff FriesenJava XML and JSONhttps://doi.org/10.1007/978-1-4842-4330-5_10

10. Extracting JSON Values with JsonPath

Jeff Friesen1 
(1)
Dauphin, MB, Canada
 

XPath is used to extract values from XML documents. JsonPath performs this task for JSON documents. Chapter 10 introduces you to JsonPath.

Note

If you’re unfamiliar with XPath, I recommend that you read Chapter 5 before reading this chapter. JsonPath was derived from XPath.

What Is JsonPath?

JsonPath is a declarative query language (also known as a path-expression-syntax) for selecting and extracting a JSON document’s property values. For example, you can use JsonPath to locate "John" in {"firstName": "John"} and return this value. JsonPath is based on XPath 1.0.

JsonPath was created by Stefan Goessner ( http://goessner.net ). Goessner also created JavaScript-based and PHP-based implementations of JsonPath. For complete documentation, check out Goessner’s website ( http://goessner.net/articles/JsonPath/index.html ).

Swedish software company Jayway ( www.jayway.com ) subsequently adapted JsonPath to Java. Their Java version of JsonPath is the focus of this chapter. You will find complete documentation on Jayway’s implementation of JsonPath at http://github.com/jayway/JsonPath .

Learning the JsonPath Language

JsonPath is a simple language with various features that are similar to their XPath counterparts. This language is used to construct path expressions.

A JsonPath expression begins with the dollar sign ($) character, which refers to the root element of a query. The dollar sign is followed by a sequence of child elements, which are separated via dot (.) notation or via square bracket ([]) notation. For example, consider the following JSON object:
{
   "firstName": "John",
   "lastName": "Smith",
   "age": 25,
   "address":
   {
      "streetAddress": "21 2nd Street",
      "city": "New York",
      "state": "NY",
      "postalCode": "10021-3100"
   },
   "phoneNumbers":
   [
      {
         "type": "home",
         "number": "212 555-1234"
      },
      {
         "type": "office",
         "number": "646 555-4567"
      }
   ]
}
The following dot notation-based JsonPath expression extracts, from the previous anonymous JSON object, the phone number (212 555-1234) that’s assigned to the number field in the anonymous JSON object, which is assigned to the first element in the phoneNumbers array:
$.phoneNumbers[0].number

The $ character represents the anonymous root JSON object. The leftmost dot character separates the object root from the phoneNumbers property name. The [0] syntax identifies the first element in the array assigned to phoneNumbers.

The first array element stores an anonymous object consisting of "type": "home" and "number": "212 555-1234" properties. The rightmost dot character accesses this object’s number child property name, which is assigned the value 212 555-1234. This value is returned from the expression.

Alternatively, I could specify the following square bracket notation to extract the same phone number:
$['phoneNumbers'][0]['number']
The Jayway documentation identifies $ as an operator and also identifies several other basic operators. Table 10-1 describes these operators.
Table 10-1

JsonPath Basic Operators

Operator

Description

$

The root element to query. This operator starts all path expressions. It’s equivalent to XPath’s / symbol.

@

The current node being processed by a filter predicate. It’s equivalent to XPath’s . symbol.

*

Wildcard. Available anywhere a name or numeric value is required.

..

Deep scan (also known as recursive descent). Available anywhere a name is required. It’s equivalent to XPath’s // symbol.

. name

Dot-notated child. The dot is equivalent to XPath’s / symbol.

[' name ' (, ' name ')]

Bracket-notated child or children.

[ number (, number )]

Array index or indexes.

[ start : end ]

Array slice operator.

[?( expression )]

Filter operator. The expression must evaluate to a Boolean value. In other words, it’s a predicate.

The Jayway documentation also identifies several functions that 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. Table 10-2 describes these functions.
Table 10-2

JsonPath Functions

Function

Description

min()

Return the minimum value (as a double) in an array of numbers.

max()

Return the maximum value (as a double) in an array of numbers.

avg()

Return the average value (as a double) of an array of numbers.

stddev()

Return the standard deviation value (as a double) of an array of numbers.

length()

Return the length (as an int) of an array.

Finally, the Jayway documentation identifies various operators for filters, which use predicates (Boolean expressions) to restrict returned lists of items. Predicates can use the filter operators in Table 10-3 to determine equality, match regular expressions, and test for inclusion.
Table 10-3

JsonPath Filter Operators

Operator

Description

==

Return true when the left operand equals the right operand. Note that 1 is not equal to '1' (i.e., number 1 and string 1 are two different things).

!=

Return true when the left operand doesn’t equal the right operand.

<

Return true when the left operand is less than the right operand.

<=

Return true when the left operand is less than or equal to the right operand.

>

Return true when the left operand is greater than the right operand.

>=

Return true when the left operand is greater than or equal to the right operand.

=~

Return true when the left operand matches the regular expression specified by the right operand; for example, [?(@.name =~ /foo.*?/i)].

in

Return true when the left operand exists in the right operand; for example, [?(@.grade in ['A', 'B'])].

nin

Return true when the left operand doesn’t exist in the right operand.

subsetof

Return true when the left operand (an array) is a subset of the right operand (an array); for example, [?(@.sizes subsetof ['S', 'M', 'L'])].

size

Return true when the size of the left operand (an array or string) matches the right operand (an integer).

empty

Return true when the left operand (an array or string) is empty and the right operand is true , or return true when the left operand is not empty and the right operand is false.

This table reveals @.name =~ /foo.*?/i and additional simple predicates. You can create more complex predicates by using the logical AND operator (&&) and the logical OR operator (||). Consider the following example:
([?(@.color == 'blue')] || [?(@.color == "red")])
You can also use the logical NEGATE operator (!) to negate a predicate:
[?(!(@.price < 10 && @.category == 'fiction'))]

Within a predicate, you must enclose any string literals with single or double quotes, which both examples demonstrate.

Obtaining and Using the JsonPath Library

As with Chapter 8’s mJson and Chapter 9’s Gson, you can obtain JsonPath from the Central Maven Repository ( http://search.maven.org ).

Note

If you’re unfamiliar with Maven, think of it as a build tool for Java projects, although Maven developers think of Maven as more than just a build tool—see http://maven.apache.org/background/philosophy-of-maven.html .

If you’re familiar with Maven, add the following XML fragment to the Project Object Model (POM) files for your Maven project(s) that will be dependent on JsonPath, and you will be good to go! (To learn about POM, check out http://maven.apache.org/pom.html#What_is_the_POM .)
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.4.0</version>
</dependency>

This XML fragment reveals 2.4.0 as the version of Jayway’s JsonPath library that I’m using in this chapter.

Note

It’s common for Maven projects to be dependent on other projects. For example, the mJson project ( http://search.maven.org/artifact/org.sharegov/mjson/1.4.0/bundle ) that I discussed in Chapter 8 and the Gson project ( http://search.maven.org/artifact/com.google.code.gson/gson/2.8.5/jar ) that I discussed in Chapter 9 are dependent on JUnit ( http://en.wikipedia.org/wiki/JUnit ). I didn’t mention or discuss downloading JUnit in either chapter because this library isn’t required for normal use.

Because I’m not currently using Maven, I downloaded the JsonPath JAR file and all of the JAR files on which JsonPath normally depends and then added all of these JAR files to my CLASSPATH. The easiest way for me to accomplish the download task was to point my browser to https://jar-download.com/artifacts/com.jayway.jsonpath/json-path/2.4.0/source-code and click the “Download json-path (2.4.0)” button link.

After unarchiving the ZIP file, I discovered a jar_files directory with the following files:
  • accessors-smart-1.2.jar

  • asm-5.0.4.jar

  • json-path-2.4.0.jar

  • json-smart-2.3.jar

  • slf4j-api-1.7.25.jar

Note

Jayway JsonPath is licensed according to Apache License Version 2.0 ( www.apache.org/licenses/ ).

For compiling Java source code that accesses JsonPath, only json-path-2.4.0.jar needs to be included in the CLASSPATH:
javac -cp json-path-2.4.0.jar source file
For running applications that access JsonPath, I use the following command line:
java -cp accessors-smart-1.2.jar;asm-5.0.4.jar;json-path-2.4.0.jar;json-smart-2.3.jar;slf4j-api-1.7.25.jar;. main classfile

These command lines assume that the JAR files are located in the current directory. To facilitate working with the command lines, place them in a pair of batch files on Windows platforms (substitute %1 for source file or main classfile) or their counterparts on other platforms.

Note

JsonPath 2.4.0’s API reference is available online at www.javadoc.io/doc/com.jayway.jsonpath/json-path/2.4.0 .

Exploring the JsonPath Library

The JsonPath library is organized into several packages. You will typically interact with the com.jayway.jsonpath package and its types. In this section, I focus exclusively on this package while showing you how to extract values from JSON objects and use predicates to filter items.

Extracting Values from JSON Objects

The com.jayway.jsonpath package provides the JsonPath class as the entry point into using the JsonPath library. Listing 10-1 introduces this class.
import java.util.HashMap;
import java.util.List;
import com.jayway.jsonpath.JsonPath;
import static java.lang.System.*;
public class JsonPathDemo
{
   public static void main(String[] args)
   {
      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" +
      "         }" +
      "      ]," +
      "      "bicycle":" +
      "      {" +
      "         "color": "red"," +
      "         "price": 19.95" +
      "      }" +
      "   }" +
      "}";
      JsonPath path = JsonPath.compile("$.store.book[1]");
      HashMap books = path.read(json);
      out.println(books);
      List<Object> authors =
         JsonPath.read(json, "$.store.book[*].author");
      out.println(authors);
      String author =
         JsonPath.read(json, "$.store.book[1].author");
      out.println(author);
   }
}
Listing 10-1

A First Taste of JsonPath

Listing 10-1 provides a JsonPathDemo class whose main() method uses the JsonPath class to extract values from JSON objects. main() first declares a string-based JSON object and assigns its reference to variable json. It then invokes the following static JsonPath method to compile a JsonPath expression (to improve performance) and return the compiled result as a JsonPath object:
JsonPath compile(String jsonPath, Predicate... filters)

The Predicate varargs list lets you specify an array of filter predicates to match filter predicate place holders (identified as ? characters) in the jsonPath string. I’ll demonstrate Predicate and related types later in this chapter.

After compiling the $.store.book[1] JsonPath expression, which identifies the anonymous object in the second element of the array assigned to the book property of the anonymous object assigned to the store property, main() passes this expression to the following JsonPath method:
<T> T read(String json)

This generic method is called on the previously compiled JsonPath instance. It receives the string-based JSON object (assigned to json) as its argument and applies the JsonPath expression in the compiled JsonPath instance to this argument. The result is the JSON object identified by $.store.book[1].

The read() method is generic because it can return one of several types. In this example, it returns an instance of the java.util.LinkedHashMap class (a subclass of java.util.Hashmap) for storing JSON object property names and their values.

When you intend to reuse JsonPath expressions, it’s good to compile them, which improves performance. Because I don’t reuse $.store.book[1], I could have used one of JsonPath’s static read() methods instead. For example, main() next demonstrates the following read() method:
<T> T read(String json, String jsonPath, Predicate... filters)

This method creates a new JsonPath object for the jsonPath argument and applies it to the json string. I ignore filters in the example.

The JsonPath expression passed to jsonPath is $.store.book[*].author. This expression includes the * wildcard to match all elements in the book array. It returns the value of the author property for each element in this array.

read() returns this value as an instance of the net.minidev.json.JSONArray class, which is stored in the json-smart-2.3.jar file that you must include in the CLASSPATH. Because JSONArray extends java.util.ArrayList<Object>, it’s legal to cast the returned object to List<Object>.

To further demonstrate read(), main() lastly invokes this method with JsonPath expression $.store.book[1].author, which returns the value of the author property in the anonymous object stored in the second element of the book array. This time, read() returns a java.lang.String object.

Note

Regarding the generic read() methods, JsonPath automatically attempts to cast the result to the type that the method’s invoker expects, such as a hashmap for a JSON object, a list of objects for a JSON array, and a string for a JSON string.

Compile Listing 10-1 as follows:
javac -cp json-path-2.4.0.jar JsonPathDemo.java
Run the resulting application as follows:
java -cp accessors-smart-1.2.jar;asm-5.0.4.jar;json-path-2.4.0.jar;json-smart-2.3.jar;slf4j-api-1.7.25.jar;. JsonPathDemo
You should observe the following output:
{category=fiction, author=Evelyn Waugh, title=Sword of Honour, price=12.99}
["Nigel Rees","Evelyn Waugh"]
Evelyn Waugh

You’ll probably also observe some messages about SLF4J (Simple Logging Facade for Java) not being able to load the StaticLoggerBinder class and defaulting to a no-operation logger implementation. You can safely ignore these messages.

Using Predicates to Filter Items

JsonPath supports filters for restricting the nodes that are extracted from a JSON document to those that match the criteria specified by predicates (Boolean expressions). You can work with inline predicates, filter predicates, or custom predicates.

Inline Predicates

An inline predicate is a string-based predicate. Listing 10-2 presents the source code to an application that demonstrates several inline predicates.
import java.util.List;
import com.jayway.jsonpath.JsonPath;
import static java.lang.System.*;
public class JsonPathDemo
{
   public static void main(String[] args)
   {
      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": "J. R. R. Tolkien"," +
      "            "title": "The Lord of the Rings"," +
      "            "isbn": "0-395-19395-8"," +
      "            "price": 22.99" +
      "         }," +
      "         {" +
      "            "category": ""," +
      "            "author": "some author"," +
      "            "title": "some title"," +
      "            "isbn": "some isbn"," +
      "            "price": 0" +
      "         }" +
      "      ]," +
      "      "bicycle":" +
      "      [" +
      "         {" +
      "            "color": "red"," +
      "            "accessories": ["horn", " +
      "            "bottle"]," +
      "            "price": 619.95" +
      "         }," +
      "         {" +
      "            "color": "green"," +
      "            "accessories": ["horn", " +
      "            "light"]," +
      "            "price": 639.95" +
      "         }," +
      "         {" +
      "            "color": "blue"," +
      "            "accessories": []," +
      "            "price": 599.95" +
      "         }" +
      "      ]" +
      "   }" +
      "}";
      String expr = "$.store.book[?(@.isbn)].title";
      List<Object> titles = JsonPath.read(json, expr);
      out.println(titles);
      expr =
         "$.store.book[?(@.category == 'fiction')].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr = "$..book[?(@.author =~ /.*REES/i)].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr =
         "$..book[?(@.price > 10 && @.price < 20)].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr = "$..book[?(@.author in ['Nigel Rees'])].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr =
         "$..book[?(@.author nin ['Nigel Rees'])].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr = "$.store.bicycle[?(@.accessories " +
             "subsetof ['horn', 'bottle', 'light'])].price";
      List<Object> prices = JsonPath.read(json, expr);
      out.println(prices);
      expr = "$.store.bicycle[?(@.accessories " +
             "subsetof ['horn', 'bottle'])].price";
      prices = JsonPath.read(json, expr);
      out.println(prices);
      expr = "$..book[?(@.author size 12)].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr = "$..book[?(@.author size 13)].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr =
         "$..bicycle[?(@.accessories empty true)].price";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr =
         "$..bicycle[?(@.accessories empty false)].price";
      titles = JsonPath.read(json, expr);
      out.println(titles);
      expr = "$..book[?(@.category empty true)].title";
      titles = JsonPath.read(json, expr);
      out.println(titles);
   }
}
Listing 10-2

Demonstrating Inline Predicates

Listing 10-2’s main() method uses the following JsonPath expressions to narrow the list of returned book title strings:
  • $.store.book[?(@.isbn)].title: returns the title values for all book elements that contain an isbn property

  • $.store.book[?(@.category == 'fiction')].title: returns the title values for all book elements whose category property is assigned the string value fiction

  • $..book[?(@.author =~ /.*REES/i)].title: returns the title values for all book elements whose author property value ends with rees (case is insignificant)

  • $..book[?(@.price >= 10 && @.price <= 20)].title: returns the title values for all book elements whose price property value lies between 10 and 20

  • $..book[?(@.author in ['Nigel Rees'])].title: returns the title values for all book elements whose author property value matches Nigel Rees

  • $..book[?(@.author nin ['Nigel Rees'])].title: returns the title values for all book elements whose author property value doesn’t match Nigel Rees

  • $.store.bicycle[?(@.accessories subsetof ['horn', 'bottle', 'light'])].price: returns the price values for all bicycle elements whose accessories property value (an array) is a subset of the ['horn', 'bottle', 'light'] array

  • $.store.bicycle[?(@.accessories subsetof ['horn', 'bottle'])].price: returns the price values for all bicycle elements whose accessories property value (an array) is a subset of the ['horn', 'bottle'] array

  • $..book[?(@.author size 12)].title: returns the title values for all book elements whose author property value (a string) is exactly 12 characters long

  • $..book[?(@.author size 13)].title: returns the title values for all book elements whose author property value (a string) is exactly 13 characters long

  • $..bicycle[?(@.accessories empty true)].price: returns the price values for all bicycle elements whose accessories property value (an array) is empty

  • $..bicycle[?(@.accessories empty false)].price: returns the price values for all bicycle elements whose accessories property value (an array) is not empty

  • $..book[?(@.category empty true)].title: returns the title values for all book elements whose category property value (a string) has zero length

Compile Listing 10-2 and run the resulting application. You should discover the following output:
["The Lord of the Rings","some title"]
["Sword of Honour","The Lord of the Rings"]
["Sayings of the Century"]
["Sword of Honour"]
["Sayings of the Century"]
["Sword of Honour","The Lord of the Rings","some title"]
[619.95,639.95,599.95]
[619.95,599.95]
["Sword of Honour"]
[]
[599.95]
[619.95,639.95]
["some title"]

Filter Predicates

A filter predicate is a predicate expressed as an instance of the abstract Filter class, which implements the Predicate interface.

To create a filter predicate, you typically chain together invocations of various fluent methods ( http://en.wikipedia.org/wiki/Fluent_interface ) located in the Criteria class, which also implements Predicate, and pass the result to Filter’s Filter filter(Predicate predicate) static method.
Filter filter = Filter.filter(Criteria.where("price").lt(20.00));

Criteria’s Criteria where(String key) static method returns a Criteria object that stores the provided key, which is price in this example. Its Criteria lt(Object o) method returns a Criteria object for the < operator that identifies the value that’s compared to the value of the key.

To use the filter predicate, first insert a ? placeholder for the filter predicate into the path:
String expr = "$['store']['book'][?].title";

Note

When multiple filter predicates are provided, they are applied in left-to-right order of the placeholders where the number of placeholders must match the number of provided filter predicates. You can specify multiple predicate placeholders in one filter operation [?, ?]; both predicates must match.

Next, because Filter implements Predicate , you pass the filter predicate to a read() method that takes a Predicate argument:
List<Object> titles = JsonPath.read(json, expr, filter);

For each book element, the read() method executes the filter predicate when it detects the ? placeholder in the JsonPath expression.

Listing 10-3 presents the source code to an application that demonstrates the previous filter predicate code fragments.
import java.util.List;
import com.jayway.jsonpath.Criteria;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.JsonPath;
import static java.lang.System.*;
public class JsonPathDemo
{
   public static void main(String[] args)
   {
      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": "J. R. R. Tolkien"," +
      "            "title": "The Lord of the Rings"," +
      "            "isbn": "0-395-19395-8"," +
      "            "price": 22.99" +
      "         }" +
      "      ]," +
      "      "bicycle":" +
      "      {" +
      "         "color": "red"," +
      "         "price": 19.95" +
      "      }" +
      "   }" +
      "}";
      Filter filter =
         Filter.filter(Criteria.where("price").lt(20.00));
      String expr = "$['store']['book'][?].title";
      List<Object> titles = JsonPath.read(json, expr,
                                          filter);
      out.println(titles);
   }
}
Listing 10-3

Demonstrating Filter Predicates

Compile Listing 10-3 and run the resulting application. You should discover the following output (both books have prices less than 20 dollars):
["Sayings of the Century","Sword of Honour"]

Custom Predicates

A custom predicate is a predicate created from a class that implements the Predicate interface.

To create a custom predicate, instantiate a class that implements Predicate and overrides the following method:
boolean apply(Predicate.PredicateContext ctx)

PredicateContext is a nested interface whose methods provide information about the context in which apply() is called. For example, Object root() returns a reference to the entire JSON document, and Object item() returns the current item being evaluated by this predicate.

apply() returns the predicate value: true (item is accepted) or false (item is rejected).

The following code fragment creates a custom predicate for returning Book elements containing a price property whose value exceeds 20 dollars:
Predicate expensiveBooks =
   new Predicate()
   {
      @Override
      public boolean apply(PredicateContext ctx)
      {
         String value = ctx.item(Map.class).
                        get("price").toString();
         return Float.valueOf(value) > 20.00;
      }
   };

PredicateContext’s <T> T item(java.lang.Class<T> clazz) generic method maps the JSON object in the Book element to a java.util.Map.

To use the custom predicate, first insert a ? placeholder for the custom predicate into the path:
String expr = "$.store.book[?]";
Next, pass the custom predicate to a read() method that takes a Predicate argument:
List<Map<String, Object>> titles =
   JsonPath.read(json, expr, expensiveBooks);

For each book element, read() executes the custom predicate associated with the ? and returns a list of maps (one map per accepted item).

Listing 10-4 presents the source code to an application that demonstrates the previous custom predicate code fragments.
import java.util.List;
import java.util.Map;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Predicate;
import static java.lang.System.*;
public class JsonPathDemo
{
   public static void main(String[] args)
   {
      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": "J. R. R. Tolkien"," +
      "            "title": "The Lord of the Rings"," +
      "            "isbn": "0-395-19395-8"," +
      "            "price": 22.99" +
      "         }" +
      "      ]," +
      "      "bicycle":" +
      "      {" +
      "         "color": "red"," +
      "         "price": 19.95" +
      "      }" +
      "   }" +
      "}";
      Predicate expensiveBooks =
         new Predicate()
         {
            @Override
            public boolean apply(PredicateContext ctx)
            {
               String value = ctx.item(Map.class).
                              get("price").toString();
               return Float.valueOf(value) > 20.00;
            }
         };
      String expr = "$.store.book[?]";
      List<Map<String, Object>> titles =
         JsonPath.read(json, expr, expensiveBooks);
      out.println(titles);
   }
}
Listing 10-4

Demonstrating Custom Predicates

Compile Listing 10-4 and run the resulting application. You should discover the following output (one book has a price greater than 20 dollars):
[{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]

Exercises

The following exercises are designed to test your understanding of Chapter 10’s content:
  1. 1.

    Define JsonPath.

     
  2. 2.

    True or false: JsonPath is based on XPath 2.0.

     
  3. 3.

    Identify the operator that represents the root JSON object.

     
  4. 4.

    In what notations can you specify JsonPath expressions?

     
  5. 5.

    What operator represents the current node being processed by a filter predicate?

     
  6. 6.

    True or false: JsonPath’s deep scan operator (..) is equivalent to XPath’s / symbol.

     
  7. 7.

    What does JsonPath’s JsonPath compile(String jsonPath, Predicate... filters) static method accomplish?

     
  8. 8.

    What is the return type of the <T> T read(String json) generic method that returns JSON object property names and their values?

     
  9. 9.

    Identify the three predicate categories.

     
  10. 10.

    Given JSON object { "number": [10, 20, 25, 30] }, write a JsonPathDemo application that extracts and outputs the maximum (30), minimum (10), and average (21.25) values.

     

Summary

JsonPath is a declarative query language (also known as a path-expression-syntax) for selecting and extracting a JSON document’s property values.

JsonPath is a simple language with various features that are similar to their XPath counterparts. This language is used to construct path expressions. Each expression begins with the $ operator, which identifies the root element of the query and which corresponds to the XPath / symbol.

As with Chapter 8’s mJson and Chapter 9’s Gson, you can obtain JsonPath from the Central Maven Repository. Alternatively, if you’re not using Maven, you can download the JsonPath JAR file and all of the JAR files on which JsonPath normally depends and then add all of these JAR files to your CLASSPATH.

The JsonPath library is organized into several packages. You will typically interact with the com.jayway.jsonpath package and its types. In this chapter, you focused exclusively on this package while learning how to extract values from JSON objects and use predicates to filter items.

Chapter 11 introduces Jackson for parsing and generating JSON content.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.132.97