Draft: draft-ietf-jsonpath-base

Commentary: This PR also addresses 
 My now implements everything in the spec , including this PR . ( It also supports math operations in expressions , which is n't part of the spec ( yet ) . ) The function infrastructure was a struggle ( mostly because I 'm in a strongly typed language , I suspect ) , but once implemented , creating the functions themselves and registering them so that they can be parsed was easy ! With my lib , the user would implement a " function definition " interface which exposes the name , the range of parameters expected ( min /  ) , and the logic for the function itself ( which follows a pattern defined in my lib ) . Once an instance of their definition is registered , it 's available to be parsed . The parsing logic handles validating that the function receives the correct number of parameters , too , so if you send seven arguments , it 'll fail to parse . 
 Tangentially related to , would we consider the use of a function as an argument to another function . Currently this is not allowed as a function is not a . An example for this may be : to determine if the maximum between and is less than 10 . 
 Yes , I hope to support using the result of a function as an argument to a(nother ) function in Note that I do n't intend to support passing a function as an argument to a(nother ) function or returning a function from a(nother ) function , as in the following example , which does both : 
 FWIW I 'd be fine with this being in a follow - up PR to . 
 It actually looks like this is already supported . can be a can be a takes zero or more s as parameters 
 Would we consider allowing advanced expressions usages ? This would return the objects with s 1 and 4 . ( Yeah , we do n't support currently , but the example illustrates the idea . ) This would return the object with 1 . There are probably other ways expressions could be used , too . 
 Note that function extensions , with the improvements anticipated in , may be able to address the above use cases : 
 I think what I 've written is probably the more intuitive given the gamut of features in programming languages available today . What you have is definitely more functional ( i.e. functional programming style ) , but I would tend toward using the operators for these examples . This issue is n't about " how could this be done with what we have ? " but rather " is this something we want to support ? " 
 Interestingly , I found a test in the comparison project that treats an expression as a : . 
 Here 's . There is no consensus among implementations , although 14 of them behave the way this issue is proposing . ( Embarrassingly , my Go implementation gets just the opposite of that result . That looks like a bug IIRC . ) 
 2023 - 01 - 10 Interim : Do not do this enhancement . 
 Currently function extensions that return a nodelist must return a nodelist consisting of a single node . When a function extension is used as a comparable , it should be able to return an empty nodelist . When a function extension is used in an existence test , it should be able to return any number of nodes in its nodelist . ( Currently , such an existence test always yields true since the returned nodelist is non - empty . ) 
 Also if a function is used as an input to another function , it should be allowed to return multiple nodes . 
 Agreed . PR 330 addresses this . 
 This issue was addressed by PR . 
 I believe this is ready for merging ( to serve as the next baseline ) . My comments can either be resolved or entered as new issues .
Paragraph (version A):
Specifically, the "Semantics" subsections of Sections name-selector,
wildcard, filter-selector, and descendant-segment describe behavior
that becomes unpredictable when the JSON value for one of the objects
under consideration was constructed out of JSON text that exhibits
multiple members for a single object that share the same member name
("duplicate names", see RFC8259).  Also, selecting a child by name
(name-selector) and comparing strings (comparisons in Section filter-
selector) assume these strings are sequences of Unicode scalar
values, becoming unpredictable if they are not (RFC8259).
Paragraph (version B):
Specifically, the "Semantics" subsections of Sections name-selector,
wildcard, filter-selector, and descendant-segment describe behavior
that becomes unpredictable when the JSON value for one of the objects
under consideration was constructed out of JSON text that exhibits
multiple members for a single object that share the same member name
("duplicate names", see RFC8259).  Also, selecting a child by name
(name-selector) and comparing strings (comparisons in filter-
selector) assume these strings are sequences of Unicode scalar
values, becoming unpredictable if they are not (RFC8259).
Paragraph (version A):
The well-formedness and the validity of JSONPath queries are
independent of the JSON value the query is applied to; no further
errors relating to the well-formedness and the validity of a JSONPath
query can be raised during application of the query to a value.
Paragraph (version B):
Uses of function extensions must be correctly typed, as described
in fnex.
Paragraph (version B):
A JSONPath implementation MUST raise an error for any query which is
not well-formed and valid.  The well-formedness and the validity of
JSONPath queries are independent of the JSON value the query is
applied to; no further errors relating to the well-formedness and the
validity of a JSONPath query can be raised during application of the
query to a value.
Paragraph (version A):
The syntax and semantics of segments are defined in Section segments-
details.
Paragraph (version B):
The syntax and semantics of segments are defined in segments-details.
Paragraph (version A):
Paths in filter expressions are Singular Paths, each of which selects
at most one node.
Paragraph (version A):
Comparisons are restricted to Singular Path values, each of which
selects at most one node, and primitive values (that is, numbers,
strings, "true", "false", and "null").
Paragraph (version B):
An existence expression may test the result of a function expression
(see fnex).
Paragraph (version B):
Comparisons are restricted to primitive values (that is, numbers,
strings, "true", "false", and "null").  These can be notated as
literal values, or they can be derived from Singular Paths, each of
which selects at most one node.  Function expressions (see fnex) used
in comparison expressions return a primitive value or at most one
node.
Paragraph (version A):
Filter selectors may use function extensions, which are covered in
Section fnex.
Paragraph (version B):
Filter selectors may use function extensions, which are covered in
fnex.
Paragraph (version A):
A function extension defines a registered name (see iana-fnex) that
can be applied to a sequence of zero or more arguments, resulting in
a result.  A function-expression stands for ("returns") a nodelist or
a value.  The arguments are filter expressions that are to be
interpreted as nodelists or values.  For each argument and for the
result, the function extension defines the "kind" of the item, i.e.,
whether the item is a value or a nodelist ("nodes").
Paragraph (version A):
Syntactically, a function-expression can occur anywhere where a
singular-path can occur (exist-expr, comparable).  A function-
expression that employs a function extension that returns a nodelist
MUST return a singular node to be used in a comparable.
Paragraph (version B):
A function extension defines a registered name (see iana-fnex) that
can be applied to a sequence of zero or more arguments, producing a
result.
Paragraph (version B):
A function argument is a "filter-path" or a "comparable".
Paragraph (version B):
According to filter-selector, a "function-expression" is valid as a
"filter-path" or a "comparable".
Paragraph (version B):
Any function expressions in a query must be well-formed (by
conforming to the above ABNF) and correctly typed, otherwise the
JSONPath implementation MUST raise an error (see synsem-overview).
To define which function expressions are correctly typed, a type
system is first introduced.
Paragraph (version B):
Each argument and result of a function extension must have a declared
type.
Paragraph (version B):
A type is a set of instances.  A type is a subtype of another type if
its set of instances (possibly after coercion) is a subset of the set
of instances of the other type.
Paragraph (version B):
tbl-types defines the available types in terms of abstract instances,
where "n" denotes a node, "v" denotes a value, and "nl" denotes a
non-empty nodelist.  The table also lists the subtypes of each type.
Paragraph (version B):
"OptionalNodeOrValue" is an abstraction of a "comparable" (which
may appear on either side of a comparison or as a function
argument).
Paragraph (version B):
"OptionalNode" is an abstraction of a Singular Path.
Paragraph (version B):
"Value" is an abstraction of a primitive value.
Paragraph (version B):
"OptionalValue" is an abstraction of a primitive value that may
also be absent.
Paragraph (version B):
"Absent" is an abstraction of an empty nodelist.
Paragraph (version B):
"OptionalNodes" is an abstraction of a "filter-path" (which
appears in an existence test or as a function argument).
Paragraph (version B):
The abstract instances above can be obtained from the concrete
representations in tbl-typerep.
Paragraph (version B):
"OptionalNode" is a subtype of "OptionalValue" via coercion since
the "OptionalNode" instance "Node(n)" can be coerced to the
"OptionalValue" instance "Value(v)", where "v" is the value of the
node "n".
Paragraph (version B):
"OptionalNode" is a subtype of "OptionalNodes" via coercion since
the "OptionalNode" instance "Node(n)" can be coerced to the
"OptionalNodes" instance "Nodes(l)", where "l" is a nodelist
consisting of just the node "n".
Paragraph (version B):
The type correctness of function expressions can now be defined in
terms of this type system.
Paragraph (version B):
If it occurs as a "comparable" in a comparison, the function is
defined to have result type "OptionalNodeOrValue" or one of its
subtypes.
Paragraph (version B):
The argument is a function expression with defined result type
that is the same as, or a subtype of, the defined type of the
argument.
Paragraph (version B):
The argument is a literal primitive value and the defined type
of the argument is "Value" or any type of which "Value" is a
subtype.
Paragraph (version B):
The argument is a Singular Path and the defined type of the
argument is "OptionalNode" or any type of which "OptionalNode"
is a subtype.
Paragraph (version B):
The argument is a "filter-path" or a Singular Path and the
defined type of the argument is "OptionalNodes".