JSONPath RFC 9535: what changed

$.store.book[?length(@.title) > 15].title

$.store.book[?length(@.title) > 15].title is RFC 9535 JSONPath for the books whose title is longer than 15 characters: Sayings of the Century and The Lord of the Rings. JavaScript implementations before the RFC spelled it [?(@.title.length > 15)] and handed the filter to JavaScript. RFC 9535, published by the IETF in February 2024, defines JSONPath on its own terms, based on Stefan Gössner’s 2007 article, and that changed a handful of things. Below, “Jayway” is Jayway JsonPath 3.0.0 for Java and “jsonpath-plus” is version 11.1.0 for JavaScript, both run on the same bookstore.

Filters don’t need parentheses

A filter is ? followed by an expression, so [[email protected] < 10] is enough. [?(@.price < 10)] stays valid, since parentheses group. The older form is the only one Jayway and jsonpath-plus read: Jayway throws InvalidPathException on [[email protected] < 10], and jsonpath-plus returns [] without an error.

Script expressions are gone

Section 4.1 says why: handing parts of a query to eval() invites injection. [(@.length-1)] becomes [-1], and .length is just a member name, so [?(@.title.length > 15)] selects nothing here, because no book has a member called length. jsonpath-plus still runs it as JavaScript and returns the two books.

Five functions

$.store.book[?length(@.title) > 15].title                         Sayings of the Century, The Lord of the Rings
$.store.book[?count(@.*) == 5].title                              Moby Dick, The Lord of the Rings
$.store.book[?match(@.isbn, '0-[0-9]{3}-[0-9]{5}-[0-9]')].title   Moby Dick, The Lord of the Rings
$.store.book[?search(@.author, 'Tolkien')].title                  The Lord of the Rings
$.store[?value(@..color) == "red"]                                the bicycle

match() tests the whole string and search() any part of it, with I-Regexp patterns (RFC 9485): no \d, and ^ and $ are ordinary characters. Arguments are type-checked before anything runs: length(@.*) is an error, because @.* can select several nodes. New functions go through IANA’s Function Extensions registry. Jayway and jsonpath-plus know none of the five inside a filter; regular expressions there are Jayway’s =~ /…/ or JavaScript’s .match().

Nothing isn’t null

A missing member is Nothing, which equals only Nothing; null is a value like any other (section 2.6). Older libraries split, with the filter in parentheses for them:

                                  RFC 9535   Jayway   jsonpath-plus
[[email protected] == null]                 none       none     the 2 books without an ISBN
[[email protected] == @.publisher]     all 4      none     all 4

One normalized path per node

Section 2.7 gives each node one spelling: brackets, single-quoted names, non-negative indexes, as in $['store']['book'][3]['title']. The tester lists matches that way. For $.store.book[-1].title, Jayway’s path list says $['store']['book'][-1]['title'].

Errors are errors

A query that isn’t well-formed and valid must be refused (section 2.1), whatever document it runs on. That covers a missing $, space before or after the query, an index past ±(2^53 − 1) or written -0, and a comparison against a query that can select many nodes.

The JSONPath Compliance Test Suite turns all of this into cases. Run in October 2026, this tester passes 713 of its 715; the two it fails expect ^ and $ to anchor a match(), and the suite’s issue #122 tracks changing them to follow RFC 9485.

Try it in the JSONPath Tester

Member names, wildcards, indexes, slices, descendants and filters, the way RFC 9535 defines them. match() and search() take I-Regexp patterns: . is any character but \n and \r, \p{Lu} is a Unicode category, and there are no \d classes, no backreferences and no anchors.

Selection

2 values selected

PathValue
$['store']['book'][0]['title']"Sayings of the Century"
$['store']['book'][3]['title']"The Lord of the Rings"

The document, with the selection marked

{
  "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": 399 }
  }
}

Runs in your browser. Nothing you enter is sent anywhere.