diff --git a/auth48/check-abnf b/auth48/check-abnf new file mode 100644 index 00000000..f679c7bd --- /dev/null +++ b/auth48/check-abnf @@ -0,0 +1,9 @@ +kramdown-rfc-extract-sourcecode -tfiles -dextract rfc9535.xml +# check consistency of collected ABNF +diff extract/abnf/collected-abnf-of-jsonpath-.abnf extract/abnf/jsonpath-collected.abnf +diff extract/abnf/collected-abnf-of-jsonpath-n.abnf extract/abnf/normalized-path-collected.abnf +# check whether there was any substantive change with I-D ABNF +bap extract/abnf/jsonpath-collected.abnf >/tmp/jc.abnf +bap ../sourcecode/abnf/jsonpath-collected.abnf | diff - /tmp/jc.abnf +bap extract/abnf/normalized-path-collected.abnf >/tmp/njc.abnf +bap ../sourcecode/abnf/normalized-path-collected.abnf | diff - /tmp/njc.abnf diff --git a/auth48/extract/application:jsonpath/count-function-extension.application:jsonpath b/auth48/extract/application:jsonpath/count-function-extension.application:jsonpath new file mode 100644 index 00000000..6441e046 --- /dev/null +++ b/auth48/extract/application:jsonpath/count-function-extension.application:jsonpath @@ -0,0 +1 @@ +$[?count(@.*.author) >= 5] diff --git a/auth48/extract/application:jsonpath/jsonpath-and-xpath.application:jsonpath b/auth48/extract/application:jsonpath/jsonpath-and-xpath.application:jsonpath new file mode 100644 index 00000000..63cb0093 --- /dev/null +++ b/auth48/extract/application:jsonpath/jsonpath-and-xpath.application:jsonpath @@ -0,0 +1 @@ +$.store.book[?@.price < 10].title diff --git a/auth48/extract/application:jsonpath/length-function-extension.application:jsonpath b/auth48/extract/application:jsonpath/length-function-extension.application:jsonpath new file mode 100644 index 00000000..f744a8e7 --- /dev/null +++ b/auth48/extract/application:jsonpath/length-function-extension.application:jsonpath @@ -0,0 +1 @@ +$[?length(@.authors) >= 5] diff --git a/auth48/extract/application:jsonpath/match-function-extension.application:jsonpath b/auth48/extract/application:jsonpath/match-function-extension.application:jsonpath new file mode 100644 index 00000000..9f1b96d7 --- /dev/null +++ b/auth48/extract/application:jsonpath/match-function-extension.application:jsonpath @@ -0,0 +1 @@ +$[?match(@.date, "1974-05-..")] diff --git a/auth48/extract/application:jsonpath/search-function-extension.application:jsonpath b/auth48/extract/application:jsonpath/search-function-extension.application:jsonpath new file mode 100644 index 00000000..5b587aad --- /dev/null +++ b/auth48/extract/application:jsonpath/search-function-extension.application:jsonpath @@ -0,0 +1 @@ +$[?search(@.author, "[BR]ob")] diff --git a/auth48/extract/application:jsonpath/segments-b.application:jsonpath b/auth48/extract/application:jsonpath/segments-b.application:jsonpath new file mode 100644 index 00000000..580912ec --- /dev/null +++ b/auth48/extract/application:jsonpath/segments-b.application:jsonpath @@ -0,0 +1 @@ +$.store.book[0].title diff --git a/auth48/extract/application:jsonpath/segments.application:jsonpath b/auth48/extract/application:jsonpath/segments.application:jsonpath new file mode 100644 index 00000000..f77e75e7 --- /dev/null +++ b/auth48/extract/application:jsonpath/segments.application:jsonpath @@ -0,0 +1 @@ +$['store']['book'][0]['title'] diff --git a/auth48/extract/application:jsonpath/selectors.application:jsonpath b/auth48/extract/application:jsonpath/selectors.application:jsonpath new file mode 100644 index 00000000..63cb0093 --- /dev/null +++ b/auth48/extract/application:jsonpath/selectors.application:jsonpath @@ -0,0 +1 @@ +$.store.book[?@.price < 10].title diff --git a/auth48/extract/application:jsonpath/value-function-extension.application:jsonpath b/auth48/extract/application:jsonpath/value-function-extension.application:jsonpath new file mode 100644 index 00000000..a7a645b0 --- /dev/null +++ b/auth48/extract/application:jsonpath/value-function-extension.application:jsonpath @@ -0,0 +1 @@ +$[?value(@..color) == "red"] diff --git a/auth48/extract/json/example-json-value.json b/auth48/extract/json/example-json-value.json new file mode 100644 index 00000000..7f16ce83 --- /dev/null +++ b/auth48/extract/json/example-json-value.json @@ -0,0 +1,31 @@ +{ "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 + } + } +} diff --git a/auth48/extract/json/examples-2.json b/auth48/extract/json/examples-2.json new file mode 100644 index 00000000..6c9a6b8c --- /dev/null +++ b/auth48/extract/json/examples-2.json @@ -0,0 +1,4 @@ +{ + "o": {"j j": {"k.k": 3}}, + "'": {"@": 2} +} diff --git a/auth48/extract/json/examples-3.json b/auth48/extract/json/examples-3.json new file mode 100644 index 00000000..02cbb64e --- /dev/null +++ b/auth48/extract/json/examples-3.json @@ -0,0 +1,4 @@ +{ + "o": {"j": 1, "k": 2}, + "a": [5, 3] +} diff --git a/auth48/extract/json/examples-4.json b/auth48/extract/json/examples-4.json new file mode 100644 index 00000000..7d2570c1 --- /dev/null +++ b/auth48/extract/json/examples-4.json @@ -0,0 +1 @@ +["a","b"] diff --git a/auth48/extract/json/examples-5.json b/auth48/extract/json/examples-5.json new file mode 100644 index 00000000..1b72d361 --- /dev/null +++ b/auth48/extract/json/examples-5.json @@ -0,0 +1 @@ +["a", "b", "c", "d", "e", "f", "g"] diff --git a/auth48/extract/json/examples-6-b.json b/auth48/extract/json/examples-6-b.json new file mode 100644 index 00000000..4e3729b9 --- /dev/null +++ b/auth48/extract/json/examples-6-b.json @@ -0,0 +1,10 @@ +{ + "a": [3, 5, 1, 2, 4, 6, + {"b": "j"}, + {"b": "k"}, + {"b": {}}, + {"b": "kilo"} + ], + "o": {"p": 1, "q": 2, "r": 3, "s": 5, "t": {"u": 6}}, + "e": "f" +} diff --git a/auth48/extract/json/examples-6.json b/auth48/extract/json/examples-6.json new file mode 100644 index 00000000..6f12af8d --- /dev/null +++ b/auth48/extract/json/examples-6.json @@ -0,0 +1,4 @@ +{ + "obj": {"x": "y"}, + "arr": [2, 3] +} diff --git a/auth48/extract/json/examples-7.json b/auth48/extract/json/examples-7.json new file mode 100644 index 00000000..1b72d361 --- /dev/null +++ b/auth48/extract/json/examples-7.json @@ -0,0 +1 @@ +["a", "b", "c", "d", "e", "f", "g"] diff --git a/auth48/extract/json/examples-8.json b/auth48/extract/json/examples-8.json new file mode 100644 index 00000000..eb76eef0 --- /dev/null +++ b/auth48/extract/json/examples-8.json @@ -0,0 +1,4 @@ +{ + "o": {"j": 1, "k": 2}, + "a": [5, 3, [{"j": 4}, {"k": 6}]] +} diff --git a/auth48/extract/json/examples-9.json b/auth48/extract/json/examples-9.json new file mode 100644 index 00000000..f5ea64b8 --- /dev/null +++ b/auth48/extract/json/examples-9.json @@ -0,0 +1 @@ +{"a": null, "b": [null], "c": [{}], "null": 1} diff --git a/auth48/extract/json/examples.json b/auth48/extract/json/examples.json new file mode 100644 index 00000000..34bc1840 --- /dev/null +++ b/auth48/extract/json/examples.json @@ -0,0 +1 @@ +{"k": "v"} diff --git a/auth48/extract/pseudocode/normative-semantics-b.pseudocode b/auth48/extract/pseudocode/normative-semantics-b.pseudocode new file mode 100644 index 00000000..b9b5d11f --- /dev/null +++ b/auth48/extract/pseudocode/normative-semantics-b.pseudocode @@ -0,0 +1,13 @@ +FUNCTION Bounds(start, end, step, len): + n_start = Normalize(start, len) + n_end = Normalize(end, len) + + IF step >= 0 THEN + lower = MIN(MAX(n_start, 0), len) + upper = MIN(MAX(n_end, 0), len) + ELSE + upper = MIN(MAX(n_start, -1), len-1) + lower = MIN(MAX(n_end, -1), len-1) + END IF + + RETURN (lower, upper) diff --git a/auth48/extract/pseudocode/normative-semantics-c.pseudocode b/auth48/extract/pseudocode/normative-semantics-c.pseudocode new file mode 100644 index 00000000..79e212ed --- /dev/null +++ b/auth48/extract/pseudocode/normative-semantics-c.pseudocode @@ -0,0 +1,17 @@ +IF step > 0 THEN + + i = lower + WHILE i < upper: + SELECT a(i) + i = i + step + END WHILE + +ELSE if step < 0 THEN + + i = upper + WHILE lower < i: + SELECT a(i) + i = i + step + END WHILE + +END IF diff --git a/auth48/extract/pseudocode/normative-semantics.pseudocode b/auth48/extract/pseudocode/normative-semantics.pseudocode new file mode 100644 index 00000000..5c08d510 --- /dev/null +++ b/auth48/extract/pseudocode/normative-semantics.pseudocode @@ -0,0 +1,6 @@ +FUNCTION Normalize(i, len): + IF i >= 0 THEN + RETURN i + ELSE + RETURN len + i + END IF diff --git a/auth48/extract/xpath/inspired-by-xpath-b.xpath b/auth48/extract/xpath/inspired-by-xpath-b.xpath new file mode 100644 index 00000000..70d14126 --- /dev/null +++ b/auth48/extract/xpath/inspired-by-xpath-b.xpath @@ -0,0 +1 @@ +x.store.book[0].title diff --git a/auth48/extract/xpath/inspired-by-xpath-c.xpath b/auth48/extract/xpath/inspired-by-xpath-c.xpath new file mode 100644 index 00000000..43960153 --- /dev/null +++ b/auth48/extract/xpath/inspired-by-xpath-c.xpath @@ -0,0 +1 @@ +x['store']['book'][0]['title'] diff --git a/auth48/extract/xpath/inspired-by-xpath.xpath b/auth48/extract/xpath/inspired-by-xpath.xpath new file mode 100644 index 00000000..04291d5f --- /dev/null +++ b/auth48/extract/xpath/inspired-by-xpath.xpath @@ -0,0 +1 @@ +/store/book[1]/title diff --git a/auth48/rfc9535.xml b/auth48/rfc9535.xml new file mode 100644 index 00000000..5b85f0f3 --- /dev/null +++ b/auth48/rfc9535.xml @@ -0,0 +1,3809 @@ + + + + + +]> + + + + + + + + JSONPath: Query Expressions for JSON + + + Fachhochschule Dortmund +
+ + Sonnenstraße 96 + Dortmund + D-44139 + Germany + + stefan.goessner@fh-dortmund.de +
+
+ + +
+ + + Winchester + + + United Kingdom + + + glyn.normington@gmail.com +
+
+ + Universität Bremen TZI +
+ + Postfach 330440 + Bremen + D-28359 + Germany + + +49-421-218-63921 + cabo@tzi.org +
+
+ + art + jsonpath + JSON + +JSONPath defines a string syntax for selecting and extracting JSON (RFC 8259) values from within a given JSON value. + +
+ + + + + + + +
+ Introduction + JSON is a popular representation +format for structured data values. +JSONPath defines a string syntax for selecting and extracting JSON values +from within a given JSON value. +In relation to JSON Pointer , JSONPath is not intended as a replacement but as a more powerful +companion. See . +
+ Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL + NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", + "MAY", and "OPTIONAL" in this document are to be interpreted as + described in BCP 14 + when, and only when, they appear in all capitals, as shown here. + +The grammatical rules in this document are to be interpreted as ABNF, +as described in . +ABNF terminal values in this document define Unicode scalar values rather than +their UTF-8 encoding. +For example, the Unicode PLACE OF INTEREST SIGN (U+2318) would be defined +in ABNF as %x2318. + Functions are referred to using the function name followed by a pair +of parentheses, as in fname(). + The terminology of applies except where clarified below. +The terms "primitive" and "structured" are used to group +different kinds of values as in . JSON objects and arrays are +structured; all other values are primitive. +Definitions for "object", "array", "number", and "string" remain +unchanged. +Importantly, "object" and "array" in particular do not take on a +generic meaning, such as they would in a general programming context. +The terminology of applies. +Additional terms used in this document are defined below. +
+
Value:
+
+ As per , a data item conforming to the generic data model of JSON, i.e., +primitive data (numbers, text strings, and the special +values null, true, and false), or structured data (JSON objects and arrays). + focuses on the textual representation of JSON values and +does not fully define the value abstraction assumed here. +
+
Member:
+
+ A name/value pair in an object. (A member is not itself a value.) +
+
Name:
+
+ The name (a string) in a name/value pair constituting a member. +This is also used in , but that specification does not +formally define it. +It is included here for completeness. +
+
Element:
+
+ A value in a JSON array. +
+
Index:
+
+ An integer that identifies a specific element in an array. +
+
Query:
+
+ Short name for a JSONPath expression. +
+
Query Argument:
+
+ Short name for the value a JSONPath expression is applied to. + +
+
Location:
+
+ The position of a value within the query argument. This can be thought of +as a sequence of names and indexes navigating to the value through +the objects and arrays in the query argument, with the empty sequence +indicating the query argument itself. +A location can be represented as a Normalized Path (defined below). +
+
Node:
+
+ The pair of a value along with its location within the query argument. +
+
Root Node:
+
+ The unique node whose value is the entire query argument. +
+
Root Node Identifier:
+
+ The expression $, which refers to the root node of the query argument. +
+
Current Node Identifier:
+
+ The expression @, which refers to the current node in the context +of the evaluation of a filter expression (described later). +
+
Children (of a node):
+
+ If the node is an array, the nodes of its elements; if the node is an object, the nodes of its member values. +If the node is neither an array nor an object, it has no children. +
+
Descendants (of a node):
+
+ The children of the node, together with the children of its children, and so forth +recursively. More formally, the "descendants" relation between nodes is the transitive +closure of the "children" relation. +
+
Depth (of a descendant node within a value):
+
+ The number of ancestors of the node within the value. The root node of the value has depth zero, +the children of the root node have depth one, their children have depth two, and so forth. +
+
Nodelist:
+
+ A list of nodes. +While a nodelist can be represented in JSON, e.g., as an array, this document +does not require or assume any particular representation. +
+
Parameter:
+
+ Formal parameter (of a function) that can take a function argument +(an actual parameter) in a function expression. +
+
Normalized Path:
+
+ + A form of JSONPath expression that identifies a node in a value by +providing a query that results in exactly that node. Each node in a +query argument is identified by exactly one Normalized Path (we say that the +Normalized Path is "unique" for that node), and to be a Normalized +Path for a specific query argument, the Normalized Path needs to identify +exactly one node. This is similar +to, but syntactically different from, a JSON Pointer . +Note: This definition is based on the syntactical definition in ; +JSONPath expressions that identify a node in a value but do not conform to that +syntax are not Normalized Paths. +
+
Unicode Scalar Value:
+
+ Any Unicode code point except high-surrogate and low-surrogate code points (in other words, integers in the inclusive base 16 ranges, either 0 to D7FF or +E000 to 10FFFF). JSONPath queries are sequences of Unicode scalar values. +
+
Segment:
+
+ One of the constructs that selects children ([<selectors>]) +or descendants (..&wj;[<selectors>]) of an input value. +
+
Selector:
+
+ A single item within a segment that takes the input value and produces a nodelist +consisting of child nodes of the input value. +
+
Singular Query:
+
+ A JSONPath expression built from segments that have been syntactically restricted in +a certain way () so that, regardless of the input +value, the expression produces a nodelist containing at most one node. +Note: JSONPath expressions that always produce a singular nodelist but do not +conform to the syntax in are not singular queries. +
+
+
+ JSON Values as Trees of Nodes + + This document models the query argument as a tree of JSON values, each +with its own node. +A node is either the root node or one of its descendants. + This document models the result of applying a query to the +query argument as a nodelist (a list of nodes). + Nodes are the selectable parts of the query argument. +The only parts of an object that can be selected by a query are the +member values. Member names and members (name/value pairs) cannot be +selected. +Thus, member values have nodes, but members and member names do not. +Similarly, member values are children of an object, but members and +member names are not. +
+
+
+ History + This document is based on 's popular JSONPath proposal (dated 2007-02-21) , builds on the experience from the widespread +deployment of its implementations, and provides a normative specification for it. + describes how JSONPath was inspired by XML's XPath +. + JSONPath was intended as a lightweight companion to JSON +implementations in programming languages such as PHP and JavaScript, +so instead of defining its own expression language, like XPath did, +JSONPath delegated parts of a query to the underlying +runtime, e.g., JavaScript's eval() function. +As JSONPath was implemented in more environments, JSONPath +expressions became decreasingly portable. +For example, regular expression processing was often delegated to a +convenient regular expression engine. + This document aims to remove such implementation-specific dependencies and +serve as a common JSONPath specification that can be used across +programming languages and environments. +This means that backwards compatibility is +not always achieved; a design principle of this document is to +go with a "consensus" between implementations even if it is rough, as +long as that does not jeopardize the objective of obtaining a usable, +stable JSON query language. + The term JSONPath was chosen because of the XPath inspiration and also because +the outcome of a query consists of paths identifying nodes in the +JSON query argument. +
+
+ JSON Values + The JSON value a JSONPath query is applied to is, by definition, a +valid JSON value. A JSON value is often constructed by parsing +a JSON text. + The parsing of a JSON text into a JSON value and what happens if a JSON +text does not represent valid JSON are not defined by this document. +Sections and of identify specific situations that may +conform to the grammar for JSON texts but are not interoperable uses +of JSON, as they may cause unpredictable behavior. +This document does not attempt to define predictable +behavior for JSONPath queries in these situations. +Specifically, the "Semantics" subsections of Sections +, , +, and describe behavior that +becomes unpredictable when the JSON value for one of the objects +under consideration was constructed out of JSON text that exhibits +multiple members for a single object that share the same member name +("duplicate names"; see ). +Also, when selecting a child by name () and comparing strings +(), it is assumed these +strings are sequences of Unicode scalar values; the behavior becomes unpredictable +if they are not (). +
+
+ Overview of JSONPath Expressions + A JSONPath expression is applied to a JSON value, known as the query argument. +The output is a nodelist. + A JSONPath expression consists of an identifier followed by a series +of zero or more segments, each of which contains one or more selectors. +
+ Identifiers + The root node identifier $ refers to the root node of the query argument, +i.e., to the argument as a whole. + The current node identifier @ refers to the current node in the context +of the evaluation of a filter expression (). +
+
+ Segments + Segments select children ([<selectors>]) or descendants (..&wj;[<selectors>]) of an input value. + Segments can use bracket notation, for example: + + or the more compact dot notation, for example: + + Bracket notation contains one or more (comma-separated) selectors of any kind. +Selectors are detailed in the next section. + A JSONPath expression may use a combination of bracket and dot notations. + This document treats the bracket notations as canonical and defines the shorthand dot notation in terms +of bracket notation. Examples and descriptions use shorthand where convenient. +
+
+ Selectors + A name selector, e.g., 'name', selects a named child of an object. + An index selector, e.g., 3, selects an indexed child of an array. + In the expression [*], a wildcard * () selects all children of a +node, and in the expression ..[*], it selects all descendants of a node. + An array slice start:end:step () selects a series of +elements from an array, giving a start position, an end position, and +an optional step value that moves the position from the start to the + end. + A filter expression ?<logical-expr> selects certain children of an object or array, as in: + +
+
+ Summary + provides a brief overview of JSONPath syntax. + + Overview of JSONPath Syntax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Syntax ElementDescription
+ $ + root node identifier
+ @ + current node identifier (valid only within filter selectors)
+ [<selectors>] + child segment: selects zero or more children of a node
+ .nameshorthand for ['name']
+ .*shorthand for [*]
+ ..&wj;[<selectors>] + descendant segment: selects zero or more descendants of a node
+ ..nameshorthand for ..['name']
+ ..*shorthand for ..[*]
+ 'name' + name selector: selects a named child of an object
+ * + wildcard selector: selects all children of a node
+ 3 + index selector: selects an indexed child of an array (from 0)
+ 0:100:5 + array slice selector: start:end:step for arrays
+ ?<logical-expr> + filter selector: selects particular children using a logical expression
+ length(@.foo) + function extension: invokes a function in a filter expression
+
+
+
+ JSONPath Examples + This section is informative. It provides examples of JSONPath expressions. + The examples are based on the simple JSON value shown in +, representing a bookstore (which also has a bicycle). +
+ Example JSON Value + +
+ shows some JSONPath queries that might be applied to this example and their intended results. + + Example JSONPath Expressions and Their Intended Results When Applied to the Example JSON Value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
JSONPathIntended Result
+ $.store.book[*].authorthe authors of all books in the store
+ $..authorall authors
+ $.store.*all things in the store, which are some books and a red bicycle
+ $.store..pricethe prices of everything in the store
+ $..book[2]the third book
+ $..book[2].authorthe third book's author
+ $..book[2].publisherempty result: the third book does not have a "publisher" member
+ $..book[-1]the last book in order
+ $..book[0,1]
$..book[:2]
the first two books
+ $..book[?@.isbn]all books with an ISBN number
+ $..book[?@.price<10]all books cheaper than 10
+ $..*all member values and array elements contained in the input value
+
+
+
+ JSONPath Syntax and Semantics +
+ Overview + A JSONPath expression is a string that, when applied to a JSON value +(the query argument), selects zero or more nodes of the argument and outputs +these nodes as a nodelist. + A query MUST be encoded using UTF-8. +The grammar for queries given in this document assumes that its UTF-8 form is first decoded into +Unicode scalar values as described +in ; implementation approaches that lead to an equivalent +result are possible. + +A string to be used as a JSONPath query needs to be well-formed and +valid. +A string is a well-formed JSONPath query if it conforms to the ABNF syntax in this document. +A well-formed JSONPath query is valid if it also fulfills both semantic +requirements posed by this document, which are as follows: +
  1. Integer numbers in the JSONPath query that are relevant +to the JSONPath processing (e.g., index values and steps) MUST be +within the range of exact integer values defined in Internet JSON (I-JSON) (see ), namely within the interval [-(253)+1, +(253)-1].
  2. +
  3. Uses of function extensions MUST be well-typed, +as described in .
  4. +
+ A JSONPath implementation MUST raise an error for any query that is not +well-formed and valid. +The well-formedness and the validity of JSONPath queries are independent of +the JSON value the query is applied to. No further errors relating to the +well-formedness and the validity of a JSONPath query can be +raised during application of the query to a value. +This clearly separates well-formedness/validity errors in the query +from mismatches that may actually stem from flaws in the data. + Mismatches between the structure expected by a valid query +and the structure found in the data can lead to empty query results, +which may be unexpected and indicate bugs in either. +JSONPath implementations might therefore want to provide diagnostics +to the application developer that aid in finding the cause of empty +results. + Obviously, an implementation can still fail when executing a JSONPath +query, e.g., because of resource depletion, but this is not modeled in +this document. However, the implementation MUST NOT +silently malfunction. Specifically, if a valid JSONPath query is +evaluated against a structured value whose size is too large to +process the query correctly (for instance, requiring the processing of +numbers that fall outside the range of exact values), the implementation + MUST provide an indication of overflow. + (Readers familiar with the HTTP error model may be reminded of 400 +type errors when pondering well-formedness and validity, and they may +recognize resource depletion and related errors as comparable to 500 type +errors.) +
+ Syntax + Syntactically, a JSONPath query consists of a root identifier ($), which +stands for a nodelist that contains the root node of the query argument, +followed by a possibly empty sequence of segments. + + The syntax and semantics of segments are defined in . +
+
+ Semantics + In this document, the semantics of a JSONPath query define the +required results and do not prescribe the internal workings of an +implementation. This document may describe semantics in a procedural +step-by-step fashion; however, such descriptions are normative only in the sense that any implementation MUST produce an identical result but not in the sense that implementers are required to use the same algorithms. + The semantics are that a valid query is executed against a value +(the query argument) and produces a nodelist (i.e., a list of zero or more nodes of the value). + The query is a root identifier followed by a sequence of zero or more segments, each of +which is applied to the result of the previous root identifier or segment and provides +input to the next segment. +These results and inputs take the form of nodelists. + The nodelist resulting from the root identifier contains a single node +(the query argument). +The nodelist resulting from the last segment is presented as the +result of the query. Depending on the specific API, it might be +presented as an array of the JSON values at the nodes, an array of +Normalized Paths referencing the nodes, or both -- or some other +representation as desired by the implementation. +Note: An empty nodelist is a valid query result. + A segment operates on each of the nodes in its input nodelist in turn, +and the resultant nodelists are concatenated in the order of the input +nodelist they were derived from to produce +the result of the segment. A node may be selected more than once and +appears that number of times in the nodelist. Duplicate nodes are not removed. + A syntactically valid segment MUST NOT produce errors when executing the query. +This means that some +operations that might be considered erroneous, such as using an index +lying outside the range of an array, +simply result in fewer nodes being selected. +(Additional discussion of this property can be found in the introduction of .) + As a consequence of this approach, if any of the segments + produces an empty nodelist, then the whole query produces an empty + nodelist. + + If the semantics of a query give an implementation a choice of producing multiple possible orderings, a particular implementation +may produce distinct orderings in successive runs of the query. +
+
+ Example + Consider this example. With the query argument {"a":[{"b":0},{"b":1},{"c":2}]}, the +query $.a[*].b selects the following list of nodes (denoted here by their values): 0, 1. + The query consists of $ followed by three segments: .a, [*], and .b. + First, $ produces a nodelist consisting of just the query argument. + Next, .a selects from any object input node and selects the +node of any +member value of the input +node corresponding to the member name "a". +The result is again a list containing a single node: [{"b":0},{"b":1},{"c":2}]. + Next, [*] selects all the elements +from the input array node. +The result is a list of three nodes: {"b":0}, {"b":1}, and {"c":2}. + Finally, .b selects from any object input node with a member name +b and selects the node of the member value of the input node corresponding to that name. +The result is a list containing 0, 1. +This is the concatenation of three lists: two of length one containing +0, 1, respectively, and one of length zero. +
+
+
+ Root Identifier +
+ Syntax + Every JSONPath query (except those inside filter expressions; see ) MUST begin with the root identifier $. + +
+
+ Semantics + The root identifier $ represents the root node of the query argument +and produces a nodelist consisting of that root node. +
+
+ Examples + + JSON: + + Queries: + + Root Identifier Example + + + + + + + + + + + + + + + + +
QueryResultResult PathComment
+ $ + {"k": "v"} + $Root node
+
+
+
+ Selectors + Selectors appear only inside child segments and +descendant segments. + A selector produces a nodelist consisting of zero or more children of the input value. + There are various kinds of selectors that produce children of objects, children of arrays, +or children of either objects or arrays. + + The syntax and semantics of each kind of selector are defined below. +
+ Name Selector +
+ Syntax + A name selector '<name>' selects at most one object member value. + In contrast to JSON, +the JSONPath syntax allows strings to be enclosed in single or double quotes. + + Notes: +
    +
  • + Double-quoted strings follow the JSON string syntax (); + single-quoted strings follow an analogous pattern. +No attempt was made to improve on this syntax, so if it is desired to +escape characters with +scalar values above 0xFFFF, such as 🎼, +they need to be represented +by a pair of surrogate escapes ("\uD83C\uDFBC" in this case).
  • +
  • Alphabetic characters in quoted strings are case-insensitive in ABNF, +so each of the hexadecimal digits within \u escapes (as specified in rules +referenced by hexchar) can be either lowercase or uppercase, +while the u in \u needs to be lowercase (indicated as %x75).
  • +
+
+
+ Semantics + A name-selector string MUST be converted to a +member name M by removing the surrounding quotes and +replacing each escape sequence with its equivalent Unicode character, as +shown in : + + Escape Sequence Replacements + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Escape SequenceUnicode CharacterDescription
+ \bU+0008BS backspace
+ \tU+0009HT horizontal tab
+ \nU+000ALF line feed
+ \fU+000CFF form feed
+ \rU+000DCR carriage return
+ \"U+0022quotation mark
+ \'U+0027apostrophe
+ \/U+002Fslash (solidus)
+ \\U+005Cbackslash (reverse solidus)
+ \uXXXXsee hexadecimal escape
+ Applying the name-selector to an object node +selects a member value whose name equals the member name M +or selects nothing if there is no such member value. +Nothing is selected from a value that is not an object. + Note: Processing the name selector requires comparing the member name string M +with member name strings in the JSON to which the selector is being applied. +Two strings MUST be considered equal if and only if they are identical +sequences of Unicode scalar values. In other words, normalization operations +MUST NOT be applied to either the member name string M from the JSONPath or +the member name strings in the JSON prior to comparison. +
+
+ Examples +JSON: + + Queries: + The examples in show the name selector in use by child segments. + + Name Selector Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $.o['j j'] + {"k.k": 3} + $['o']['j j']Named
value in
a nested
object
+ $.o['j j']&wj;['k.k'] + 3 + $['o']['j j']&wj;['k.k']Nesting
further
down
+ $.o["j j"]&wj;["k.k"] + 3 + $['o']['j j']&wj;['k.k']Different
delimiter
in the query,
unchanged
Normalized
Path
+ $["'"]["@"] + 2 + $['\'']['@']Unusual
member
names
+
+
+
+ Wildcard Selector +
+ Syntax + The wildcard selector consists of an asterisk. + +
+
+ Semantics + A wildcard selector selects the nodes of all children of an object or array. +The order in which the children of an object appear in the resultant nodelist is not stipulated, +since JSON objects are unordered. + Children of an array appear in array order in the resultant nodelist. + Note that the children of an object are its member values, not its member names. + The wildcard selector selects nothing from a primitive JSON value (that is, +a number, a string, true, false, or null). +
+
+ Examples + JSON: + + Queries: + The examples in show the wildcard selector in use by a child segment. + + Wildcard Selector Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $[*] + {"j": 1, "k": 2}
[5, 3]
+ $['o']
$['a']
Object values
+ $.o[*] + 1
2
+ $['o']['j']
$['o']['k']
Object values
+ $.o[*] + 2
1
+ $['o']['k']
$['o']['j']
Alternative result
+ $.o[*, *] + 1
2
2
1
+ $['o']['j']
$['o']['k']
$['o']['k']
$['o']['j']
Non-deterministic ordering
+ $.a[*] + 5
3
+ $['a'][0]
$['a'][1]
Array members
+ The example above with the query $.o[*, *] shows that the wildcard selector may produce nodelists in distinct +orders each time it appears in the child segment when it is applied to an object node with two or more +members (but not when it is applied to object nodes with fewer than two members or to array nodes). +
+
+
+ Index Selector +
+ Syntax + An index selector <index> matches at most one array element value. + + Applying the numerical index-selector selects the corresponding +element. JSONPath allows it to be negative (see ). + To be valid, the index selector value MUST be in the I-JSON +range of exact values (see ). + Notes: +
    +
  • An index-selector is an integer (in base 10, as in JSON numbers).
  • +
  • As in JSON numbers, the syntax does not allow octal-like integers with leading zeros, such as 01 or -01.
  • +
+
+
+ Semantics + A non-negative index-selector applied to an array selects an array element using a zero-based index. +For example, the selector 0 selects the first, and the selector 4 selects the fifth element of a sufficiently long array. +Nothing is selected, and it is not an error, if the index lies outside the range of the array. Nothing is selected from a value that is not an array. + A negative index-selector counts from the array end backwards, +obtaining an equivalent non-negative index-selector by adding the +length of the array to the negative index. +For example, the selector -1 selects the last, and the selector -2 selects the penultimate element of an array with at least two elements. +As with non-negative indexes, it is not an error if such an element does +not exist; this simply means that no element is selected. +
+
+ Examples +JSON: + + Queries: + The examples in show the index selector in use by a child segment. + + Index Selector Examples + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $[1] + "b" + $[1]Element of array
+ $[-2] + "a" + $[0]Element of array, from the end
+
+
+
+ Array Slice Selector +
+ Syntax + The array slice selector has the form <start>:<end>:<step>. +It matches elements from arrays starting at index <start> and ending at (but +not including) <end>, while incrementing by step with a default of 1. + + The slice selector consists of three optional decimal integers separated by colons. +The second colon can be omitted when the third integer is omitted. + To be valid, the integers provided MUST be in the I-JSON +range of exact values (see ). +
+
+ Semantics + The slice selector was inspired by + the slice operator that was proposed for ECMAScript 4 (ES4), which was never released, + and that of Python. +
+ Informal Introduction + This section is informative. + Array slicing is inspired by the behavior of the Array.prototype.slice method +of the JavaScript language, as defined by the ECMA-262 standard , +with the addition of the step parameter, which is inspired by the Python slice expression. + The array slice expression start:end:step selects elements at indices starting at start, +incrementing by step, and ending with end (which is itself excluded). +So, for example, the expression 1:3 (where step defaults to 1) +selects elements with indices 1 and 2 (in that order), whereas +1:5:2 selects elements with indices 1 and 3. + When step is negative, elements are selected in reverse order. Thus, +for example, 5:1:-2 selects elements with indices 5 and 3 (in +that order), and ::-1 selects all the elements of an array in +reverse order. + When step is 0, no elements are selected. +(This is the one case that differs from the behavior of Python, which +raises an error in this case.) + The following section specifies the behavior fully, without depending on +JavaScript or Python behavior. +
+
+ Normative Semantics + A slice expression selects a subset of the elements of the input array in +the same order +as the array or the reverse order, depending on the sign of the step parameter. +It selects no nodes from a node that is not an array. + A slice is defined by the two slice parameters, start and end, and +an iteration delta, step. +Each of these parameters is +optional. In the rest of this section, len denotes the length of the input array. + The default value for step is 1. +The default values for start and end depend on the sign of step, +as shown in . + + Default Array Slice start and end Values + + + + + + + + + + + + + + + + + + + +
Conditionstartend
step >= 00len
step < 0len - 1-len - 1
+ Slice expression parameters start and end are not directly usable +as slice bounds and must first be normalized. +Normalization for this purpose is defined as: + = 0 THEN + RETURN i + ELSE + RETURN len + i + END IF +]]> + The result of the array index expression i applied to an array +of length len is the result of the array +slicing expression Normalize(i, len):Normalize(i, len)+1:1. + Slice expression parameters start and end are used to derive slice bounds lower and upper. +The direction of the iteration, defined +by the sign of step, determines which of the parameters is the lower bound and which +is the upper bound: + = 0 THEN + lower = MIN(MAX(n_start, 0), len) + upper = MIN(MAX(n_end, 0), len) + ELSE + upper = MIN(MAX(n_start, -1), len-1) + lower = MIN(MAX(n_end, -1), len-1) + END IF + + RETURN (lower, upper) +]]> + The slice expression selects elements with indices between the lower and +upper bounds. +In the following pseudocode, a(i) is the i+1th element of the array a +(i.e., a(0) is the first element, a(1) the second, and so forth). + 0 THEN + + i = lower + WHILE i < upper: + SELECT a(i) + i = i + step + END WHILE + +ELSE if step < 0 THEN + + i = upper + WHILE lower < i: + SELECT a(i) + i = i + step + END WHILE + +END IF +]]> + When step = 0, no elements are selected, and the result array is empty. +
+
+
+ Examples + JSON: + + Queries: + The examples in show the array slice selector in use by a child segment. + + Array Slice Selector Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $[1:3] + "b"
"c"
+ $[1]
$[2]
Slice with default step
+ $[5:] + "f"
"g"
+ $[5]
$[6]
Slice with no end index
+ $[1:5:2] + "b"
"d"
+ $[1]
$[3]
Slice with step 2
+ $[5:1:-2] + "f"
"d"
+ $[5]
$[3]
Slice with negative step
+ $[::-1] + "g"
"f"
"e"
"d"
"c"
"b"
"a"
+ $[6]
$[5]
$[4]
$[3]
$[2]
$[1]
$[0]
Slice in reverse order
+
+
+
+ Filter Selector + Filter selectors are used to iterate over the elements or members of +structured values, i.e., JSON arrays and objects. +The structured values are identified in the nodelist offered by the +child or descendant segment using the filter selector. + For each iteration (element/member), a logical expression (the filter expression) +is evaluated, which decides whether the node of +the element/member is selected. +(While a logical expression evaluates to what mathematically is a +Boolean value, this specification uses the term logical to maintain a distinction from +the Boolean values that JSON can represent.) + During the iteration process, the filter expression receives the node +of each array element or object member value of the structured value being +filtered; this element or member value is then known as the current node. + The current node can be used as the start of one or more JSONPath +queries in subexpressions of the filter expression, notated +via the current-node-identifier @. +Each JSONPath query can be used either for testing existence of a +result of the query, for obtaining a specific JSON value resulting +from that query that can then be used in a comparison, or as a +function argument. + Filter selectors may use function extensions, which are covered in . +Within the logical expression for a filter selector, function +expressions can be used to operate on nodelists and values. +The set of available functions is extensible, with a number of +functions predefined (see ) and the ability to register further +functions provided by the "Function Extensions" subregistry (). +When a function is defined, it is given a unique name, and its return value and each of its parameters are given a +declared type. +The type system is limited in scope; its purpose is to express +restrictions that, without functions, are implicit in the grammar of +filter expressions. +The type system also guides conversions () that mimic the +way different kinds of expressions are handled in the grammar when +function expressions are not in use. +
+ Syntax + The filter selector has the form ?<logical-expr>. + + As the filter expression is composed of constituents free of side effects, +the order of evaluation does not need to be (and is not) defined. +Similarly, for conjunction (&&) and disjunction (||) (defined later), +both a short-circuiting and a fully evaluating +implementation will lead to the same result; both implementation +strategies are therefore valid. + The current node is accessible via the current node identifier @. +This identifier addresses the current node of the filter-selector that +is directly enclosing the identifier. Note: Within nested +filter-selectors, there is no syntax to address the current node of +any other than the directly enclosing filter-selector (i.e., of +filter-selectors enclosing the filter-selector that is directly +enclosing the identifier). + Logical expressions offer the usual Boolean operators (|| for OR, +&& for AND, and ! for NOT). +They have the normal semantics of Boolean algebra and obey its laws +(for example, see ). +Parentheses MAY be used within logical-expr for grouping. + It is not required that logical-expr consist of +a parenthesized expression (which was required in ), +although it can be, and the semantics are the same +as without the parentheses. + + A test expression +either tests the existence of a node +designated by an embedded query (see ) or tests the +result of a function expression (see ). +In the latter case, if the function's declared result type is +LogicalType (see ), it tests whether the result +is LogicalTrue; if the function's declared result type is +NodesType, it tests whether the result is non-empty. +If the function's declared result type is ValueType, its use in a +test expression is not well-typed (see ). + + Comparison expressions are available for comparisons between primitive +values (that is, numbers, strings, true, false, and null). +These can be obtained via literal values; singular queries, each of +which selects at most one node, the value of which is then used; or +function expressions (see ) of type ValueType. + =" / + "<" / ">" + +singular-query = rel-singular-query / abs-singular-query +rel-singular-query = current-node-identifier singular-query-segments +abs-singular-query = root-identifier singular-query-segments +singular-query-segments = *(S (name-segment / index-segment)) +name-segment = ("[" name-selector "]") / + ("." member-name-shorthand) +index-segment = "[" index-selector "]" +]]> + Literals can be notated in the way that is usual for JSON (with the +extension that strings can use single-quote delimiters). + Note: Alphabetic characters in quoted strings are case-insensitive in ABNF, so within a +floating point number, the ABNF expression "e" can be either the character +'e' or 'E'. + true, false, and null are lowercase only (case-sensitive). + + lists filter expression operators in order of precedence from highest (binds most tightly) to lowest (binds least tightly). + + Filter Expression Operator Precedence + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PrecedenceOperator typeSyntax
5Grouping
Function Expressions
+ (...)
name(...)
4Logical NOT + !
3Relations + == !=
< <= > >=
2Logical AND + &&
1Logical OR + ||
+
+
+ Semantics + The filter selector works with arrays and objects exclusively. Its result is a list of (zero, one, multiple, or all) their array elements or member values, respectively. +Applied to a primitive value, it selects nothing (and therefore does +not contribute to the result of the filter selector). + In the resultant nodelist, children of an array are ordered by their position in the array. +The order in which the children of an object (as opposed to an array) +appear in the resultant nodelist is not stipulated, +since JSON objects are unordered. +
+ Existence Tests + A query by itself in a logical context is an existence test that yields true if the query selects at least one node and yields false if the query does not select any nodes. + Existence tests differ from comparisons in that: +
    +
  • They work with arbitrary relative or absolute queries (not just singular queries).
  • +
  • They work with queries that select structured values.
  • +
+ To examine the value of a node selected by a query, an explicit comparison is necessary. +For example, to test whether the node selected by the query @.foo has the value null, use @.foo == null (see ) +rather than the negated existence test !@.foo (which yields false if @.foo selects a node, regardless of the node's value). +Similarly, @.foo == false yields true only if @.foo selects a node and +the value of that node is false. +
+
+ Comparisons + The comparison operators == and < are defined first, and then these are used to define !=, <=, >, and >=. + When either side of a comparison results in an empty nodelist or the +special result Nothing (see ): +
    +
  • A comparison using the operator == yields true if and only the +other side also results in an empty nodelist or the special result Nothing.
  • +
  • A comparison using the operator < yields false.
  • +
+ When any query or function expression on either side of a comparison results in a nodelist consisting of a single node, that side is +replaced by the value of its node and then: +
    +
  • + A comparison using the operator == yields true if and only if the comparison +is between: + +
      +
    • numbers expected to interoperate, as per I-JSON, that compare equal using normal mathematical equality,
    • +
    • numbers, at least one of which is not expected to interoperate as per I-JSON, where the numbers compare equal using an implementation-specific equality,
    • +
    • equal primitive values that are not numbers,
    • +
    • equal arrays, that is, arrays of the same length where each element of the first array is equal to the corresponding +element of the second array, or
    • +
    • + equal objects with no duplicate names, that is, where: + +
        +
      • both objects have the same collection of names (with no duplicates) and
      • +
      • for each of those names, the values associated with the name by the objects are equal.
      • +
      +
    • +
    +
  • +
  • + A comparison using the operator < yields true if and only if +the comparison is between values that are both numbers or both strings and that satisfy the comparison: +
      +
    • numbers expected to interoperate, as per I-JSON, MUST compare using the normal mathematical ordering; +numbers not expected to interoperate, as per I-JSON, MAY compare using an implementation-specific ordering,
    • +
    • the empty string compares less than any non-empty string, and
    • +
    • a non-empty string compares less than another non-empty string if and only if the first string starts with a +lower Unicode scalar value than the second string or if both strings start with the same Unicode scalar value and +the remainder of the first string compares less than the remainder of the second string.
    • +
    +
  • +
+ !=, <=, >, and >= are defined in terms of the other comparison operators. For any a and b: +
    +
  • The comparison a != b yields true if and only if a == b yields false.
  • +
  • The comparison a <= b yields true if and only if a < b yields true or a == b yields true.
  • +
  • The comparison a > b yields true if and only if b < a yields true.
  • +
  • The comparison a >= b yields true if and only if b < a yields true or a == b yields true.
  • +
+
+
+
+ Examples + The first set of examples shows some comparison expressions and their +result with a given JSON value as input. + JSON: + + Comparisons: + + Comparison Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComparisonResultComment
+ $.absent1 == $.absent2trueEmpty nodelists
+ $.absent1 <= $.absent2true + == implies <=
+ $.absent == 'g'falseEmpty nodelist
+ $.absent1 != $.absent2falseEmpty nodelists
+ $.absent != 'g'trueEmpty nodelist
+ 1 <= 2trueNumeric comparison
+ 1 > 2falseNumeric comparison
+ 13 == '13'falseType mismatch
+ 'a' <= 'b'trueString comparison
+ 'a' > 'b'falseString comparison
+ $.obj == $.arrfalseType mismatch
+ $.obj != $.arrtrueType mismatch
+ $.obj == $.objtrueObject comparison
+ $.obj != $.objfalseObject comparison
+ $.arr == $.arrtrueArray comparison
+ $.arr != $.arrfalseArray comparison
+ $.obj == 17falseType mismatch
+ $.obj != 17trueType mismatch
+ $.obj <= $.arrfalseObjects and arrays do not offer < comparison
+ $.obj < $.arrfalseObjects and arrays do not offer < comparison
+ $.obj <= $.objtrue + == implies <=
+ $.arr <= $.arrtrue + == implies <=
+ 1 <= $.arrfalseArrays do not offer < comparison
+ 1 >= $.arrfalseArrays do not offer < comparison
+ 1 > $.arrfalseArrays do not offer < comparison
+ 1 < $.arrfalseArrays do not offer < comparison
+ true <= truetrue + == implies <=
+ true > truefalseBooleans do not offer < comparison
+ The second set of examples shows some complete JSONPath queries that make use +of filter selectors and the results of evaluating these queries on a +given JSON value as input. +(Note: Two of the queries employ function extensions; please see +Sections and for details about these.) + JSON: + + Queries: + The examples in show the filter selector in use by a child segment. + + Filter Selector Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $.a[?@.b == 'kilo'] + {"b": "kilo"} + $['a'][9]Member value comparison
+ $.a[?(@.b == 'kilo')] + {"b": "kilo"} + $['a'][9]Equivalent query with enclosing parentheses
+ $.a[?@>3.5] + 5
4
6
+ $['a'][1]
$['a'][4]
$['a'][5]
Array value comparison
+ $.a[?@.b] + {"b": "j"}
{"b": "k"}
{"b": {}}
{"b": "kilo"}
+ $['a'][6]
$['a'][7]
$['a'][8]
$['a'][9]
Array value existence
+ $[?@.*] + [3, 5, 1, 2, 4, 6, {"b": "j"}, {"b": "k"}, {"b": {}}, {"b": "kilo"}]
{"p": 1, "q": 2, "r": 3, "s": 5, "t": {"u": 6}}
+ $['a']
$['o']
Existence of non-singular queries
+ $[?@[?@.b]] + [3, 5, 1, 2, 4, 6, {"b": "j"}, {"b": "k"}, {"b": {}}, {"b": "kilo"}] + $['a']Nested filters
+ $.o[?@<3, ?@<3] + 1
2
2
1
+ $['o']['p']
$['o']['q']
$['o']['q']
$['o']['p']
Non-deterministic ordering
+ $.a[?@<2 || @.b == "k"] + 1
{"b": "k"}
+ $['a'][2]
$['a'][7]
Array value logical OR
+ $.a[?match(@.b, "[jk]")] + {"b": "j"}
{"b": "k"}
+ $['a'][6]
$['a'][7]
Array value regular expression match
+ $.a[?search(@.b, "[jk]")] + {"b": "j"}
{"b": "k"}
{"b": "kilo"}
+ $['a'][6]
$['a'][7]
$['a'][9]
Array value regular expression search
+ $.o[?@>1 && @<4] + 2
3
+ $['o']['q']
$['o']['r']
Object value logical AND
+ $.o[?@>1 && @<4] + 3
2
+ $['o']['r']
$['o']['q']
Alternative result
+ $.o[?@.u || @.x] + {"u": 6} + $['o']['t']Object value logical OR
+ $.a[?@.b == $.x] + 3
5
1
2
4
6
+ $['a'][0]
$['a'][1]
$['a'][2]
$['a'][3]
$['a'][4]
$['a'][5]
Comparison of queries with no values
+ $.a[?@ == @] + 3
5
1
2
4
6
{"b": "j"}
{"b": "k"}
{"b": {}}
{"b": "kilo"}
+ $['a'][0]
$['a'][1]
$['a'][2]
$['a'][3]
$['a'][4]
$['a'][5]
$['a'][6]
$['a'][7]
$['a'][8]
$['a'][9]
Comparisons of primitive and of structured values
+ The example above with the query $.o[?@<3, ?@<3] shows that a filter selector may produce nodelists in distinct +orders each time it appears in the child segment. +
+
+
+
+ Function Extensions + Beyond the filter expression functionality defined in the preceding +subsections, JSONPath defines an extension point that can be used to +add filter expression functionality: "Function Extensions". + This section defines the extension point and some function +extensions that use this extension point. +While these mechanisms are designed to use the extension point, +they are an integral part of the JSONPath specification and are +expected to be implemented like any other integral part of this +specification. + A function extension defines a registered name (see ) that +can be applied to a sequence of zero or more arguments, producing a +result. Each registered function name is unique. + A function extension MUST be defined such that its evaluation is +free of side effects, i.e., all possible orders of evaluation and choices +of short-circuiting or full evaluation of an expression containing it +MUST lead to the same result. +(Note: Memoization or logging are not side effects in this sense +as they are visible at the implementation level only -- they do not +influence the result of the evaluation.) + + Any function expressions in a query must be well-formed (by conforming to the above ABNF) +and well-typed; +otherwise, the JSONPath implementation MUST raise an error +(see ). +To define which function expressions are well-typed, +a type system is first introduced. +
+ Type System for Function Expressions + Each parameter and the result of a function extension must have a declared type. + Declared types enable checking a JSONPath query for well-typedness +independent of any query argument the JSONPath query is applied to. + defines the available types in terms of the instances they contain. + + Function Extension Type System + + + + + + + + + + + + + + + + + + + + +
TypeInstances
+ ValueTypeJSON values or Nothing
+ LogicalType + LogicalTrue or LogicalFalse
+ NodesTypeNodelists
+ Notes: +
    +
  • The only instances that can be directly represented in JSONPath syntax are certain JSON values +in ValueType expressed as literals (which, in JSONPath, are limited to primitive values).
  • +
  • The special result Nothing represents the absence of a JSON value and is distinct from any JSON value, including null.
  • +
  • + LogicalTrue and LogicalFalse are unrelated to the JSON values expressed by the +literals true and false.
  • +
+
+
+ Type Conversion + Just as queries can be used in logical expressions by testing for the +existence of at least one node (), a function expression of +declared type NodesType can be used as a function argument for a +parameter of declared type LogicalType, with the equivalent conversion rule: +
    +
  • If the nodelist contains one or more nodes, the conversion result is LogicalTrue.
  • +
  • If the nodelist is empty, the conversion result is LogicalFalse.
  • +
+ Notes: +
    +
  • Extraction of a value from a nodelist can be performed in several +ways, so an implicit conversion from NodesType to ValueType +may be surprising and has therefore not been defined.
  • +
  • A function expression with a declared type of NodesType can +indirectly be used as an argument for a parameter of declared type +ValueType by wrapping the expression in a call to a function extension, +such as value() (see ), +that takes a parameter of type NodesType and returns a +result of type ValueType.
  • +
+ The well-typedness of function expressions can now be defined in terms of this type system. +
+
+ Well-Typedness of Function Expressions + For a function expression to be well-typed: +
    +
  1. Its declared type must be well-typed in the context in which it occurs. +As per the grammar, a function expression can occur in three different +immediate contexts, which lead to the following conditions for well-typedness: +
    +
    As a test-expr in a logical expression:
    +
    + The function's declared result type is LogicalType or +(giving rise to conversion as per ) NodesType. +
    +
    As a comparable in a comparison:
    +
    + The function's declared result type is ValueType. +
    +
    As a function-argument in another function expression:
    +
    + The function's declared result type fulfills the following rules for +the corresponding parameter of the enclosing function. +
    +
    +
  2. +
  3. Its arguments must be well-typed for the declared type of the corresponding parameters. + The arguments of the function expression are well-typed when +each argument of the function can be used for the declared type of the +corresponding parameter, according to one of the following +conditions: +
      +
    • When the argument is a function expression with the same declared result type as the +declared type of the parameter.
    • +
    • + When the declared type of the parameter is LogicalType and the argument is one of the following: + +
        +
      • A function expression with declared result type NodesType. +In this case, the argument is converted to LogicalType as per .
      • +
      • A logical-expr that is not a function expression.
      • +
      +
    • +
    • When the declared type of the parameter is NodesType and the argument is a query +(which includes singular query).
    • +
    • + When the declared type of the parameter is ValueType and the argument is one of the following: + +
        +
      • A value expressed as a literal.
      • +
      • + A singular query. In this case: + +
          +
        • If the query results in a nodelist consisting of a single node, the +argument is the value of the node.
        • +
        • If the query results in an empty nodelist, the argument is +the special result Nothing.
        • +
        +
      • +
      +
    • +
    +
  4. +
+
+
+ length() Function Extension +
+
Parameters:
+
+
  1. + ValueType
  2. +
+
+
Result:
+
+ ValueType (unsigned integer or Nothing) +
+
+ The length() function extension provides a way to compute the length +of a value and make that available for further processing in the +filter expression: + = 5] +]]> + Its only argument is an instance of ValueType (possibly taken from a +singular query, as in the example above). The result is also an +instance of ValueType: an unsigned integer or the special result Nothing. +
    +
  • If the argument value is a string, the result is the number of +Unicode scalar values in the string.
  • +
  • If the argument value is an array, the result is the number of +elements in the array.
  • +
  • If the argument value is an object, the result is the number of +members in the object.
  • +
  • For any other argument value, the result is the special result Nothing.
  • +
+
+
+ count() Function Extension +
+
Parameters:
+
+
  1. + NodesType
  2. +
+
+
Result:
+
+ ValueType (unsigned integer) +
+
+ The count() function extension provides a way to obtain the number of +nodes in a nodelist and make that available for further processing in +the filter expression: + = 5] +]]> + Its only argument is a nodelist. +The result is a value (an unsigned integer) that gives the number of +nodes in the nodelist. +Notes: +
    +
  • There is no deduplication of the nodelist.
  • +
  • The number of nodes in the nodelist is counted independent of their +values or any children they may have, e.g., the count of a non-empty +singular nodelist such as count(@) is always 1.
  • +
+
+
+ match() Function Extension +
+
Parameters:
+
+
  1. + ValueType (string)
  2. +
  3. + ValueType (string conforming to )
  4. +
+
+
Result:
+
+ LogicalType +
+
+ The match() function extension provides a way to check whether (the +entirety of; see ) a given +string matches a given regular expression, which is in the form described in . + + Its arguments are instances of ValueType (possibly taken from a +singular query, as for the first argument in the example above). +If the first argument is not a string or the second argument is not a +string conforming to , the result is LogicalFalse. +Otherwise, the string that is the first argument is matched against +the I-Regexp contained in the string that is the second argument; +the result is LogicalTrue if the string matches the I-Regexp and is +LogicalFalse otherwise. +
+
+ search() Function Extension +
+
Parameters:
+
+
  1. + ValueType (string)
  2. +
  3. + ValueType (string conforming to )
  4. +
+
+
Result:
+
+ LogicalType +
+
+ The search() function extension provides a way to check whether a +given string contains a substring that matches a given regular +expression, which is in the form described in . + + Its arguments are instances of ValueType (possibly taken from a +singular query, as for the first argument in the example above). +If the first argument is not a string or the second argument is not a +string conforming to , the result is LogicalFalse. +Otherwise, the string that is the first argument is searched for a +substring that matches the I-Regexp contained in the string +that is the second argument; the result is LogicalTrue if at +least one such substring exists and is LogicalFalse otherwise. +
+
+ value() Function Extension +
+
Parameters:
+
+
  1. + NodesType
  2. +
+
+
Result:
+
+ ValueType +
+
+ The value() function extension provides a way to convert an instance of NodesType to a value and +make that available for further processing in the filter expression: + + Its only argument is an instance of NodesType (possibly taken from a +filter-query, as in the example above). The result is an +instance of ValueType. +
    +
  • If the argument contains a single node, the result is +the value of the node.
  • +
  • If the argument is the empty nodelist or contains multiple nodes, the +result is Nothing.
  • +
+ Note: A singular query may be used anywhere where a ValueType is expected, +so there is no need to use the value() function extension with a singular query. +
+
+ Examples + + Function Expression Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryComment
+ $[?length(@) < 3]well-typed
+ $[?length(@.*) < 3]not well-typed since @.* is a non-singular query
+ $[?count(@.*) == 1]well-typed
+ $[?count(1) == 1]not well-typed since 1 is not a query or function expression
+ $[?count(foo(@.*)) == 1]well-typed, where foo() is a function extension with a parameter of type NodesType and result type NodesType
+ $[?match(@.timezone, 'Europe/.*')]well-typed
+ $[?match(@.timezone, 'Europe/.*') == true]not well-typed as LogicalType may not be used in comparisons
+ $[?value(@..color) == "red"]well-typed
+ $[?value(@..color)]not well-typed as ValueType may not be used in a test expression
+ $[?bar(@.a)]well-typed for any function bar() with a parameter of any declared type and result type LogicalType
+ $[?bnl(@.*)]well-typed for any function bnl() with a parameter of declared type NodesType or LogicalType and result type LogicalType
+ $[?blt(1==1)]well-typed, where blt() is a function with a parameter of declared type LogicalType and result type LogicalType
+ $[?blt(1)]not well-typed for the same function blt(), as 1 is not a query, logical-expr, or function expression
+ $[?bal(1)]well-typed, where bal() is a function with a parameter of declared type ValueType and result type LogicalType
+
+
+
+ Segments + For each node in an input nodelist, +segments apply one or more selectors to the node and concatenate the +results of each selector into per-input-node nodelists, which are then +concatenated in the order of the input nodelist to form a single +segment result nodelist. + It turns out that the more segments there are in a query, the greater the depth in the input value of the +nodes of the resultant nodelist: +
    +
  • A query with N segments, where N >= 0, produces a nodelist +consisting of nodes at depth in the input value of N or greater.
  • +
  • A query with N segments, where N >= 0, all of which are child segments, +produces a nodelist consisting of nodes precisely at depth N in the input value.
  • +
+ There are two kinds of segments: child segments and descendant segments. + + The syntax and semantics of each kind of segment are defined below. +
+ Child Segment +
+ Syntax + The child segment consists of a non-empty, comma-separated +sequence of selectors enclosed in square brackets. + Shorthand notations are also provided for when there is a single +wildcard or name selector. + + .*, a child-segment directly built from a wildcard-selector, is +shorthand for [*]. + .<member-name>, a child-segment built from a + member-name-shorthand, is shorthand for ['<member-name>']. +Note: This can only be used with member names that are composed of certain +characters, as specified in the ABNF rule member-name-shorthand. +Thus, for example, $.foo.bar is shorthand for $['foo']['bar'] (but not for $['foo.bar']). +
+
+ Semantics + A child segment contains a sequence of selectors, each of which +selects zero or more children of the input value. + Selectors of different kinds may be combined within a single child segment. + For each node in the input nodelist, +the resulting nodelist of a child segment is the concatenation of +the nodelists from each of its selectors in the order that the selectors +appear in the list. +Note: Any node matched by more than one selector is kept +as many times in the nodelist. + Where a selector can produce a nodelist in more than one possible order, +each occurrence of the selector in the child segment + may produce a nodelist in a distinct order. + In summary, a child segment drills down one more level into the structure of the input value. +
+
+ Examples + JSON: + + Queries: + + Child Segment Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $[0, 3] + "a"
"d"
+ $[0]
$[3]
Indices
+ $[0:2, 5] + "a"
"b"
"f"
+ $[0]
$[1]
$[5]
Slice and index
+ $[0, 0] + "a"
"a"
+ $[0]
$[0]
Duplicated entries
+
+
+
+ Descendant Segment +
+ Syntax + The descendant segment consists of a double dot .. +followed by a child segment (using bracket notation). + Shorthand notations are also provided that correspond to the shorthand forms of the child segment. + + ..*, the descendant-segment directly built from a +wildcard-selector, is shorthand for ..[*]. + ..<member-name>, a descendant-segment built from a +member-name-shorthand, is shorthand for ..&wj;['<member-name>']. +Note: As with the similar shorthand of a child-segment, this can +only be used with member names that are composed of certain +characters, as specified in the ABNF rule member-name-shorthand. + Note: On its own, .. is not a valid segment. +
+
+ Semantics + A descendant segment produces zero or more descendants of an input value. + For each node in the input nodelist, +a descendant selector visits the input node and each of +its descendants such that: +
    +
  • nodes of any array are visited in array order, and
  • +
  • nodes are visited before their descendants.
  • +
+ The order in which the children of an object are visited is not stipulated, since +JSON objects are unordered. + Suppose the descendant segment is of the form ..&wj;[<selectors>] (after converting any shorthand +form to bracket notation), +and the nodes, in the order visited, are D1, ..., Dn (where n >= 1). +Note: D1 is the input value. + For each i such that 1 <= i <= n, the nodelist Ri is defined to be a result of applying +the child segment [<selectors>] to the node Di. + For each node in the input nodelist, +the result of the descendant segment is the concatenation of R1, +..., Rn (in that order). +These results are then concatenated in input nodelist order to form +the result of the segment. + In summary, a descendant segment drills down one or more levels into the structure of each input value. +
+
+ Examples + JSON: + + Queries: + (Note that the fourth example can be expressed in two equivalent +queries, shown in in one table row instead of two almost-identical rows.) + + Descendant Segment Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $..j + 1
4
+ $['o']['j']
$['a'][2][0]['j']
Object values
+ $..j + 4
1
+ $['a'][2][0]['j']
$['o']['j']
Alternative result
+ $..[0] + 5
{"j": 4}
+ $['a'][0]
$['a'][2][0]
Array values
+ $..[*]
or
$..*
+ {"j": 1, "k": 2}
[5, 3, [{"j": 4}, {"k": 6}]]
1
2
5
3
[{"j": 4}, {"k": 6}]
{"j": 4}
{"k": 6}
4
6
+ $['o']
$['a']
$['o']['j']
$['o']['k']
$['a'][0]
$['a'][1]
$['a'][2]
$['a'][2][0]
$['a'][2][1]
$['a'][2][0]['j']
$['a'][2][1]['k']
All values
+ $..o + {"j": 1, "k": 2} + $['o']Input value is visited
+ $.o..[*, *] + 1
2
2
1
+ $['o']['j']
$['o']['k']
$['o']['k']
$['o']['j']
Non-deterministic ordering
+ $.a..[0, 1] + 5
3
{"j": 4}
{"k": 6}
+ $['a'][0]
$['a'][1]
$['a'][2][0]
$['a'][2][1]
Multiple segments
+ Note: The ordering of the results for the $..[*] and $..* examples above is not guaranteed, except that: +
    +
  • + {"j": 1, "k": 2} must appear before 1 and 2,
  • +
  • + [5, 3, [{"j": 4}, {"k": 6}]] must appear before 5, 3, and [{"j": 4}, {"k": 6}],
  • +
  • + 5 must appear before 3, which must appear before [{"j": 4}, {"k": 6}],
  • +
  • + 5 and 3 must appear before {"j": 4}, 4, {"k": 6}, and 6,
  • +
  • + [{"j": 4}, {"k": 6}] must appear before {"j": 4} and {"k": 6},
  • +
  • + {"j": 4} must appear before {"k": 6},
  • +
  • + {"k": 6} must appear before 4, and
  • +
  • + 4 must appear before 6.
  • +
+ The example above with the query $.o..[*, *] shows that a selector may produce nodelists in distinct orders +each time it appears in the descendant segment. + The example above with the query $.a..[0, 1] shows that the child segment [0, 1] is applied to each node +in turn (rather than the nodes being visited once per selector, which is the case for some JSONPath implementations +that do not conform to this specification). +
+
+
+
+ Semantics of null + Note: JSON null is treated the same as any other JSON value, i.e., it is not taken to mean "undefined" or "missing". +
+ Examples + JSON: + + Queries: + + Examples Involving (or Not Involving) null + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QueryResultResult PathsComment
+ $.a + null + $['a']Object value
+ $.a[0] + null used as array
+ $.a.d + null used as object
+ $.b[0] + null + $['b'][0]Array value
+ $.b[*] + null + $['b'][0]Array value
+ $.b[?@] + null + $['b'][0]Existence
+ $.b[?@==null] + null + $['b'][0]Comparison
+ $.c[?@.d==null] Comparison with "missing" value
+ $.null + 1 + $['null']Not JSON null at all, just a member name string
+
+
+
+ Normalized Paths + A Normalized Path is a unique representation of the location of a node in a value that +uniquely identifies the node in the value. +Specifically, a Normalized Path is a JSONPath query with restricted syntax (defined below), +e.g., $['book'][3], which when applied to the value, results in a nodelist consisting +of just the node identified by the Normalized Path. +Note: A Normalized Path represents the identity of a node in a specific value. +There is precisely one Normalized Path identifying any particular node in a value. + A nodelist may be represented compactly in JSON as an array of strings, where the strings are +Normalized Paths. + Normalized Paths provide a predictable format that simplifies testing and post-processing +of nodelists, e.g., to remove duplicate nodes. +Normalized Paths are used in this document as result paths in examples. + Normalized Paths use the canonical bracket notation, rather than dot notation. + Single quotes are used in Normalized Paths to delimit string member names. This reduces the +number of characters that need escaping when Normalized Paths appear in +strings delimited by double quotes, e.g., in JSON texts. + Certain characters are escaped in Normalized Paths in one and only one way; all other + characters are unescaped. + + + Since there can only be one Normalized Path identifying a given node, the syntax +stipulates which characters are escaped and which are not. +So the definition of normal-hexchar is designed for hex escaping of characters +that are not straightforwardly printable, for example, U+000B LINE TABULATION, but +for which no standard JSON escape, such as \n, is available. +
+ Examples + + Normalized Path Examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathNormalized PathComment
+ $.a + $['a']Object value
+ $[1] + $[1]Array index
+ $[-3] + $[2]Negative array index for an array of length 5
+ $.a.b[1:2] + $['a']['b'][1]Nested structure
+ $["\u000B"] + $['\u000b']Unicode escape
+ $["\u0061"] + $['a']Unicode character
+
+
+
+
+ + IANA Considerations +
+ Registration of Media Type application/jsonpath + IANA has registered the following media type : +
+
Type name:
+
+ application +
+
Subtype name:
+
+ jsonpath +
+
Required parameters:
+
+ N/A +
+
Optional parameters:
+
+ N/A +
+
Encoding considerations:
+
+ binary (UTF-8) +
+
Security considerations:
+
+ See the Security Considerations section of RFC 9535. +
+
Interoperability considerations:
+
+ N/A +
+
Published specification:
+
+ RFC 9535 +
+
Applications that use this media type:
+
+ Applications that need to convey queries in JSON data +
+
Fragment identifier considerations:
+
+ N/A +
+
Additional information:
+

+
+
Deprecated alias names for this type:
+
+ N/A +
+
Magic number(s):
+
+ N/A +
+
File extension(s):
+
+ N/A +
+
Macintosh file type code(s):
+
+ N/A +
+
+
+
Person & email address to contact for further information:
+
iesg@ietf.org
+
Intended usage:
+
+ COMMON +
+
Restrictions on usage:
+
+ N/A +
+
Author:
+
+ JSONPath WG +
+
Change controller:
+
+ IETF +
+
+
+
+ Function Extensions Subregistry + Per this specification, IANA has created a new "Function Extensions" subregistry in +a new "JSONPath" registry. The "Function Extensions" subregistry has the policy "Expert Review" +(). + The experts are instructed to be frugal in the allocation of function +extension names that are suggestive of generally applicable semantics, +keeping them in reserve for functions that are likely to enjoy wide +use and can make good use of their conciseness. +The expert is also instructed to direct the registrant to provide a +specification () but can make exceptions, +for instance, when a specification is not available at the time of +registration but is likely forthcoming. +If the expert becomes aware of function extensions that are deployed and +in use, they may also initiate a registration on their own if +they deem such a registration can avert potential future collisions. + Each entry in the subregistry must include the following: +
+
Function Name:
+
+ A lowercase ASCII string that starts with a letter and can +contain letters, digits, and underscore characters afterwards +([a-z][_a-z0-9]*). No other entry in the subregistry can have the +same function name. +
+
Brief description:
+
+ A brief description +
+
Parameters:
+
+ A comma-separated list of zero or more declared types, one for each of the +arguments expected for this function extension +
+
Result:
+
+ The declared type of the result for this function extension +
+
Change Controller:
+
+ See . +
+
Reference:
+
+ A reference document that provides a description of the function +extension +
+
+ The initial entries in this subregistry are listed in ; the +entries in the "Change Controller" column all have the value "IETF", +and the entries in the +"Reference" column all have the value " of RFC 9535": + + Initial Entries in the Function Extensions Subregistry + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function NameBrief DescriptionParametersResult
lengthlength of string, array, or object + ValueType + ValueType
countsize of nodelist + NodesType + ValueType
matchregular expression full match + ValueType, ValueType + LogicalType
searchregular expression substring match + ValueType, ValueType + LogicalType
valuevalue of the single node in nodelist + NodesType + ValueType
+
+
+
+ Security Considerations + Security considerations for JSONPath can stem from: +
    +
  • attack vectors on JSONPath implementations,
  • +
  • attack vectors on how JSONPath queries are formed, and
  • +
  • the way JSONPath is used in security-relevant mechanisms.
  • +
+
+ Attack Vectors on JSONPath Implementations + Historically, JSONPath has often been implemented by feeding parts of +the query to an underlying programming language engine, e.g., +JavaScript's eval() function. +This approach is well known to lead to injection attacks and would +require perfect input validation to prevent these attacks (see + for similar considerations for JSON itself). +Instead, JSONPath implementations need to implement the entire syntax +of the query without relying on the parsers of programming language +engines. + Attacks on availability may attempt to trigger unusually expensive +runtime performance exhibited by certain implementations in certain +cases. +(See for issues in hash-table implementations +and for performance issues in regular +expression implementations.) +Implementers need to be aware that good average performance is not +sufficient as long as an attacker can choose to submit specially +crafted JSONPath queries or query arguments that trigger surprisingly high, possibly +exponential, CPU usage or, for example, via a naive recursive implementation of the descendant segment, +stack overflow. Implementations need to have appropriate resource management +to mitigate these attacks. +
+
+ Attack Vectors on How JSONPath Queries Are Formed + JSONPath queries are often not static but formed from variables that +provide index values, member names, or values to compare with in a +filter expression. +These variables need to be validated (e.g., only allowing specific constructs +such as .name to be formed when the given values allow that) and translated +(e.g., by escaping string delimiters). +Not performing these validations and translations correctly can lead to unexpected +failures, which can lead to availability, confidentiality, and +integrity breaches, in particular, if an adversary has control over the +values (e.g., by entering them into a web form). +The resulting class of attacks, injections (e.g., SQL injections), +is consistently found among the top causes of application security +vulnerabilities and requires particular attention. +
+
+ Attacks on Security Mechanisms That Employ JSONPath + Where JSONPath is used as a part of a security mechanism, attackers +can attempt to provoke unexpected or unpredictable behavior or +take advantage of differences in behavior between JSONPath implementations. + Unexpected or unpredictable behavior can arise from a query argument with certain +constructs described as unpredictable by . +Predictable behavior can be expected, except in relation to the ordering +of objects, for any query argument conforming with . + Other attacks can target the behavior of underlying technologies, such as UTF-8 (see +) and the Unicode character set. +
+
+
+ + + + References + + Normative References + + + + + + + + + + + + + + + The Unicode® Standard + + The Unicode Consortium + + + At the time of writing, . + + + + + + + + Informative References + + + + JSONPath Comparison + + Thoughtworks + + + + + + + + + JSONPath - XPath for JSON + + Fachhochschule Dortmund + + + + + + + + XML Path Language (XPath) 2.0 (Second Edition) + + + + + + + + + + + + + + + Information technology - ECMAScript for XML (E4X) specification + + ISO + + + + + Withdrawn + An equivalent specification, also withdrawn, is available from . + + + + + Slice notation + + + + + + commit 82f95b4 + + + + + ECMAScript Language Specification + + ECMA International + + + + Standard ECMA-262, Third Edition + + + + + + + Boolean algebra: Laws + + + + + + + + +
+ Collected ABNF Grammars + This appendix collects the ABNF grammar from the ABNF passages used +throughout the document. + + + + + + contains the collected ABNF grammar that defines the +syntax of a JSONPath query. +
+ Collected ABNF of JSONPath Queries + =" / + "<" / ">" + +singular-query = rel-singular-query / abs-singular-query +rel-singular-query = current-node-identifier singular-query-segments +abs-singular-query = root-identifier singular-query-segments +singular-query-segments = *(S (name-segment / index-segment)) +name-segment = ("[" name-selector "]") / + ("." member-name-shorthand) +index-segment = "[" index-selector "]" +number = (int / "-0") [ frac ] [ exp ] ; decimal number +frac = "." 1*DIGIT ; decimal fraction +exp = "e" [ "-" / "+" ] 1*DIGIT ; decimal exponent +true = %x74.72.75.65 ; true +false = %x66.61.6c.73.65 ; false +null = %x6e.75.6c.6c ; null +function-name = function-name-first *function-name-char +function-name-first = LCALPHA +function-name-char = function-name-first / "_" / DIGIT +LCALPHA = %x61-7A ; "a".."z" + +function-expr = function-name "(" S [function-argument + *(S "," S function-argument)] S ")" +function-argument = literal / + filter-query / ; (includes singular-query) + logical-expr / + function-expr +segment = child-segment / descendant-segment +child-segment = bracketed-selection / + ("." + (wildcard-selector / + member-name-shorthand)) + +bracketed-selection = "[" S selector *(S "," S selector) S "]" + +member-name-shorthand = name-first *name-char +name-first = ALPHA / + "_" / + %x80-D7FF / + ; skip surrogate code points + %xE000-10FFFF +name-char = name-first / DIGIT + +DIGIT = %x30-39 ; 0-9 +ALPHA = %x41-5A / %x61-7A ; A-Z / a-z +descendant-segment = ".." (bracketed-selection / + wildcard-selector / + member-name-shorthand) +]]> +
+ contains the collected ABNF grammar that +defines the syntax of a JSONPath Normalized Path while also using the rules +root-identifier, ESC, DIGIT, and DIGIT1 from . +
+ Collected ABNF of JSONPath Normalized Paths + +
+
+
+ Inspired by XPath + This appendix is informative. + At the time JSONPath was invented, XML was noted for the availability of +powerful tools to analyze, transform, and selectively extract data from +XML documents. + is one of these tools. + In 2007, the need for something solving the same class of problems for +the emerging JSON community became apparent, specifically for: +
    +
  • finding data interactively and extracting them out of +JSON values without special scripting and
  • +
  • specifying the relevant parts of the JSON data in a request by a +client, so the server can reduce the amount of data in its response, +minimizing bandwidth usage.
  • +
+ (Note: XPath has evolved since 2007, and recent versions even +nominally support operating inside JSON values. +This appendix only discusses the more widely used version of XPath +that was available in 2007.) + JSONPath picks up the overall feeling of XPath but maps the concepts +to syntax (and partially semantics) that would be familiar to someone +using JSON in a dynamic language. + For example, in popular dynamic programming languages such as JavaScript, +Python, and PHP, the semantics of the XPath expression: + + can be realized in the expression: + + or in bracket notation: + + with the variable x holding the query argument. + The JSONPath language was designed to: +
    +
  • be naturally based on those language characteristics,
  • +
  • cover only the most essential parts of XPath 1.0,
  • +
  • be lightweight in code size and memory consumption, and
  • +
  • be runtime efficient.
  • +
+
+ JSONPath and XPath + JSONPath expressions apply to JSON values in the same way +as XPath expressions are used in combination with an XML document. +JSONPath uses $ to refer to the root node of the query argument, similar +to XPath's / at the front. +JSONPath expressions move further down the hierarchy using dot notation +($.store.book[0].title) +or the bracket notation +($['store']['book'][0]['title']); both replace XPath's / within query expressions, where dot notation serves as a lightweight but limited syntax while bracket notation is a +heavyweight but more general syntax. + Both JSONPath and XPath use * for a wildcard. +JSONPath's descendant segment notation, starting with .., borrowed from , is similar to XPath's //. +The array slicing construct [start:end:step] is unique to JSONPath, +inspired by from ECMASCRIPT 4. + Filter expressions are supported via the syntax ?<logical-expr> as in: + + extends by providing a comparison +with similar XPath concepts. + + XPath Syntax Compared to JSONPath + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XPathJSONPathDescription
+ / + $the root XML element
+ . + @the current XML element
+ / + . or []child operator
+ ..n/aparent operator
+ // + ..name, ..&wj;[index], ..*, or ..[*]descendants (JSONPath borrows this syntax from E4X)
+ * + *wildcard: All XML elements regardless of their names
+ @n/aattribute access: JSON values do not have attributes
+ [] + []subscript operator used to iterate over XML element collections and for predicates
+ | + [,]Union operator (results in a combination of node sets); called list operator in JSONPath, allows combining member names, array indices, and slices
n/a + [start:end:step]array slice operator borrowed from ES4
+ [] + ?applies a filter (script) expression
seamlessn/aexpression engine
+ ()n/agrouping
+For further illustration, shows some XPath expressions +and their JSONPath equivalents. + + Example XPath Expressions and Their JSONPath Equivalents + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XPathJSONPathResult
+ /store/book/author + $.store.book[*].authorthe authors of all books in the store
+ //author + $..authorall authors
+ /store/* + $.store.*all things in store, which are some books and a red bicycle
+ /store//price + $.store..pricethe prices of everything in the store
+ //book[3] + $..book[2]the third book
+ //book[last()] + $..book[-1]the last book in order
+ //&wj;book[position()<3] + $..book[0,1]
$..book[:2]
the first two books
+ //book[isbn] + $..book[?@.isbn]filter all books with an ISBN number
+ //book[price<10] + $..book[?@.price<10]filter all books cheaper than 10
+ //* + $..*all elements in an XML document; all member values and array elements contained in input value
+ XPath has a lot more functionality (location paths in unabbreviated syntax, +operators, and functions) than listed in this comparison. Moreover, there are +significant differences in how the subscript operator works in XPath and +JSONPath: +
    +
  • Square brackets in XPath expressions always operate on the node +set resulting from the previous path fragment. Indices always start +at 1.
  • +
  • With JSONPath, square brackets operate on each of the nodes in the nodelist +resulting from the previous query segment. Array indices always start +at 0.
  • +
+
+
+
+ JSON Pointer + This appendix is informative. + In relation to JSON Pointer , JSONPath is not intended as a replacement but as a more powerful +companion. The purposes of the two standards +are different. + JSON Pointer is for identifying a single value within a JSON value whose +structure is known. + JSONPath can identify a single value within a JSON value, for example, by +using a Normalized Path. But JSONPath is also a query syntax that can be used +to search for and extract multiple values from JSON values whose structure +is known only in a general way. + A Normalized JSONPath can be converted into a JSON Pointer by converting the syntax, +without knowledge of any JSON value. The inverse is not generally true, i.e., a numeric +reference token (path component) in a JSON Pointer may identify a member value of an object or an element of an array. +For conversion to a JSONPath query, knowledge of the structure of the JSON value is +needed to distinguish these cases. +
+
+ Acknowledgements + This document is based on 's +original online article defining JSONPath . +The books example was taken from course material that Bielefeld University, Germany used in 2002. + This work is indebted to for the superb +JSONPath comparison project that details the behavior of over forty JSONPath +implementations applied to numerous queries. +
+
+ Contributors + + InfluxData, Inc. +
+ + Pisa + Italy + + mmikulicic@gmail.com +
+
+ + TheSoul Publishing Ltd. +
+ + Limassol + Cyprus + + esurov.tsp@gmail.com +
+
+ + +
+ + Auckland + New Zealand + + gregsdennis@yahoo.com + https://github.com/gregsdennis +
+
+
+
+
diff --git a/draft-ietf-jsonpath-base.md b/draft-ietf-jsonpath-base.md index 8a460049..3d4ffdac 100644 --- a/draft-ietf-jsonpath-base.md +++ b/draft-ietf-jsonpath-base.md @@ -18,7 +18,7 @@ abbrev: JSONPath area: ART wg: JSONPath WG kw: JSON -date: 2023 +date: 2024 author: - @@ -449,7 +449,7 @@ $.store.book[?@.price < 10].title | `..name` | shorthand for `..['name']` | | `..*` | shorthand for `..[*]` | | `'name'` | [name selector](#name-selector): selects a named child of an object | -| `*` | [wildcard selector](#name-selector): selects all children of a node | +| `*` | [wildcard selector](#wildcard-selector): selects all children of a node | | `3` | [index selector](#index-selector): selects an indexed child of an array (from 0) | | `0:100:5` | [array slice selector](#slice): start:end:step for arrays | | `?` | [filter selector](#filter-selector): selects particular children using a logical expression |