Package ca.marcusdunn.jsonlens.path.core.query
The abstract syntax tree of a JSONPath query (RFC 9535).
The parser makes these trees from query text. A caller can also make them directly, and
JsonPathQuery.toString() writes a tree as query text.
Grammar and types
The types follow the ABNF grammar of RFC 9535. Where the grammar or the type system of Section 2.4 restricts an expression, the Java types restrict it too. Thus many queries that are not valid cannot be made at all.
| Grammar | Type |
|---|---|
jsonpath-query |
JsonPathQuery: $ and zero or more Segments |
child-segment, descendant-segment |
Segment.Child, Segment.Descendant |
name-selector, wildcard-selector, index-selector, slice-selector, filter-selector |
Selector.Name, Selector.Wildcard, Selector.Index, Selector.Slice, Selector.Filter |
logical-expr |
LogicalExpression |
comparable |
ComparableExpression: a Literal, a SingularQuery, or a FunctionCall.Value |
filter-query |
FilterQuery |
function-expr |
FunctionCall: FunctionCall.Value, FunctionCall.Logical, or FunctionCall.Nodes |
function-argument |
FunctionArgument: one record for each declared parameter type |
For example, a side of a LogicalExpression.Comparison is a ComparableExpression. A query
that can select more than one node is not a ComparableExpression, so it cannot be a side of a
comparison.
Make a query directly
// $.store.book[?length(@.title) > 10]['title'], made without the parser.
LogicalExpression longTitle = new LogicalExpression.Comparison(
new FunctionCall.Value("length", List.of(new FunctionArgument.Value(
new SingularQuery(Identifier.CURRENT, List.of(new SingularSegment.Name("title")))))),
ComparisonOperator.GREATER,
new Literal.NumberLiteral(BigDecimal.TEN));
JsonPathQuery query = new JsonPathQuery(List.of(
new Segment.Child(List.of(new Selector.Name("store"))),
new Segment.Child(List.of(new Selector.Name("book"))),
new Segment.Child(List.of(new Selector.Filter(longTitle))),
new Segment.Child(List.of(new Selector.Name("title")))));
String text = query.toString(); // $['store']['book'][?length(@['title']) > 10]['title']
The Java types cannot express all validity rules. For example, an index must be in the I-JSON range, and a function call must agree with the signature of the function. The evaluator checks these rules before it applies a query.
Safe query construction
JsonPathQuery.toString() escapes all names and strings. Thus a name from user input cannot
change the structure of a query (RFC 9535, Section 4.2):
// A name from user input cannot change the structure of the query.
String input = "x'] || $..*[?@ == '";
JsonPathQuery query = new JsonPathQuery(List.of(new Segment.Child(List.of(new Selector.Name(input)))));
String text = query.toString(); // $['x\'] || $..*[?@ == \'']
-
ClassDescriptionA side of a comparison, or a ValueType function argument: a literal, a singular query, or a function with the result type ValueType (RFC 9535, Sections 2.3.5.1 and 2.4.3).A comparison operator (RFC 9535, Section 2.3.5.1).A query in a filter expression:
@or$followed by zero or more segments (RFC 9535, Section 2.3.5.1).A function argument, with the declared type of its parameter (RFC 9535, Section 2.4.3).An argument for a LogicalType parameter.An argument for a NodesType parameter.An argument for a ValueType parameter.A function expression (RFC 9535, Section 2.4).A call of a function with the result type LogicalType.A call of a function with the result type NodesType.A call of a function with the result type ValueType.The start of a query in a filter expression (RFC 9535, Sections 2.2 and 2.3.5).A JSONPath query: the root identifier$followed by zero or more segments (RFC 9535, Section 2.1.1).A literal value in a filter expression (RFC 9535, Section 2.3.5.1).The literaltrueorfalse.The literalnull.A number literal.A string literal.An expression with a logical result: LogicalTrue or LogicalFalse (RFC 9535, Section 2.3.5).A conjunction:a && b && ....A comparison:left op right(Section 2.3.5.2.2).A negation:!a.A disjunction:a || b || ....A NodesType function argument: a query or a function with the result type NodesType (RFC 9535, Section 2.4.3).A segment: it applies its selectors to the children or descendants of a node (RFC 9535, Section 2.5).A child segment:[<selectors>],.name, or.*(Section 2.5.1).A descendant segment:..[<selectors>],..name, or..*(Section 2.5.2).A selector in a segment (RFC 9535, Section 2.3).A filter selector:?<logical-expr>(Section 2.3.5).An index selector (Section 2.3.3).A name selector:'name'or"name"(Section 2.3.1).An array slice selector:start:end:step(Section 2.3.4).The wildcard selector:*(Section 2.3.2).A singular query: a query that selects at most one node (RFC 9535, Section 2.3.5.1).A segment of a singular query (RFC 9535, Section 2.3.5.1).An index segment:[index].A name segment:['name']or.name.