Limitations
editThe library implements RFC 9535 with opt-in typed function extensions. This page lists what that leaves out, the limits that protect your application from hostile input, and the precision of number comparisons.
Other JSONPath dialects
Before RFC 9535, JSONPath was an informal syntax with many variants. Their extensions are not supported, and Parse rejects most of them:
- No script expressions:
$.book[(@.length-1)]is invalid. Write$.book[-1]. - No
.lengthproperty:$.books.lengthis valid but selects a member namedlength. Count the matches instead, or uselength()in a filter. - No other operators: no
=~,in,nin,containsor regular expression literals (/.../). Usematch()andsearch(). - No parent or property name operators (
^,~), and no filters evaluated as JavaScript or C# code: filters use the standard operators and functions only. - Only five functions by default. Domain-specific functions require an explicit custom function registry.
var document = JsonNode.Parse("""{"books":[{"title":"A"},{"title":"B"}]}""");
// .length selects a member named "length", not the length of the array
Assert.Empty(JsonPath.Parse("$.books.length").Evaluate(document));
// Count the matches instead
Assert.HasCount(2, JsonPath.Parse("$.books[*]").Evaluate(document));Filters written as [?(@.price < 10)], with parentheses, are valid RFC 9535 and work unchanged.
Other features
- No changes through paths. There is no method to set, add or remove values by path. With
JsonNode, change the matched nodes yourself; see Change the matched values. - No streaming. The query runs on a parsed document (
JsonNode,JsonDocument,JsonElement) or on your own model, not on aUtf8JsonReaderor a stream. - Regular expressions are I-Regexp only.
match()andsearch()do not accept .NET-specific syntax, and^and$are not anchors. See Write the patterns.
Limits
For application-selected cancellation, work, final-match and intermediate-result limits, see Cancel or bound evaluation. These limits throw instead of silently truncating results and do not replace the structural limits below.
- Queries: filter expressions, nested filter selectors and function arguments nest up to 64 levels deep. Beyond that, Parse throws a
FormatExceptionand TryParse returnsfalse, so a hostile or generated query cannot exhaust the stack. - Documents: descendant segments (
..) and comparisons of arrays and objects visit at most 256 levels of nesting. Beyond that, evaluation throws a JsonPathEvaluationException, in both evaluation modes. Documents parsed bySystem.Text.Jsonwith its defaultMaxDepthof 64 never reach this limit; it only affects values built in code, parsed with a higherMaxDepth, or exposed by a custom navigator. - Indexes and slices: the numbers of index and slice selectors must be between -(253)+1 and 253-1, the I-JSON range; Parse rejects larger ones.
Number precision
Filters compare numbers, the literals of the query and the values of the document, as double values. Every integer between -(253)+1 and 253-1 and every number that a double represents exactly compare exactly. Outside that range, distinct numbers can compare as equal:
- Integers beyond ±(2^53)-1 are rounded:
$[?@ == 9007199254740993]matches9007199254740992. - Decimals are rounded to the nearest
double:$[?@ == 0.1]matches0.10000000000000001. - Numbers too large for a
doublebecome infinity:$[?@ == 1e400]matches1e500. - Numbers too small for a
doublebecome zero:$[?@ < 0]does not match-1e-400.
When exact values matter, such as identifiers or amounts of money, store them as strings in the document, or compare them in your code after the query.