$.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.