JSONPath was in use for seventeen years before it had a specification. Stefan Gössner’s 2007 article defined it loosely and handed filter expressions to the host language — JavaScript’s eval(), in the original — so what ?(@.price < 10) meant depended on the library. Jayway’s Java library added operators and path functions of its own, and the same query came to mean different things in different tools. RFC 9535, published in February 2024, is the first standard. This tester implements it exactly and is checked against all 706 cases of the official JSONPath Compliance Test Suite, so a query that is valid here is valid in every conforming implementation, and one that is rejected here is not standard JSONPath, whatever your current library accepts.
The query is parsed and type-checked before the document is looked at, as the RFC requires: it is valid or an error regardless of the data, and a valid query never fails at run time — an index past the end or a missing name simply selects nothing. A filter [?…] runs over the children of each node it is given — the elements of an array, or the member values of an object — with @ bound to each child in turn. Comparisons never convert types, so 1 == '1' is false, and a missing value is equal only to another missing value. The five functions, length(), count(), match(), search() and value(), exist only inside filters, and the RFC’s typing rules decide where each may appear: length(@.tags) must be compared with something, while match(@.name, 'A.*') stands on its own as a test.
The result is always a list of nodes, even when one node matches, shown both as values and as Normalized Paths such as $['store']['book'][0]['title'] — the RFC’s single canonical spelling of a location, with names in single quotes and negative indexes resolved. Results from .. are in pre-order: each node before its own descendants, array elements in index order. Object members come in the order JavaScript holds them, which the RFC allows because objects are unordered, so a member named "10" is listed before one named "a". match() and search() take I-Regexp (RFC 9485), a portable subset of regular expressions: the pattern is validated, a dot matches anything except \n and \r, and a pattern that uses something outside the subset, such as \d or a lookahead, makes the function false rather than quietly running with JavaScript’s meaning.