JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.71k stars 3.24k forks source link

Valid JsonPath expression `$.*` on Json Array results in exception #2913

Open gorillapower opened 9 months ago

gorillapower commented 9 months ago

Source/destination JSON

[{"item":"two"},{"item":"two"},{"item":"two"}]

Expected behavior

Executing JToken.SelectTokens("$.*") on a valid JSON array should produce multiple JToken results

Actual Behavior

Newtonsoft.Json.JsonException: Property '*' not valid on JArray.
   at Newtonsoft.Json.Linq.JsonPath.FieldFilter.ExecuteFilter(JToken root, IEnumerable`1 current, JsonSelectSettings settings)+MoveNext()
   at System.Collections.Generic.LargeArrayBuilder…

Repro Steps

https://dotnetfiddle.net/ginhZu

var json = """[{"item":"two"},{"item":"two"},{"item":"two"}]""";

var parsed = JToken.Parse(json);
var query = parsed.SelectTokens("$.*",true).ToList();    

Running the same query here https://json-everything.net/json-path produces a valid result.

WorkAround

JsonPath $[*] products the expected result

elgonzo commented 9 months ago

To add to the report, according to the JsonPath draft spec, section 1.4.4, .* is a shorthand/alias for [*]. Therefore, $.* is equivalent to $[*].

However, not only does Newtonsoft.Json implement .* incorrectly, it also implements [*] incorrectly.

Since .* is a shorthand/alias for [*], both .* and [*] should be applicable to objects AND arrays equally. But Newtonsoft.Json treats both .* and [*] differently, in violation of the JsonPath draft spec i linked to above. .* works on objects but incorrectly not on arrays, as the report pointed out. And [*] works on arrays but incorrectly not on objects.


P.S.: While the very first Json draft spec version 00 -- draft-ietf-jsonpath-base-00 -- also already explains the .* semantics in section 3.6.1, the draft spec version 00 seems to lack any formal definition for [*] -- it only mentions

JSONPath allows the wildcard symbol "*" for member names and array indices

in passing. The same mention appears at https://goessner.net/articles/JsonPath/, and Newtonsoft.Json therefore seems to also violate the old Goessner draft from 2007 in this respect...