Appendix B. Inspired by XPath
Appendix B. 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. [XPath] 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
[RFC8259] 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:
/store/book[1]/title
can be realized in the expression:
x.store.book[0].title
or in bracket notation:
x['store']['book'][0]['title']
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.
B.1. 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 [E4X], is similar to XPath's //. The array slicing construct [start:end:step] is unique to JSONPath, inspired by [SLICE] from ECMASCRIPT 4.
Filter expressions are supported via the syntax ?<logical-expr> as in:
$.store.book[[email protected] < 10].title
Table 20 extends Table 1 by providing a comparison with similar XPath concepts.
| XPath | JSONPath | Description | |
|---|---|---|---|
| / | $ | the root XML element | |
| . | @ | the current XML element | |
| / | . or [] | child operator | |
| .. | n/a | parent operator | |
| // | ..name, | descendants (JSONPath borrows | |
| ..[index], ..*, | this syntax from E4X) | ||
| or ..[*] | |||
| * | * | wildcard: All XML elements | |
| regardless of their names | |||
| @ | n/a | attribute 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 | |||
| seamless | n/a | expression engine | |
| () | n/a | grouping |
Table 20: XPath Syntax Compared to JSONPath
For further illustration, Table 21 shows some XPath expressions and their JSONPath equivalents.
| XPath | JSONPath | Result |
|---|---|---|
| /store/book/author | $.store.book[*].author | the authors |
| of all books | ||
| in the store | ||
| //author | $..author | all authors |
| /store/* | $.store.* | all things in |
| store, which | ||
| are some | ||
| books and a | ||
| red bicycle | ||
| /store//price | $.store..price | the prices of |
| everything in | ||
| the store | ||
| //book[3] | $..book[2] | the third |
| book | ||
| //book[last()] | $..book[-1] | the last book |
| in order | ||
| //book[position()<3] | $..book[0,1] | the first two |
| $..book[:2] | books | |
| //book[isbn] | $..book[[email protected]] | filter all |
| books with an | ||
| ISBN number | ||
| //book[price<10] | $..book[[email protected]<10] | filter all |
| books cheaper | ||
| than 10 | ||
| //* | $..* | all elements |
| in an XML | ||
| document; all | ||
| member values | ||
| and array | ||
| elements | ||
| contained in | ||
| input value |
Table 21: Example XPath Expressions and Their JSONPath Equivalents
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.