)-1]).  The well-formedness and the validity of JSONPath queries are independent of the JSON value the query is applied to; no further errors can be raised during application of the query to a value. string, "true", "false", "null").  Comparisons with complex values will fail, i.e. no selection occurs. <del> Types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. </del>  A member or element value by itself in a Boolean context is interpreted as "false" only if it does not exist.  Otherwise it is as an exception to the general rule -- also works with structured values. <del> Regular expression tests can be applied to "string" values only. </del>  Alphabetic characters in ABNF are case-insensitive, so "e" can be either "e" or "E".

Anything else we expect to merge for this I-D deadline? If not, I'd like to submit.
great ,,, thanks.
Issue 17 regular expressions in filters, which is supported by of JSONPath. This raises two questions: What is the precise syntax of regular expressions? How should be mitigated? One approach which addresses both these questions would be to adopt as discussed in , although not all languages may yet have support for RE2.
So you are saying JSONpath should only support regular expression literals, not strings with regular expressions.
Unfortunately, no, I'm saying that at the time I wrote that sentence, I had forgotten that Perl/Python/Ruby et al support variables inside the "/" delimiters. I wish I could interpret it the way you suggested.
Do you mean as in (1) interpolating variables into the RE () or (2) filling in variables with results of the RE scan ()? So far, I haven't seen any proposal for variables in the JSONPath expression language that could go into either place.
RE2 syntax would have the advantage that nobody of us likes it :-) But seriously, any RE syntax that is not already documented will need to be defined in the document. That leaves the ECMAscript syntax of the week or W3C XSD syntax. ECMAscript is a bit anemic but changes all the time. W3C XSD REs are exactly what would be needed here, but are not very popular.
NAME wrote: Perhaps an expression e.g. that evaluated to a string should be allowed within "/" delimiters. I haven't thought this through, I only have experience implementing it with character literals, and the only has character literals. I'll submit a pull request with JSONPath comparison with a match against an expression, to see what everybody else does.
I would prefer to restrict the right hand side of a regular expression match () to a literal regular expression. I might be persuaded that we should also allow a JSONPath expression which evaluates to a (single) literal regular expression. I really would like to avoid literal regular expressions that contain JSONPath expressions as that would mean not being able to reuse an existing regular expression syntax (such as RE2).
After giving this some thought, I agree. Introducing "/" delimiters for regular expressions suggests static "compilation" of the regular expression, as it does in perl/ruby/python. If in JSONPath we're applying a regular expression in a search of a million items, we wouldn't want the regular expression to depend on the data, as that would defeat the purpose of introducing the "/" delimiters in the first place. We wouldn't want to force implementations to "recompile" the regular expression every time the current node changed. Also, I don't think my speculation above about allowing inside "/" delimiters makes sense, as the symbols allowed within "/" delimiters are reserved for regular expression symbols. These observations are consistent with the implementation of the "~=" operator. In terms of functional requirements, regular expressions are very useful for search and filtering, but such expressions are generally statically known. I don't fully understand this sentence. JSONPath expressions don't produce character literals, character literals are a static concept. JSONPath expressions can produce strings, but that's not the same thing. The key feature of character literals is that they don't depend on the data, and in particular on the current node . I don't think anybody would propose that!
Well, then let me propose that :-) Building a RE out of data that has been found in the input is not that outlandish, I think. I’m not sure that we ultimately want to support that, but it is not something that is self-evidently excluded. Grüße, Carsten
Pardon my confusion, but what I had in mind was to allow the likes of where evaluates to a regular expression such as .
NAME wrote: One minor point, I believe it should say that it evaluates to a string , rather than character literals . Otherwise, I believe that that's technically sound, and permits an efficient implementation, in the sense of "compile" regular expression once and apply many times. And it's somewhat more likely that there is a regular expression to be found at an absolute location in the JSON document, as opposed to in all current nodes :-) I still think it's an unlikely user requirement. If you do become persuaded to support this syntax, it probably won't be because I've tried to persuade you.
The expression language could also contain something like URL, and it is likely to be helpful to compose the regular expression out of constant and variable (from input item) parts. What’s out there in today’s implementations? Grüße, Carsten
NAME wrote: As it turns out, no implementation supports terms in regular expressions.
I could get behind this. But I definitely wouldn't want to "construct" a RegEx from input data, as others have also been opposed to.
It would easy to come up with something, but I’d rather not invent something — if there is no current practice for this, we should not include it. Grüße, Carsten
Agree. Reminder: Charter says we're supposed to specify something "based on the common semantics and other aspects of existing implementations". So there's a judgment call to be made as to whether enough of them support a common regex that we can reasonably claim it constitutes "common semantics". My impression had been No, but it's months since I looked at the overlap chart.
I can tell you neither of mine support RegEx (one is obsolete now). But I'm open to adding it to the current one.
I would really wish support for regex, and honestly I think they are nearly a must. However I'm really worried about all the implications behind them. We are working hard for making sure that any future implementation is going to behave consistently with any other which follows our work. I'm worried that all the complexity and differences behind regex is going to reintroduce back all the discrepancies we are trying hard to remove. I think that If we wish any regex support we need to go for a regex syntax which is well specified and comonly implemented. Honestly I'm not happy with RE2 that has been mentioned before, as far as I know it is available to most of languages as a C library through bindings (bindings might be really problematic). For instance I wasn't happy with RE2 library while working with Erlang and Elixir, among all the reasons, using it would force my JSONPath implementation to depend on native code using a NIF while the whole library is 100% Elixir compiled into BEAM byte code. IMHO we might investigate a Perl-like or POSIX-like regex support (that are quite popular). But again we should avoid getting stuck into all the regex complexities. I have also some further points, questions and doubts: I think that regex should be supported only as a constant, therefore they must not be taken from a JSONPath evaluation result (e.g. disallow ). We might change idea on a future revision, but right now I'm worried that this might introduce further complexity, discrepancies and performance penalities (we can parse and compile the regex while parsing the JSONPath). are we going to treat regex as strings when using == comparison (e.g. is true when is ) or are we going to use any special type, therefore == will never be true when comparing with a string? should we raise a parsing time error if a ill-formed regex is provided (e.g. )?
My 2 ¢: Any RE syntax we decide to use will need to be thoroughly documented in JSONPath, except if it is one of the ECMAscript versions or W3C XSD syntax. (I do not really consider Posix a candidate, it is a bit anemic.) Of course, we don't need capture groups, global substitute, and can probably live without back references etc. That makes W3C XSD syntax my favorite, but it is also less widely implemented than others. It's 2021, so strings and REs will be Unicode text. Is it (1) string =~ RE, or (2) RE =~ string, or (3) both or even (4) both but with subtly different semantics (horror experience from the Ruby language)? That is a sensible approach. Unless there is a large installed base that depends on computed REs, I agree. We could make sure that a later extension can be added seamlessly. We have the luxury of being able to provide strong typing, so a RE literal should be a (syntax?) error except near a . Yes. If we can check a query before applying it to input, we should do that with failing fast.
I tried to query this example [1] using a JSONPath with a XSD regex I tried using (which is equivalent to ): Jayway: fails to understand it and returns a "bogus" result (but it doesn't fail with the "regular" regex) Personal opinion about XSD regex: I feel like that no implementation is supporting them (I'm not aware of any), I feel like that every implementation supports whatever the language provides as builtin regex implementation (which is likely far from XSD regex syntax). Please, let me know if any implementation is supporting that syntax. If none supports that syntax, are we really sure to go for a syntax that nobody is using? Furthermore I didn't find any online tool to test regex with XSD style, conversely, PCRE style regex are easy to test (this is not really encouraging). I also did few tests with some online test tools, following implementations just fail to understand any regex (I tried with "basic" syntax ): jsonpath-plus (javascript, 0.18.1) goessner: bogus result here, it replaces every title occurrence with -1 Personal opinion: previous results make me feel skeptic about the whole regex feature. Do we know which implementations are supporting regex? [1]:
As far as I know XPath/XQuery regex : I feel like there is a lack modern tooling for testing XML Schema flavor regex (outside XML schemas), and this might be quite frustrating for end users. By the way .
I did some further investigation into regex support (using cburgmer's tool and his implementations list). I usued a quite simple regex (JSON input was: and JSONPath was: ). They are supported by 11 implementations in 7 different languages [1], interestingly JavaScript implementations were not supporting it, and 3/4 of them were completely misbehaving [2]: JavaScript brunerd "matches" everything JavaScript Goessner and jsonpath-plus replace matches with -1 I'm worried that users might expect to use regex to reliably validate/filter out invalid inputs, but they get accepted anyway. Instead is not supported at all. Also I tested a XSD-like syntax, is supported by a further limited subset of implementations (5/11). [1] List of implementations supporting : C++ (1/1 implementation): jsoncons Go (2/6 implementations): URL URL Java (2/2 implementations): URL URL Objective-C (1/1 implementation): SMJJSONPath Ruby (1/1 implementation): jsonpath PHP (3/4 implementations): galbar-jsonpath remorhaz-jsonpath softcreatr-jsonpath dotNET (1/4 implementations): Json.NET [2] JavaScript misbehaving implementations: Goessner: [{"a": -1}, {"a": -1, "b": "s"}] brunerd: [{"a": "a"}, {"b": "s"}] jsonpath-plus: [{"a": -1}, {"a": -1, "b": "s"}]
Interesting. While it may be a bit early to actually decide anything about regular expressions, this also seems to show some differences in expression evaluation. Can you do a similar check with and ?
NAME it's fine. Let me know what kind of output are you looking for, so I can summarize it in a helpful way.
NAME what is your opinion about ECMA 262? All other things equal, and when it doesn't matter too much, I am strongly in favour of staying consistent with other standards, whether IETF recommendation or de facto standards such as JSON Schema. Daniel
... this might be a way to go. Sharing a small, well defined subset of with JSON Schema.
I think the purpose of the RFC is to give advice to implementers and users as to what works. It's very unlikely that any existing implementation will change its semantics because of our work - but new ones will follow it if we do a good job. So I'd like the RFC to say something like "Some implementations support regular expression filters in JSONPaths; maximum interoperability can be achieved by using subset $X." In particular, since regexes exhibit an 80/20 rule - you get 80% of the benefit with 20% of the features. Another reason a modest subset seems like a good idea for the JSONPath RFC.
Some historical context: JSON Schema specifies 262 because that was what was available when the feature was added. It maintains 262 because that's what implementations now support. I don't think this is cause enough for us to adopt it here. We should look at which RegEx specification serves our needs and use that. If it also happens to be 262, that's fine. On a side note of implementation support, neither of my implementations support RegEx, but I'm happy to add it. I expect other maintainers wouldn't complain about it if it became a requirement.
NAME The modest subset is what actually really works in a consistent manner: is supported by 100% implementations, and Goessner's article is enough for that (I believe that some "basic" features are not supported by every implementation just because they are incomplete implementations, so no RFC is going to fix an unfinished or unmaintained project). I don't see any useful reason about documenting just the "modest subset" (and I don't think it is worth it), also I think that is not compatible with our WG charter: I will quote Barry Leiba, that asked to change the original charter. The original charter: Barry Leiba: And the following has been proposed: Honestly what I found hard was taking decisions about quite commonly implemented "extensions" and a number of corner cases, and users love extensions (such as regex) because they find them useful. NAME however if you are willing to work on it, we might document a "JSONPath Core" subset, that can be safely used across implementations for portability reasons, and for transitional purposes, but I don't agree about just limiting to it. Sorry for the OT, let's continue the regex topic. Edit: I wrote a quick proposal that tries to match the 2 point of view I see here (and in other discussions): URL
Talking about regex: I think we should start again from requirements. I'll start with some of them: Good enough for matching URLs, domain names, mail addresses, IP addresses, UUIDs and all the stuff that people keep asking on stackoverflow Reasonable unicode support (it is 2021, honestly I rather not support them than supporting a limited version that is mostly good for Latin1).
I think we all agree: JSONPath must stipulate a regular expression syntax for use in filters, and it's not the role of JSONPath to define a new regular expression standard. Fortunately, there's a clean syntactic and semantic separation between JSONPath and regular expression (de facto or de jure) standards. I suggest we then stipulate RE2 for its security properties and unicode support (with "SHOULD" language) and allow for other regular expression standards (with "MAY" language). JSONPath implementations that share a regular expression standard will interoperate on JSONPaths involving regular expressions. JSONPath implementations which don't share a regular expression standard may or may not interoperate on particular JSONPaths, depending on the regular expressions used. In terms of compliance testing, it may be sufficient to include a few simple regular expressions which will work "everywhere".
I see your intent here, but I have to say that I'm not a fan of pure wrappers (especially as I work in .Net), and it seems that all of the implementations for RE2 are just wrappers for the C++ implementation. There are a lot of benefits to developers when a library is written in the language. I don't think we should ignore that. Let's make sure that is considered in this decision.
Go has RE2 built in (URL), but point taken. I agree that a wrapper is to be avoided, especially if it makes shipping a static binary impossible. Which other regex (de facto or de jure) standards support unicode?
It's 2021, so all (notable) RE standards support Unicode. I think, for once, recent drafts from json-URL got this right: Let's define a common subset, and reference that to an existing written up standard such as ECMAScript. (json-URL got the idea right, not necessarily the specific subset -- there is quite some fluff in that.) If nobody else wants, I'll do a PR with an ABNF definition of such a subset. We can then debate what to leave in/throw out/add.
Example that could be solved using RegEx.
Another on the usage of RegEx in filters.
I find it interesting that JMESPath does not support regular expressions in filters. See, for example, .
The discussion found in this issue pretty much is the reason why iregexp is the right approach. (The alternative, escaping into a platform-specific function, is not available for the present standardization effort.)
Is iregexp the right approach for JMESPath too? If so, I wonder if the JMESPath community would be interested in collaborating on iregexp?
We could ask! We can use all the help we can get.
Well, maybe I can get iregexp-02 out first...
Sounds good!
112 output:
Looks good now with the most recent changes. Thanks.

)-1]). <ins> To be valid, strings on the right hand side of the "=~" regex matching operator need to conform to I-D.draft-bormann-jsonpath- iregexp. </ins> The well-formedness and the validity of JSONPath queries are independent of the JSON value the query is applied to; no further errors can be raised during application of the query to a value. string, "true", "false", "null").  Comparisons with complex values will fail, i.e. no selection occurs.  <ins> Data types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. </ins> A member or element value by itself in a Boolean context is interpreted as "false" only if it does not exist.  Otherwise it is as an exception to the general rule -- also works with structured values.  <ins> The regular expressions in the string-literals on the right-hand side of "=~" are as defined in I-D.draft-bormann-jsonpath-iregexp. Regular expression tests can be applied to JSON string values (RFC8259) only (on the left-hand side of "=~"); they yield false otherwise. </ins> Alphabetic characters in ABNF are case-insensitive, so "e" can be either "e" or "E".


3.5.8. <del> The list selector allows combining member names, array indices, and slices in a single selector. Note: The list selector was called "union selector" in JSONPath-orig, as it was intended to solve use cases addressed by the union selector in XPath.  However, the term "union" has the connotation of a set operation that involves merging input sets while avoiding duplicates, so the concept was renamed into "list selector". </del> 3.5.8.1. <del> The list selector is syntactically related to the "index-selector" and the "slice-selector".  It contains two or more entries, separated by commas. 3.5.8.2. A list selector selects the nodes that are selected by at least one of the selector entries in the list and yields the concatenation of the lists (in the order of the selector entries) of nodes selected by the selector entries.  Note that any node selected in more than one of the selector entries is kept as many times in the node list. To be valid, integer values in the "element-index" and "slice-index" components MUST be in the I-JSON range of exact values, see synsem- overview. 3.5.9. 3.5.9.1. </del> The filter selector has the form "[?<expr>]".  It works via iterating over structured values, i.e. arrays and objects. precedence from highest (binds most tightly) to lowest (binds least tightly). <del> 3.5.9.2. </del>  The "filter-selector" works with arrays and objects exclusively.  Its result might be a list of Some examples:  3.6. A Normalized Path is a JSONPath with restricted syntax that

To do: [x] Consider reorganising selectors in section 3.3 to match the order of the document [x] Consider reorganising table 1 to match the order of the document Fixes URL
Reorganised selectors in section 3.3 to match the order of the document. Did not reorganise table 1 as it flows better as is.
Filter selectors should come before list selectors to avoid a forward reference. The following comment should be deleted: Also, as noted by NAME at today's interim WG meeting, we should factor out a separate production to avoid repeating here: and here: Possible names for this production: or .
I think we proposed something like ... and here: thanks.
(And once we are don't with this issue, we can reorder table 1. Not quite sure if we want to do this entirely in section order; let's see how that turns out first.)

3.5.8.  3.5.8.1.  The filter selector has the form "[?<expr>]".  It works via iterating over structured values, i.e. arrays and objects. precedence from highest (binds most tightly) to lowest (binds least tightly).  <ins> 3.5.8.2. </ins> The "filter-selector" works with arrays and objects exclusively.  Its result might be a list of Some examples: <ins> 3.5.9. The list selector allows combining member names, array indices, and slices in a single selector. Note: The list selector was called "union selector" in JSONPath-orig, as it was intended to solve use cases addressed by the union selector in XPath.  However, the term "union" has the connotation of a set operation that involves merging input sets while avoiding duplicates, so the concept was renamed into "list selector". 3.5.9.1. The list selector is syntactically related to the "index-selector" and the "slice-selector".  It contains two or more entries, separated by commas. 3.5.9.2. A list selector selects the nodes that are selected by at least one of the selector entries in the list and yields the concatenation of the lists (in the order of the selector entries) of nodes selected by the selector entries.  Note that any node selected in more than one of the selector entries is kept as many times in the node list. To be valid, integer values in the "element-index" and "slice-index" components MUST be in the I-JSON range of exact values, see synsem- overview. </ins> 3.6. A Normalized Path is a JSONPath with restricted syntax that


5. <del> This section gives security considerations, as required by RFC3552. </del>

Let's use this issue to capture possible items for the Security Considerations section of the spec. As discussed in URL, CPU exploits are possible using selectors such as: One mitigation would be to run the implementation in an environment, such as a Linux cgroup, which can restrict the CPU consumed.
NAME provided the following: A malicious user can submit a JSON object intended to cause explosive backtracking by a JSONPath implementation performing regular expression matching. This is known as a ReDOS [REDOS] attack. To defend against this attack, regular expressions in JSONPath filters SHOULD conform to RE2 syntax [RE2SYNTAX], which does not support backtracking. (but MAY not support "C" - move this to the filter section). Additionally, implementations SHOULD guarantee linear run time for regular expression matching, such as provided by the original RE2 library implementation [RE2IMPL] and Go's "regexp" library [GOREG]. [GOREG] The Go Authors, "Package regexp", January 2007, . [RE2IMPL] The RE2 Authors, "RE2", March 2010, . [RE2SYNTAX] The RE2 Authors, "Syntax", November 2014, . [REDOS] Crosby, SA. and DS. Wallach, "Denial of Service via Algorithmic Complexity Attacks (In "Proceedings of the 12th USENIX Security Symposium")", August 2003.
NAME suggested adding the following to the Security Considerations section: Eavesdropping, replay, message insertion, deletion, modification and man-in-the-middle attacks are considered out of scope for JSONPath. These attacks are relevant to a network protocol, but not to a query language.
Granted, but I'm not sure this would be in-scope for the RFC.
Agreed about specific solutions not being in scope for the RFC. At most, I think we can identify several potential risks, but: It should be stated that such a list of risks cannot be comprehensive. Solutions will be specific and relevant according to the implementation, and so should not be included. As an exaample of point 2, an implementation that is designed for applications that run on Windows obviously cannot run in Linux.
Would it be worth giving special consideration to concerns for JavaScript in the security considerations? RFC 8259 does this, and there are similar concerns for this document too. For instance, some naïve implementations of JSONPath in JavaScript could run into trouble with paths that refer to things like or that try to invoke special functions like (which you can trigger by concatenating any non-string value with a string). JavaScript is special here in that it's very popular and there is a very strong conventional representation for JSON data -- whatever returns -- and that representation can, if you naïvely fetch its attributes, start returning things that the programmer might not expect to be manipulating. It may be worth talking to seasoned JavaScript security practitioners if we want to make any comment on the perils of walking arbitrary properties of . I am not such a person.
It may be worth mentioning that the recursive descent operator is a possible security issue. Naïve implementations that simply recurse down the stack may be vulnerable to attack, and would likely fail suitably designed fuzzer tests. At the least, the specification should require a limit to the depth of recursion.
How big of JSON objects are we talking about here? It's not like GraphQL where you can actually have requests for circular data. JSON is most definitely finite, and surely other mechanisms, such as limits on request size (an application concern), would capture JSON objects large enough to cause recursion issues. Unless your available call stack is really small, I suppose. But environmental awareness seems like a concern of either the app or the implementation, not this spec.
We're talking about attack files that are specifically generated to exploit vulnerabilities. That's what fuzz testing is about, bombarding your function calls with simulated attack files on a continuous basis, to detect whether your API is vulnerable to malicious attackers. Recursive algorithms are a big source of security vulnerabilities. Daniel
We still have to write the Security Considerations section. (Some of this also goes into .)

5.  <ins> Security considerations for JSONPath can stem from attack vectors on JSONPath implementations, and the way JSONPath is used in security-relevant mechanisms. 5.1. Historically, JSONPath has often been implemented by feeding parts of the query to an underlying programming language engine, e.g., JavaScript.  This approach is well known to lead to injection attacks and would require perfect input validation to prevent these attacks (see RFC8259 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 RFC8949 for issues in hash-table implementations, and I- D.draft-bormann-jsonpath-iregexp 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 that trigger surprisingly high, possibly exponential, CPU usage. 5.2. Where JSONPath is used as a part of a security mechanism, attackers can attempt to evoke unexpected behavior, or take advantage of differences in behavior between JSONPath implementations. This also applies to underlying technologies such as UTF-8 (see RFC3629), the Unicode character set, and JSON.  A characteristic of JSON that can lead to varying results is the fact that JSON objects are unordered; therefore, the order in which results of a JSONPath query reflect the presence of JSON object members can vary with implementations. </ins>


Note: This ordering of the results for the "$..[*]" and "$..*" examples above is not guaranteed, except that: <del> "{o: {"j": 1, "k": 2}, a: [5, 3]}" must appear before "{"j": 1, "k": 2}" and "[5, 3]", </del>  "{"j": 1, "k": 2}" must appear before "1" and "2", of their element or member values then.  Applied to other value types, it will select nothing. <del> Some examples: </del>  3.5.9. components MUST be in the I-JSON range of exact values, see synsem- overview.  3.6. A Normalized Path is a JSONPath with restricted syntax that

Ref: URL
we need to discuss the descendant selector's behavior by including itself to the node list.
Yes. Let's do that in a PR for URL
yes ... it's illustratively shown, what a good thing inline examples are ...
Considering the following input: would evaluate to (in this case the values of the object): I would expect the descendant version: to evaluate to: Yet the example says: Considering the following pseudo logic: In the case of the would be an index wildcard selector. I would expect the descendant selector to (starting by selecting itself) walk through the json structure and select all the results by applying the child selector (dot-member-name, index-selector, index-wild-selector, or wildcard) on each traversed value. Am I misunderstanding something here or is this the intended behavior?
Thanks for raising this. When I was writing the example, I noticed that only a few implementations included the node itself. But the descendant selector semantics currently say: and so I included the "starting" node itself. This is why I included the following text in the commit message: The semantics section needs improving anyway to clarify the semantics of the various forms of the descendants selector. I agree with the semantics proposed above, providing there is a consensus for this in the WG.
In my understanding descendant selector simply extends the single-level operating of child selector , in that it further recursively operates on all other descendant levels. So I agree to Bram's traversal algorithm above. A node is not considered a descendant of itself. Obviously I have not been aware of this behavior.

Note: This ordering of the results for the "$..[*]" and "$..*" examples above is not guaranteed, except that:  <ins> "{"o": {"j": 1, "k": 2}, "a": [5, 3]}" must appear before "{"j": 1, "k": 2}" and "[5, 3]", </ins> "{"j": 1, "k": 2}" must appear before "1" and "2", of their element or member values then.  Applied to other value types, it will select nothing.  <ins> 3.5.8.3. JSON document: Queries: </ins> 3.5.9. components MUST be in the I-JSON range of exact values, see synsem- overview. <ins> 3.5.9.3. JSON document: Queries: </ins> 3.6. A Normalized Path is a JSONPath with restricted syntax that


Normalized Paths: "$[-3]", for example, is a Singular Path, but not a Normalized Path.  4. 4.1.

can only produce a singular result since the slice is equivalent to the index . Agreed?
In the first two examples, the Path and Normalized path are equivalent in what they identify. Not so for the third because the Path produces a plural result and thus cannot be normalized. This should probably be noted?

Normalized Paths: "$[-3]", for example, is a Singular Path, but not a Normalized Path. <ins> 3.6.1. </ins> 4. 4.1.


JSONPath allows the wildcard symbol "*" to select any member of an object or any element of an array (wildcard).  The descendant <del> operator ".." selects the node and all its descendants (descendant- selector).  The array slice syntax "[start:end:step]" allows selecting a regular selection of an element from an array, giving a start position, an end position, and possibly a step value that moves the position from the start to the end (slice). </del>  Filter expressions are supported via the syntax "?(<boolean expr>)" as in Array slice selector "[<start>:<end>:<step>]", where the optional values "<start>", "<end>", and "<step>" are integer literals. <del> Nested descendants selector "..". </del>  List selector "[<sel1>,<sel2>,...,<selN>]", holding a comma separated list of index and slice selectors. 3.5.7.2. <del> The "descendant-selector" selects the node and all its descendants. </del>  <del> In the resultant nodelist: * nodes occur before their children, and * nodes of an array occur in array order. </del>  Children of an object may occur in any order, since JSON objects are unordered. Queries: <del> Note: This ordering of the results for the "$..[*]" and "$..*" </del>  examples above is not guaranteed, except that: <del> "{"o": {"j": 1, "k": 2}, "a": [5, 3]}" must appear before "{"j": 1, "k": 2}" and "[5, 3]", </del> "{"j": 1, "k": 2}" must appear before "1" and "2", <del> "[5, 3]" must appear before "5" and "3", and </del>  <del> "5" must appear before "3". </del>  3.5.8.

Exclude the node itself Define the term "descendants" more precisely Define the descendant selector semantics more thoroughly Fixes: URL
I would consider adding two additional examples: given: results in: - and results in: - ] ]
I extended the existing example attempting to exhibit the same points as the example above.
Looks good, thanks!
Considering the following input: would evaluate to (in this case the values of the object): I would expect the descendant version: to evaluate to: Yet the example says: Considering the following pseudo logic: In the case of the would be an index wildcard selector. I would expect the descendant selector to (starting by selecting itself) walk through the json structure and select all the results by applying the child selector (dot-member-name, index-selector, index-wild-selector, or wildcard) on each traversed value. Am I misunderstanding something here or is this the intended behavior?
Thanks for raising this. When I was writing the example, I noticed that only a few implementations included the node itself. But the descendant selector semantics currently say: and so I included the "starting" node itself. This is why I included the following text in the commit message: The semantics section needs improving anyway to clarify the semantics of the various forms of the descendants selector. I agree with the semantics proposed above, providing there is a consensus for this in the WG.
In my understanding descendant selector simply extends the single-level operating of child selector , in that it further recursively operates on all other descendant levels. So I agree to Bram's traversal algorithm above. A node is not considered a descendant of itself. Obviously I have not been aware of this behavior.
I haven't checked the examples, but I like the narrative changes.

JSONPath allows the wildcard symbol "*" to select any member of an object or any element of an array (wildcard).  The descendant  <ins> operator ".." selects all the descendants (descendant-selector) of a node.  The array slice syntax "[start:end:step]" allows selecting a regular selection of an element from an array, giving a start position, an end position, and possibly a step value that moves the position from the start to the end (slice). </ins> Filter expressions are supported via the syntax "?(<boolean expr>)" as in Array slice selector "[<start>:<end>:<step>]", where the optional values "<start>", "<end>", and "<step>" are integer literals.  <ins> Descendants selector "..". </ins> List selector "[<sel1>,<sel2>,...,<selN>]", holding a comma separated list of index and slice selectors. 3.5.7.2.  <ins> The "descendant-selector" selects certain descendants of a node: </ins>  <ins> the "..<name>" form (and the "..[<index>]" form where "<index>" is a "quoted-member-name") selects those descendants of the node that are member values of an object with the given member name. the "..[<index>]" where "<index>" is an "element-index" selects those descendants of the node that are array elements with the given index. the "..[*]" and "..*" forms select all the descendants of the node. In the resultant nodelist: nodes occur before their children, and nodes of an array occur in array order. </ins> Children of an object may occur in any order, since JSON objects are unordered. Queries:  <ins> Note: The ordering of the results for the "$..[*]" and "$..*" </ins> examples above is not guaranteed, except that:  "{"j": 1, "k": 2}" must appear before "1" and "2",  <ins> "[5, 3, [{"j": 4}]]" must appear before "5", "3", and "[{"j": 4}]", "5" must appear before "3" which must appear before "[{"j": 4}]", "[{"j": 4}]" must appear before "{"j": 4}", and </ins>  <ins> "{"j": 4}" must appear before "4". </ins> 3.5.8.


The current item is selected if and only if the result is "true". <del> Notes: </del>  <del> Parentheses can be used with "boolean-expr" for grouping.  So filter selection syntax in the original proposal "[?(<expr>)]" is naturally contained in the current lean syntax "[?<expr>]" as a special case. </del>  <del> Comparisons are restricted to primitive values (such as number, string, "true", "false", "null").  Comparisons with complex values will fail, i.e. no selection occurs. </del>  <del> Data types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. </del>  <del> A member or element value by itself in a Boolean context is interpreted as "false" only if it does not exist.  Otherwise it is interpreted as "true".  To be more specific about the actual value, explicit comparisons are necessary.  This existence test -- as an exception to the general rule -- also works with structured values. </del>  <del> Paths in filter expressions are Singular Paths, each of which selects at most one node. </del>  <del> The regular expressions in the string-literals on the right-hand side of "=~" are as defined in I-D.draft-bormann-jsonpath-iregexp. Regular expression tests can be applied to JSON string values (RFC8259) only (on the left-hand side of "=~"); they yield false otherwise. </del>  <del> Alphabetic characters in ABNF are case-insensitive, so "e" can be either "e" or "E". </del>  <del> false, null, true are lower-case only (case-sensitive). </del>  The following table lists filter expression operators in order of precedence from highest (binds most tightly) to lowest (binds least 3.5.8.2. The "filter-selector" works with arrays and objects exclusively.  Its <del> result might be a list of </del>  , or <del> of their element or member values then.  Applied to other value types, it will select nothing. </del>  3.5.8.3.

Fixes URL
The notes need separating out into paragraphs. The semantics section needs to be expanded.

The current item is selected if and only if the result is "true".  <ins> Paths in filter expressions are Singular Paths, each of which selects at most one node. </ins>  <ins> Parentheses can be used with "boolean-expr" for grouping.  So filter selection syntax in the original proposal "[?(<expr>)]" is naturally contained in the current lean syntax "[?<expr>]" as a special case. </ins>  <ins> Comparisons are restricted to Singular Path values and primitive values (such as number, string, "true", "false", "null"). </ins>  <ins> Comparisons with complex values will fail, i.e. no selection occurs. </ins>  <ins> Data types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. </ins>  <ins> A member or element value by itself in a Boolean context is interpreted as "false" only if it does not exist.  Otherwise it is interpreted as "true".  To be more specific about the actual value, explicit comparisons are necessary.  This existence test -- as an exception to the general rule -- also works with structured values. </ins>  <ins> Alphabetic characters in ABNF are case-insensitive, so "e" can be either "e" or "E". </ins>  <ins> "true", "false", and "null" are lower-case only (case-sensitive). </ins>  <ins> Regular expression tests can be applied to JSON string values (RFC8259) only (on the left-hand side of "=~"); they yield false otherwise. The syntax of regular expressions in the string-literals on the right-hand side of "=~" is as defined in I-D.draft-bormann-jsonpath- iregexp. </ins> The following table lists filter expression operators in order of precedence from highest (binds most tightly) to lowest (binds least 3.5.8.2. The "filter-selector" works with arrays and objects exclusively.  Its  <ins> result is a list of </ins> , or  <ins> of their array elements or member values, respectively.  Applied to other value types, it will select nothing. A relative path, beginning with "@", refers to the current array element or member value as the filter selector iterates over the array or object. Comparisons using one of the operators "<", "<=", ">", and ">=" are between numeric values only.  Using these operators to compare other types of values produces a "false" comparison result. The semantics of regular expressions are as defined in I-D.draft- bormann-jsonpath-iregexp. </ins> 3.5.8.3.


NAME and NAME Thanks for your help. I verified cut'n'past works correctly.
Some of these are split across lines in awkward places: ! We could either fix the rendering somehow to split at a more acceptable point or change the examples to avoid these awkward splits.
NAME Do you know how to fix the rendering? E.g. I think it would be better not to split the lines in the middle of a quoted string, but splitting after would be ok.
Please check my little tweak to
What if we reduce each aspect to minimal necessary ... ?
This seems to work ...
This is essentially what URL does, except that it uses native nbsps.
ahh ... fine ...
There are two considerations I have in mind: Ease of future editing - may need to add a comment about invisible special characters. Cut'n'paste - need to be able to run the examples and get the same results when clipped from either text or HTML.
Left an editing note. Copy/paste works for me in TXT (which has an ASCII space) and HTML (which has an NBSP, but that gets reduced in copy/paste).
Fixed as part of e82ce1f521e94ee2cd5b93d14726875e94a4a8e7.

3.7.1. <ins> "$["u00b1"]" is normalized into (noise in the table and lack of typewriter font is due to RFCXMLv3 limitations). </ins> 4. 4.1.


5.2. Where JSONPath is used as a part of a security mechanism, attackers <del> can attempt to evoke unexpected behavior, or take advantage of differences in behavior between JSONPath implementations. This also applies to underlying technologies such as UTF-8 (see RFC3629), the Unicode character set, and JSON.  A characteristic of JSON that can lead to varying results is the fact that JSON objects are unordered; therefore, the order in which results of a JSONPath query reflect the presence of JSON object members can vary with </del>  implementations.

See also . Fixes URL
I have read the latest draft of section 5.2 "Attacks on Security Mechanisms that Employ JSONPath" and I'm having trouble figuring out what it's saying and what would be useful for implementors. On consideration, I think the following is true. If the JSON text to which you're applying a JSONpath follows the rules of I-JSON [RFC7493] the results should be deterministic and repeatable for the same JSON text from one JSONpath implementation to another. On the other hand, if you have JSON with dupe object keys, or 300-digit numbers, or broken UTF16 surrogates, you really have no expectation of deterministic behavior. I think (do others agree?) that given I-JSON, conforming JSONpath implementations should be deterministic? Anyhow, I'd replace section 5.2 with text saying something like "If your security mechanism includes the use of JSONpath implementations, you should be aware that results will be nondeterministic and interoperation can fail if a JSON text you are processing includes constructs that are deprecated but allowed by [RFC8259]. Deterministic behavior can be expected for any JSON text conformant with [RFC7493].
Note that in URL, I didn't adopt the language above to describe certain constructs as "deprecated but allowed" by RFC 8259 since that RFC does not use the term deprecation. Please feel free to object to this in the PR.
It's been previously mentioned in the issues, but the draft should say something about the danger of attack from a query that triggers overflow in a recursive step. The JSONPath recursion operator, given how it's implemented in many implementations, is vulnerable to attack, in situations where a JSONPath expression is provided as a parameter. It's pretty obvious that some, perhaps even most, implementations would not be able to pass Google fuzzer, were that a scenario. Note that enterprises take the risk of vulnerability through recursion very seriously. In my opinion, some limits on recursion levels ought to be specified.
Interesting. Wouldn't such a stack overflow attack be bounded by the JSON document? I guess where an attacker can provide both the JSON document and the JSONPath, there is an opportunity for stack overflow. But there is a more general resource exhaustion attack if attackers are allowed to provide arbitrarily large JSON documents. I agree that JSONPath implementations may wish to defend themselves by imposing recusion limits, memory limits, etc., but I'm not sure I'd want to go as far as requiring specific limits in the spec.
I believe so, but as you also mention, the attacker could supply both. Or supply a document that exploits a JSONPath with a recursive operator. Of course, a hostile document raises more issues than for just JSONPath. Pull parsers also may exhibit recursion, Microsoft guards against that by limiting .Net JSON parser depth by default to 64. My own view is that in today's world, anything that suggests recursion should be flagged.
Ok, and based on the advice in URL on DOS attacks, I'll put together a PR to flag up the risk of a DOS attack due to recursion and see how that goes down.

5.2. Where JSONPath is used as a part of a security mechanism, attackers  <ins> can attempt to provoke unexpected or unpredictable behavior, or take advantage of differences in behavior between JSONPath </ins> implementations. <ins> Unexpected or unpredictable behaviour can arise from an argument with certain constructs described as unpredictable by RFC8259. Predictable behavior can be expected, except in relation to the ordering of objects, for any argument conforming with RFC7493. Other attacks can target the behaviour of underlying technologies such as UTF-8 (see RFC3629) and the Unicode character set. </ins>


Root selector "$" (used at the start of a query and in expressions) <del> Dot selector ".<name>", used with object member names exclusively. </del>  <del> Dot wildcard selector ".*". </del>  Index selector "[<index>]", where "<index>" is either a (possibly negative, see index-semantics) array index or an object member <del> name. </del>  <del> Index wildcard selector "[*]". </del>  Array slice selector "[<start>:<end>:<step>]", where the optional <del> values "<start>", "<end>", and "<step>" are integer literals. </del>  <del> Descendants selector "..". </del>  List selector "[<sel1>,<sel2>,...,<selN>]", holding a comma <del> separated list of index and slice selectors. </del>  Filter selector "[?(<expr>)]"

contains a bulleted list of the selector types. Each of the items in the list ends with a period. While it may (or may not) be grammatically correct, it leads to some confusing text, specifically when a selector contains, or completely comprises of, periods. For example: Because we only have plain text, it's really difficult to see what's going on here. Formatted, it would look like which is much clearer. If the spec is to continue being issued in a plain text format, I suggest we remove the ending periods from these lines.

Root selector "$" (used at the start of a query and in expressions)  <ins> Dot selector ".<name>", used with object member names exclusively </ins>  <ins> Dot wildcard selector ".*" </ins> Index selector "[<index>]", where "<index>" is either a (possibly negative, see index-semantics) array index or an object member  <ins> name </ins>  <ins> Index wildcard selector "[*]" </ins> Array slice selector "[<start>:<end>:<step>]", where the optional  <ins> values "<start>", "<end>", and "<step>" are integer literals </ins>  <ins> Descendants selector starting with a double dot ".." </ins> List selector "[<sel1>,<sel2>,...,<selN>]", holding a comma  <ins> separated list of index and slice selectors </ins> Filter selector "[?(<expr>)]"


indexing beyond the end of an array, simply result in fewer nodes being selected. <del> Let's walk through an example in detail.  With the argument </del>  "{"a":[{"b":0},{"b":1},{"c":2}]}", the query "$.a[*].b" selects the following list of nodes: "0", "1" (denoted here by their value).

Fixes URL
In a previous issue, I suggested the idea of adding a processing model description to the specification. So was added. However, in re-reading the current document, I found that the process is repeated (albeit with less detail) in . I think that the language in 3.4 may be sufficient to explain how the path is expected to operate, making the processing model (or at least one of them) somewhat redundant. Can we combine these sections in some way instead of repeating ourselves?
I agree that we could combine these sections and avoid some repetition. I'm inclined to keep the Semantics section and do away with the Processing Model section since I think the term "Processing Model" is a little obscure compared to "Semantics".
Regardless of my question I like the change.

indexing beyond the end of an array, simply result in fewer nodes being selected.  <ins> Consider this example.  With the argument </ins> "{"a":[{"b":0},{"b":1},{"c":2}]}", the query "$.a[*].b" selects the following list of nodes: "0", "1" (denoted here by their value).


Comparisons are restricted to Singular Path values and primitive values (such as number, string, "true", "false", "null"). <del> Comparisons with complex values will fail, i.e. no selection occurs. </del> Data types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. element or member value as the filter selector iterates over the array or object. <del> Comparisons using one of the operators "<", "<=", ">", and ">=" are between numeric values only.  Using these operators to compare other types of values produces a "false" comparison result. </del>  The semantics of regular expressions are as defined in I-D.draft- bormann-jsonpath-iregexp.

Fixes URL
Merging to unblock other editorial work.
Even after the clarification of URL, comparison of two structured values always produces a "false" comparison result. This includes the following cases: Comparing two equal structured values with gives "false". Comparing two equal structured values with gives "false". Comparing two unequal structured values with gives "false". Comparing two unequal structured values with gives "false". With these semantics, the following law of comparisons does not hold: if and only if
I think this is worth declaring explicitly while we don't allow structured values. If/when we move to support them, we would need to remember to remove this.
NAME I'm not sure what you mean by "this". I would favour changing the spec so that the above law does hold in all cases._
Yes. I agree. This topic. All of the above. !
I've attempted to fix this in URL
I don't understand why the draft doesn't support sensible equality comparisons between arbitrary JSON values, the Committee doesn't have to invent anything, there is prior experience that covers this. Jayway, possibly the most widely used of the current implementations (to many Stack Overflow users, Jayway is JSONPath), has no difficulty with these comparisons, or, for that matter, comparisons with array and object literals.
IIRC we discussed this on more than one call and after considering the options, we settled on the current behaviour. I'm afraid I can't remember the rationale, but maybe NAME or NAME can. See: URL URL
I would describe the rationale as focus on shipping the MVP. I agree with Daniel that it is a quite limited amount of work to support equality for all JSON values. Inequalities are more work, less general (as long as excluding normalized comparison), and don't have a good solution for maps, but also could be done. If we find that we are creating a major interop issue by the MVP approach, I think we should still be open to addressing general equality (and inequalities). We'll have to solve the absent value problem in any case.
What I didn't mention is the not quite insignificant accretion of new grammar to make literals for all of JSON.
(This is a follow-on from URL) URL covers comparing absent with absent using == and !=, but we still haven't decided what to do about the likes of "absent >= absent". The spec currently says: This doesn't make it clear what to do when comparing two singular paths which each select no value. I can see two options: We might want "absent >= absent" to be true because "absent == absent" is true. We might say that "absent" isn't a numeric value and so "absent >= absent" is false. I prefer the first option as it preserves the usual law that "x >= y" if and only if "x >y" OR "x ==y". (I guess we might want to add such laws to the spec too!)
I, too, prefer the first option.
If your model is Javascript and "absent" has the same properties as "undefined", then inequality operators wouldn't be supported. If your model is a language that supports the notion of "optional", I can't think of any that support inequality operators for values of that type. But on this, the draft really needs to define its type system more precisely, as introducing the notion of "absent" extends the type system beyond JSON.
According to the spec, the results of singular paths are nodelists consisting of at most one node. So one way to address this issue would be to say that: when a nodelist consisting of a single node appears in a comparison, it is replaced by the value of the node, and when an empty nodelist appears in a comparison, the result of the comparison is true if and only if the comparison is being made with another empty nodelist and the comparison operation is , or .
You also have to think about what it means for an expression that evaluates to "absent" to be passed to a function (assuming the draft supports functions.) By comparison, in Javascript, a value of type undefined is passed to the function.
Noted in URL
Currently the syntax section of the "Filter Selector" section describes some semantics. These descriptions should be folded into the semantics section.
If yes, is false. Need to discuss impact on >, >=, etc. See also: URL
I've extended the query which compares two paths via equals to include absent keys: URL No consensus, not even a majority at this point.
... which is not necessarily a problem: I gives us more leeway to nail down something sane (if we want to).
... with JavaScript ... due to .
Isolating the empty key behavior, I think the results are consistent with what we understand about the implementations. By my count, 12 implementations select the item. It depends on whether the implementation returns a value (such as ) for an absent key, or whether it handles it as a recoverable error. The Javascript ones that return for an absent key select , as would be expected. Jayway, which handles an absent key as a recoverable error that takes out the term, does not select , again as expected. . I think it would be interesting to add to the document.
Done :)
I would like to add here, just to ensure that it's documented, that C# recently added as an expression equivalent to . Therefore returning could be quite confusing for some users.
Okay, from the data (checked cells correspond to selected values), it appears that twelve of 42 implementations consider absent is equal to absent (column 2), while one, PHP (galbar-jsonpath), considers is equal to absent (column 5), and absent to (column 6), but not absent to absent (column 2). The ones that consider absent is equal to absent do so for different reasons. Cpp (jsoncons) and dotNET (JsonCons.JsonPath) evaluate absent to be , and is equal to . The JavaScript implementations evaluate absent to be , and is equal to . Three of the JavaScript implementations also show equal to and equal to , no doubt because of conversion when comparing and . Implementation ---------------------------- Clojure (json-path) Cpp (jsoncons) dotNET (JsonCons.JsonPath) dotNET (JsonPathLib) dotNET (Manatee.Json) Elixir (warpath) Erlang (ejsonpath) JavaScript (brunerd) JavaScript (Goessner) JavaScript (jsonpath) JavaScript (jsonpath-plus) Ruby (jsonpath) PHP (galbar-jsonpath) We can deduce that the remaining 30 of 42 implementations do not consider absent equal to absent. Again, the reasons vary. 15 implementations either fail or return an empty collection. While there is more going on in this test than "absent equal to absent", the number 15 lines up with the number in URL that fail when attempting to evaluate an absent member. So for these, it looks like absent is always an unrecoverable error. When Jayway evaluates with absent and absent , it considers the first absence a recoverable error, and it will branch to some code that ignores this comparison, so this comparison selects nothing. That applies to all comparators, , , , .
112 minutes: So we need to discuss this.
By , do you mean literally an IEEE 754 , to have evaluate to that? First, I don't think any existing JsonPath implementation does that. Second, not all mainstream programming languages require IEEE 754 or . Generally speaking, notions such as or tend to be language specific. Some languages support as a primitive value for when a variable is declared but not initialized, some support something similar for , some want to make it impossible to have a variable that is not initialized. There are alternatives, It isn't necessary to have evaluate to a "value", whether , or . can be considered an error, resulting in the term in question being unmatched. That's the approach of JAVA Jayway, and the implementations that followed Jayway.
NaN is just a placeholder for a value representing “absent" that behaves like NaN: It does not compare equal to anything, including itself. This obviously is a weird value to have, and I believe it was introduced in IEEE 754 as a hack to make it safer to reuse existing code with that new standard, not because having such a value is such a great concept. Right. But that is not relevant to the discussion at hand. “Undefined” again is a placeholder for any non-JSON value representing “absent" that does compare equal to itself. NAME == NAME This is hard to do with throwing an exception. There is nothing wrong with a value representing “absent”. “undefined” and “NaN” were just figures of speech for values representing “absent” that do or do not compare equal to themselves. Grüße, Carsten
Thanks for clarifying. Like SQL NULL then. Do you think so? Personally, I would be fine if both evaluated to no results (although in Jayway they do not.) It's unnatural in some programming languages. A more universal notion is optionality, a result that may or may not have a value. Daniel
Note that by introducing as a value to represent absent, you've effectively extended the JSONPath type system to be more than JSON, JSON does not have the notion of . In JavaScript JSONPath implementations, you can write (returns everything) and (returns nothing), do you plan to support that notation as well? Or do you plan to only allow the construction of an indirectly as the result of evaluating ? Regardless, you've still introduced a non-JSON type. What happens in a future version of JSONPath that supports functions of expressions, like all the current JavaScript ones? Do they accept as an argument, like JavaScript? More things to reason about. Of course, there is plenty of prior experience that bears on these matters. JMESPath stays entirely within the JSON type system as a design principle, and represents the result of as a JSON null value. A couple of JSONPath implementations (a distinct minority) also take that approach. JSONPath implementations that use a scripting language having as a primitive type usually use for absent. The most important and widely used implementations that implement their own expression language, notably Jayway, handle absent as a recoverable error affecting that term.
JSON doesn't have , but it does have a distinction between and absent, which is what represents. It doesn't need to be a "value" that's recognized externally; we intend it as an internal placeholder that indicates the absence. The question we're raising here is, internally to an implementation, how the absence of one property equate to the absence of another property? This will not be a supported syntax in JSON Path. Instead we are using implicit existence: for presence test and for absence test.
We don't have a PR for this issue yet, but I don't think we need to introduce in the specification. This is just a figure of speech to have an reasonable conversation about this issue. Yes. This is good. I don't see a point in providing a literal notation for the absent condition. I would expect so. In my eyes, that would be a bug; a null value is different from absence. Curious: Where are these throws caught ("recoverable")? So far, we have been able to avoid throw/catch, and I wouldn't mind if it stayed that way.
Thinking further on whether needs to have a value or not, would we also expect the following to be true?
Both don't exist, so they are equal, so they are the same, so no.
Argh! I meant would we also expect that expression to be false. But my point here is that the undefined value is acting more than a figure of speech here because when we apply selectors to it (such as [0]), it is preserved. I'm not sure how we could explain that propagation behaviour without there being an undefined value of some sort, even though it may be implicit. Of course, a clean way of defining this would be to say that each selector produces an optional nodelist with an "absent" nodelist which is preserved by other selectors. As was pointed out earlier, we don't need to have an explicit representation for the "absent" nodelist, but we do need to talk about how the "absent" nodelist behaves. Does this help?
Yes, that (empty input empty output) is part of the definition of the path selectors, and maybe needs to be made more explicit there. It is not an aspect of the filter expression language.
Your understanding seems to be closer to c++ , rust , or c# . Something with and properties, considered abstractly. From a conceptual point of view, I think that's better, because it's less Javascriptish, not many consider Javascript to be a great design, and all values remain JSON. Daniel
The nice thing about the JMESPath convention is that it leads to a simple consistent model that stays entirely within the JSON type system. Regarding how this corresponds to user intuition, of all the JMESPath issue logs and all the JMESPath discussions that I've followed, I've never seen this come up. But I think the same can be said of other conventions. Users care about many things, but they don't care about this, whatever the convention is, they figure it out and move on. Most languages would consider having both and as having one thing too many; some (rust, functional languages) would consider that as having two things too many. Daniel
In Javascript, that would result in an exception being thrown, with message "Cannot read properties of undefined"
But this is not JavaScript. From context, this seems to be meant as a part of a filter expressions. LHS and RHS of are two path constructs. These don’t have any values but nodelists; so I don’t know where (or any other surrogate for absent) comes in. The results of these two paths then are used in a comparison, which causes the JSON value at the node selected by each path is obtained. This is where this concept of (absent) comes in, because the nodelists are empty, and therefore there is no such JSON value, so we need to remember that the input to the comparison is something else. Grüße, Carsten
In most prior experience that I know of in JSONPath implementations, the LHS and RHS in filter expressions are expressions that evaluate to single values (null, true, false, string, number, array, object and in some cases undefined), not result lists. These JSONPath implementations group largely into two categories, Implementations that use Javascript/Python/Lua to evaluate filter expressions, where the symbol in the script is substituted with the current node value, and is evaluated as a Javascript/Python/Lua expression, which evaluates to a single value (no result list.) Implementations that evaluate as a JSONPath expression, but using rules so that the result is produced as a single value rather than a result list. Jayway JSONPath is an example, when evaluating in a filter, the slice, union and filter selectors will always produce results wrapped in an array, the wildcard selector will produce results wrapped in an array if there are more than two items, the identifier and index selectors will produce a single value if matched, otherwise a null. It is done that way in the filter even if the final result returned to the user is a result list (Jayway supports both single value and result list returned to the user.) Between the Javascript/Python implementations and Java Jayway , that accounts for most of the JSONPath implementations in use. Do you know of any prior experience where the LHS and RHS in filter expressions evaluate to result lists (node lists)? Thanks, Daniel
In JavaScript ... ... with new optional chaining URL
I wasn't talking about implementations, but about the processing model we have adopted.
Interesting. So, given If resolves to a "result list", , how is the result list containing compared to the single value ? What convention are you following to support comparison between a "result list" and a single value? I apologize if I missed that in the draft. In all the prior experience that I'm familiar with, always evaluates to a single value according to rules. That's true of both implementations that treat as a Javascript like variable, much in fact like it is in the draft, and in implementations where the grammar of is the same as . (For these implementations, is always evaluated to a single value following rules that may differ from evaluating to a result list.) So your approach sounds like something different. Thanks, Daniel
We have rough consensus that absent does equal absent. Tagged as editorial.

Comparisons are restricted to Singular Path values and primitive values (such as number, string, "true", "false", "null").  Data types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. element or member value as the filter selector iterates over the array or object.  <ins> When a path resulting in an empty nodelist appears on either side of a comparison, the result of the comparison is true if and only if the comparison operator is "==", ">=" or "<=" and the other side of the comparison is also a path resulting in an empty nodelist. When no path resulting in an empty nodelist appears on either side of a comparison, any path which appears on either side of the comparison and results in a nodelist consisting of a single node is replaced by the value of the node and then: comparison using one of the operators "==" or "!=" produce a "true" comparison result if and only if the comparison is between: primitive values which satisfy the comparison, or structured values compared using "!=". comparisons using one of the operators "<", "<=", ">", or ">=" produce a "true" comparison result if and only if the comparison is between numeric values which satisfy the comparison. Note that comparisons between structured values, even if the values are equal, produce a "false" comparison result. </ins> The semantics of regular expressions are as defined in I-D.draft- bormann-jsonpath-iregexp.


"index-wild-selector", "filter-selector", or "list-selector" acting on objects or arrays, or a "slice-selector" acting on arrays. <del> Note that there is no "bald" descendant selector (".." on its own). </del>  3.5.7.2. descendants -- uniquely defined by a relative path -- is tested against a boolean expression "boolean-expr". <del> The current item is selected if and only if the result is "true". </del>  Paths in filter expressions are Singular Paths, each of which selects at most one node. Comparisons are restricted to Singular Path values and primitive values (such as number, string, "true", "false", "null"). <del> Data types are not implicitly converted in comparisons.  So ""13 == '13'"" selects no node. A member or element value by itself in a Boolean context is interpreted as "false" only if it does not exist.  Otherwise it is interpreted as "true".  To be more specific about the actual value, explicit comparisons are necessary.  This existence test -- as an exception to the general rule -- also works with structured values. </del> Alphabetic characters in ABNF are case-insensitive, so "e" can be either "e" or "E". "true", "false", and "null" are lower-case only (case-sensitive). <del> Regular expression tests can be applied to JSON string values (RFC8259) only (on the left-hand side of "=~"); they yield false otherwise. </del> The syntax of regular expressions in the string-literals on the right-hand side of "=~" is as defined in I-D.draft-bormann-jsonpath- iregexp. element or member value as the filter selector iterates over the array or object.  When a path resulting in an empty nodelist appears on either side of <del> a comparison, the result of the comparison is true if and only if the </del>  comparison operator is "==", ">=" or "<=" and the other side of the comparison is also a path resulting in an empty nodelist. and results in a nodelist consisting of a single node is replaced by the value of the node and then: <del> comparison using one of the operators "==" or "!=" produce a "true" comparison result if and only if the comparison is between: </del>  primitive values which satisfy the comparison, or structured values compared using "!=". comparisons using one of the operators "<", "<=", ">", or ">=" <del> produce a "true" comparison result if and only if the comparison is between numeric values which satisfy the comparison. </del>  Note that comparisons between structured values, even if the values <del> are equal, produce a "false" comparison result. </del>  The semantics of regular expressions are as defined in I-D.draft- bormann-jsonpath-iregexp. The logical AND, OR, and NOT operators have the normal semantics of Boolean algebra and consequently obey these laws (where "P", "Q", and "R" are any expressions with syntax "logical-and-expr", "T" is any <del> true expression, such as "1 == 1", and "F" is any false expression, such as "1 == 0"): </del>  3.5.8.3.

Fixes URL
Let's continue in URL
Currently the syntax section of the "Filter Selector" section describes some semantics. These descriptions should be folded into the semantics section.
I'm not sure we are done with this yet. See comments.The reordering looks good to me.

"index-wild-selector", "filter-selector", or "list-selector" acting on objects or arrays, or a "slice-selector" acting on arrays.  <ins> Note that ".." on its own is not a valid selector. </ins> 3.5.7.2. descendants -- uniquely defined by a relative path -- is tested against a boolean expression "boolean-expr".  <ins> The current item is selected if and only if the boolean expression yields true. </ins> Paths in filter expressions are Singular Paths, each of which selects at most one node. Comparisons are restricted to Singular Path values and primitive values (such as number, string, "true", "false", "null").  Alphabetic characters in ABNF are case-insensitive, so "e" can be either "e" or "E". "true", "false", and "null" are lower-case only (case-sensitive).  The syntax of regular expressions in the string-literals on the right-hand side of "=~" is as defined in I-D.draft-bormann-jsonpath- iregexp. element or member value as the filter selector iterates over the array or object. <ins> A singular path by itself in a Boolean context is an existence test which yields true if the path selects a node and yields false if the path does not select a node.  To be more specific about the actual value of a node selected by a path, explicit comparisons are necessary.  This existence test -- as an exception to the general rule -- also works with nodes with structured values. </ins> When a path resulting in an empty nodelist appears on either side of  <ins> a comparison, the comparison yields true if and only if the </ins> comparison operator is "==", ">=" or "<=" and the other side of the comparison is also a path resulting in an empty nodelist. and results in a nodelist consisting of a single node is replaced by the value of the node and then:  <ins> comparison using one of the operators "==" or "!=" yields true if and only if the comparison is between: </ins> primitive values which satisfy the comparison, or structured values compared using "!=". comparisons using one of the operators "<", "<=", ">", or ">="  <ins> yield true if and only if the comparison is between numeric values which satisfy the comparison. </ins> Note that comparisons between structured values, even if the values  <ins> are equal, yield false. Data types are not implicitly converted in comparisons.  So "13 == '13'" yields false. A regular-expression test yields true if and only if the value on the left-hand side of "=~" is a string value and it matches the regular expression on the right-hand side according to the semantics of I- D.draft-bormann-jsonpath-iregexp. </ins> The semantics of regular expressions are as defined in I-D.draft- bormann-jsonpath-iregexp. The logical AND, OR, and NOT operators have the normal semantics of Boolean algebra and consequently obey these laws (where "P", "Q", and "R" are any expressions with syntax "logical-and-expr", "T" is any  <ins> expression that yields true, such as "1 == 1", and "F" is any expression that yields false, such as "1 == 0"): </ins> 3.5.8.3.


JSONPath allows the wildcard symbol "*" to select any member of an object or any element of an array (wildcard).  The descendant <del> operator ".." selects all the descendants (descendant-selector) of a node.  The array slice syntax "[start:end:step]" allows selecting a regular selection of an element from an array, giving a start position, an end position, and possibly a step value that moves the position from the start to the end (slice). </del>  Filter expressions are supported via the syntax "?(<boolean expr>)" as in Array slice selector "[<start>:<end>:<step>]", where the optional values "<start>", "<end>", and "<step>" are integer literals <del> Descendants selector starting with a double dot ".." </del>  List selector "[<sel1>,<sel2>,...,<selN>]", holding a comma 3.5.7.1. <del> The descendant selector starts with a double dot ".." and can be </del>  followed by an object member name (similar to the "dot-selector"), by an "index-selector" acting on objects or arrays, or by a wildcard.  3.5.7.2. The "descendant-selector" selects certain descendants of a node: the "..[*]" and "..*" forms select all the descendants of the node. <del> In the resultant nodelist: </del>  <del> nodes occur before their children, and </del>  <del> nodes of an array occur in array order. </del>  <del> Children of an object may occur in any order, since JSON objects are unordered. </del>  3.5.7.3. "5" must appear before "3" which must appear before "[{"j": 4}]",  "[{"j": 4}]" must appear before "{"j": 4}", and "{"j": 4}" must appear before "4".

Currently the spec only permits , ..[]..[1]. I think it would be beneficial and trivial to also allow the other bracketed query syntaxes: (I expect this should already be supported since is, but it doesn't seem to be) -
Descendants with quoted member names, such as , are already supported:
Here are the relevant tests from the comparison project. Lack of consensus for descendant/filter: URL URL Consensus for descendant/list: URL (Context: URL)
Currently, the descendant selector spec allows some non-determinism which may be unexpected. The spec currently says that in the resultant nodelist from the descendant selector: nodes occur before their children, and nodes of an array occur in array order. This sometimes allows multiple orderings when the result includes children of a node, but not the node itself. For example, with the document: the selector could, according to the spec, produce the nodelist: or the nodelist: This is surprising given that there are no objects in the document, since object ordering is the usual source of non-determinism. We could change the spec to constrain the order of traversal rather than the order of the resultant nodelist, but this seems to be getting into implementation detail. Is the current approach acceptable?
Hi Glyn, I treated the descendant-selector and the following object member name, index-selector, or wildcard as two separate steps. In order for the next step to be able to return values as per the examples, the first node that needs to be presented by the descendant-selector to the next step is the entirety of the current node (in case of the whole document). Given what I've written above, in the example, the whole document is always the first thing presented to the index selector. Given this, when the descendant-selector goes into the array, it will present the nodes and to the index selector. (Note that node is a child of node , so comes after.) Since the selector presumably only applies to arrays, it only applies to nodes and , and the "nodes before children" gives an explicit order, I don't see how the result could be . Have I missed something? Is it a matter of updating the semantics to say the entirety of the current node is looked at first? (Side note - the spec is not as clear on the element-index only applying to arrays. It's implied, but not stated as clearly as it is for quoted-member-names and objects.) Kind Regards, Graham
I think something like that is probably desirable, but without unduly constraining implementations. Thanks. I'll take a look at that with an editorial PR.
I think rewording the second condition ("nodes of an array occur in array order") achieves the desired ordering: nodes of a given array, and descendants of nodes of the given array, occur in array order.
I'm still here. I'm not sure that anything needs to be updated. I think the current text (node then descendants) is sufficient to guarantee the correct ordering. In this case, is processed, producing then is processed, producing It must be this way because of array ordering. gives the (ordered) node list . Of those, we take the first elements of arrays, which is from and from . I'm really struggling to see how the current wording can yield anything else.
The behaviour of is interesting. With the document: and the selector , Nebhale produces a result obeying the reworded conditions (but starts the nodelist with ): Jayway and Goessner place after , contrary to the reworded conditions: and Gatling doesn't even get close to the spec:
The problem with the current wording is that it allows too much freedom in the resultant nodelist. The result is allowed because: nodes occur before their children (since isn't a child of or vice versa), and nodes of an array occur in array order (since and are not nodes of the same array). I think you are interpreting differently from the spec. You seem to be regarding it as a combination of and ...... whereas the spec allows only strict descendants.)
It probably should say that this is the node order of the node list that describes the entire input JSON value. A node list is a subset of that novelist, preserving order.
Hmmm. That's a bit tricky because there isn't necessarily a unique node order (because objects are not ordered). So, at best, it describes a collection of ordered nodelists and then the resultant nodelist is a subset of any one of those nodelists, preserving order. I think the reworded condition above captures the constraint more simply.
These rules necessitate that 0 come before 1 in the above case. Let's look at the case because it's more interesting given the array as the first item. Evaluating the array in sequence and nodes before children has two possible processes: Evaluate each item, evaluating its children before moving to the next item. Order of processing is , , , , . Queue each item, queuing its children as the item is processed, eventually running through the queue. Order of processing is , , , , . In both cases, the resulting node list is . You never get before , which means that you will always get in the first example. The only question is whether does 1 or 2 from above.
I would agree, if the spec required evaluating the array in sequence and nodes before children, but it doesn't. It only talks about the order of the resultant nodelist. What text in the spec makes you think it is talking about the order of evaluation, as such? Of course, the order of the resultant nodelist implies some things about the order of evaluation, but it doesn't say anything about the ordering of nodes relative to the descendants of their siblings.
I thought we already defined this. I'll need to consult the spec again.
It's surprising the comparison project has the for applied to :
Perhaps the others also did what I did and treated the and what follows as two separate steps? The descendant part only visits each of the nodes leaving it to the second part to process what's there. This allows the same code to be used as for the non-descendant version of the same selector. (It also means that my descendant selector allows list selectors because I removed the other types of selectors in favour of that.) If instead is treated as a single step and takes care of both jobs, descending and wildcard, then I could see how the following alternate result could be returned: The definitions at the top of this JSONPath document mentions a "transitive closure over the chidlren relation" but that was too mathematical for me. I had a look at XPath's descendant-or-self but the spec didn't tell me exactly what to expect. I tried the following XML using an : An XPath of produced something like the "alternate result" I've given above:
Yes, that's what I've done in my implementation as well. But in terms of the specification, must always be coupled with another selector, whether that's a name, wildcard, or bracket-syntax. As such it makes sense to define it in conjunction with the "second" selector. There's some discussion as well.
All the spec needs to require is that there is an input order that the output nodelist is a subsequence of. After you have banged it into shape to actually do this, I’m not so sure… Grüße, Carsten
That would work, but we'd need to define "input order" carefully as it's not necessarily unique because of objects.
NAME I had a go at the "input order" approach. See the in PR 218.
Great. Maybe we should give orders that satisfy the criteria a name; with your text, maybe "visit order"?
Happy to attempt something once URL lands. I feel that "visit order" is a little too generic. I would prefer a more specific term such as "array preorder". WDYT? (Happy to continue this thread here, but feel free to move to a fresh editorial issue if you prefer.)

JSONPath allows the wildcard symbol "*" to select any member of an object or any element of an array (wildcard).  The descendant  <ins> operators (which start with "..") select some or all of the descendants (descendant-selectors) of a node.  The array slice syntax "[start:end:step]" allows selecting a regular selection of an element from an array, giving a start position, an end position, and possibly a step value that moves the position from the start to the end (slice). </ins> Filter expressions are supported via the syntax "?(<boolean expr>)" as in Array slice selector "[<start>:<end>:<step>]", where the optional values "<start>", "<end>", and "<step>" are integer literals  <ins> Descendants selectors starting with a double dot ".." </ins> List selector "[<sel1>,<sel2>,...,<selN>]", holding a comma 3.5.7.1.  <ins> The descendant selectors start with a double dot ".." and can be </ins> followed by an object member name (similar to the "dot-selector"), by an "index-selector" acting on objects or arrays, or by a wildcard. <ins> Note that there is no "bald" descendant selector "..". </ins> 3.5.7.2. The "descendant-selector" selects certain descendants of a node: the "..[*]" and "..*" forms select all the descendants of the node.  <ins> The resultant nodelist is ordered as if: nodes are visited before their children, and </ins>  <ins> nodes of an array are visited in array order. </ins>  <ins> Children of an object may be visited in any order, since JSON objects are unordered. </ins>  <ins> Implementations may visit descendants in any way providing the resultant nodelist could have been produced by visiting descendants as above. </ins> 3.5.7.3. "5" must appear before "3" which must appear before "[{"j": 4}]", <ins> "5" and "3" must appear before "{"j": 4}" and "4", </ins> "[{"j": 4}]" must appear before "{"j": 4}", and "{"j": 4}" must appear before "4".


3.5.7.1. The descendant selectors start with a double dot ".." and can be <del> followed by an object member name (similar to the "dot-selector"), by an "index-selector" acting on objects or arrays, or by a wildcard. </del>  Note that there is no "bald" descendant selector "..". The "descendant-selector" selects certain descendants of a node: the "..<name>" form (and the "..[<index>]" form where "<index>" is <del> a "quoted-member-name") selects those descendants of the node that are member values of an object with the given member name. </del>  <del> the "..[<index>]" where "<index>" is an "element-index" selects those descendants of the node that are array elements with the given index. </del>  <del> the "..[*]" and "..*" forms select all the descendants of the node. </del>  The resultant nodelist is ordered as if:

Add array slicing, filters, and lists. Fixes URL
Would it be useful to have references to indications of implementation consensus in this ticket?
Probably best to put such things in issues rather than PRs, so I'll add something to URL
Currently the spec only permits , ..[]..[1]. I think it would be beneficial and trivial to also allow the other bracketed query syntaxes: (I expect this should already be supported since is, but it doesn't seem to be) -
Descendants with quoted member names, such as , are already supported:
Here are the relevant tests from the comparison project. Lack of consensus for descendant/filter: URL URL Consensus for descendant/list: URL (Context: URL)
Currently, the descendant selector spec allows some non-determinism which may be unexpected. The spec currently says that in the resultant nodelist from the descendant selector: nodes occur before their children, and nodes of an array occur in array order. This sometimes allows multiple orderings when the result includes children of a node, but not the node itself. For example, with the document: the selector could, according to the spec, produce the nodelist: or the nodelist: This is surprising given that there are no objects in the document, since object ordering is the usual source of non-determinism. We could change the spec to constrain the order of traversal rather than the order of the resultant nodelist, but this seems to be getting into implementation detail. Is the current approach acceptable?
Hi Glyn, I treated the descendant-selector and the following object member name, index-selector, or wildcard as two separate steps. In order for the next step to be able to return values as per the examples, the first node that needs to be presented by the descendant-selector to the next step is the entirety of the current node (in case of the whole document). Given what I've written above, in the example, the whole document is always the first thing presented to the index selector. Given this, when the descendant-selector goes into the array, it will present the nodes and to the index selector. (Note that node is a child of node , so comes after.) Since the selector presumably only applies to arrays, it only applies to nodes and , and the "nodes before children" gives an explicit order, I don't see how the result could be . Have I missed something? Is it a matter of updating the semantics to say the entirety of the current node is looked at first? (Side note - the spec is not as clear on the element-index only applying to arrays. It's implied, but not stated as clearly as it is for quoted-member-names and objects.) Kind Regards, Graham
I think something like that is probably desirable, but without unduly constraining implementations. Thanks. I'll take a look at that with an editorial PR.
I think rewording the second condition ("nodes of an array occur in array order") achieves the desired ordering: nodes of a given array, and descendants of nodes of the given array, occur in array order.
I'm still here. I'm not sure that anything needs to be updated. I think the current text (node then descendants) is sufficient to guarantee the correct ordering. In this case, is processed, producing then is processed, producing It must be this way because of array ordering. gives the (ordered) node list . Of those, we take the first elements of arrays, which is from and from . I'm really struggling to see how the current wording can yield anything else.
The behaviour of is interesting. With the document: and the selector , Nebhale produces a result obeying the reworded conditions (but starts the nodelist with ): Jayway and Goessner place after , contrary to the reworded conditions: and Gatling doesn't even get close to the spec:
The problem with the current wording is that it allows too much freedom in the resultant nodelist. The result is allowed because: nodes occur before their children (since isn't a child of or vice versa), and nodes of an array occur in array order (since and are not nodes of the same array). I think you are interpreting differently from the spec. You seem to be regarding it as a combination of and ...... whereas the spec allows only strict descendants.)
It probably should say that this is the node order of the node list that describes the entire input JSON value. A node list is a subset of that novelist, preserving order.
Hmmm. That's a bit tricky because there isn't necessarily a unique node order (because objects are not ordered). So, at best, it describes a collection of ordered nodelists and then the resultant nodelist is a subset of any one of those nodelists, preserving order. I think the reworded condition above captures the constraint more simply.
These rules necessitate that 0 come before 1 in the above case. Let's look at the case because it's more interesting given the array as the first item. Evaluating the array in sequence and nodes before children has two possible processes: Evaluate each item, evaluating its children before moving to the next item. Order of processing is , , , , . Queue each item, queuing its children as the item is processed, eventually running through the queue. Order of processing is , , , , . In both cases, the resulting node list is . You never get before , which means that you will always get in the first example. The only question is whether does 1 or 2 from above.
I would agree, if the spec required evaluating the array in sequence and nodes before children, but it doesn't. It only talks about the order of the resultant nodelist. What text in the spec makes you think it is talking about the order of evaluation, as such? Of course, the order of the resultant nodelist implies some things about the order of evaluation, but it doesn't say anything about the ordering of nodes relative to the descendants of their siblings.
I thought we already defined this. I'll need to consult the spec again.
It's surprising the comparison project has the for applied to :
Perhaps the others also did what I did and treated the and what follows as two separate steps? The descendant part only visits each of the nodes leaving it to the second part to process what's there. This allows the same code to be used as for the non-descendant version of the same selector. (It also means that my descendant selector allows list selectors because I removed the other types of selectors in favour of that.) If instead is treated as a single step and takes care of both jobs, descending and wildcard, then I could see how the following alternate result could be returned: The definitions at the top of this JSONPath document mentions a "transitive closure over the chidlren relation" but that was too mathematical for me. I had a look at XPath's descendant-or-self but the spec didn't tell me exactly what to expect. I tried the following XML using an : An XPath of produced something like the "alternate result" I've given above:
Yes, that's what I've done in my implementation as well. But in terms of the specification, must always be coupled with another selector, whether that's a name, wildcard, or bracket-syntax. As such it makes sense to define it in conjunction with the "second" selector. There's some discussion as well.
All the spec needs to require is that there is an input order that the output nodelist is a subsequence of. After you have banged it into shape to actually do this, I’m not so sure… Grüße, Carsten
That would work, but we'd need to define "input order" carefully as it's not necessarily unique because of objects.
NAME I had a go at the "input order" approach. See the in PR 218.
Great. Maybe we should give orders that satisfy the criteria a name; with your text, maybe "visit order"?
Happy to attempt something once URL lands. I feel that "visit order" is a little too generic. I would prefer a more specific term such as "array preorder". WDYT? (Happy to continue this thread here, but feel free to move to a fresh editorial issue if you prefer.)

3.5.7.1. The descendant selectors start with a double dot ".." and can be  <ins> followed by an object member name (similar to the "dot-selector"), a wildcard (similar to the "dot-wild-selector"), an "index-selector", "index-wild-selector", "filter-selector", or "list-selector" acting on objects or arrays, or a "slice-selector" acting on arrays. </ins> Note that there is no "bald" descendant selector "..". The "descendant-selector" selects certain descendants of a node: the "..<name>" form (and the "..[<index>]" form where "<index>" is  <ins> a "quoted-member-name") selects those descendants that are member values of an object with the given member name. </ins>  <ins> the "..[<index>]" form, where "<index>" is an "element-index", selects those descendants that are array elements with the given index. </ins>  <ins> the "..[<slice-index>]" form selects those descendants that are array elements selected by the given slice. the "..[<filter>]" form selects those descendants that are array elements or object values selected by the given filter. the "..[*]" and "..*" forms select all the descendants. </ins> The resultant nodelist is ordered as if: