Repository navigation
Description
Some feedback after using the new JsonNode apis for some time:
- For F# use JsonNode is missing a convenience method to safely 'dot into' a deep path. F# does not have a null conditional operator to conveniently intersperse between indexer calls. I've had to add something like the following code to make querying workable.
type JsonNode with
member node.GetNode(index: int) = Option.ofObj node.[index]
member node.GetNode(segment: string) = Option.ofObj node.[segment]
member node.GetNode([<ParamArray>]pathSegments: obj[]) =
let mutable current, i = node, 0
while not (isNull current) && i < pathSegments.Length do
match pathSegments.[i] with
| :? int as index -> current <- current.[index]
| :? string as segment -> current <- current.[segment]
| _ -> failwith "Unknown path segment type, either int or string is supported."
i <- i + 1
Option.ofObj currentIt could make sense to provide this in the box but mainly I wanted to note this usability issue for F#.
-
JsonArray is missing a convenience method to get an IEnumerable or array of * GetValue * results out. I'm assuming the alternative pattern is
node.AsArray().Select(x => x.GetValue<int>()). A direct method on JsonArray would be useful for discoverability. -
I'm missing an easy way to access (if available) PropertyName on JsonNode. I can parse it back out via GetPath or track it on the side during folds but it might be helpful to have an easier way for it?
-
For dynamic data or when converting JsonNode to another tree representation I'm missing any and all useful information on JsonValue. What kind might it be? Which
TryGetValuecalls are probably going to succeed? Is the expectation here to just probeTryGetValueagainst likely types? I get that you want to support arbitrary values to support whatever serialization conversions users may want but as a result handling json data with a conventional shape (primitives/JsonElement) is slightly crazy. Do I serialize JsonValue instances to json and deserialize to a JsonElement? IMO this severly limits the usability to just use it as a mutable version of JsonDocument. -
I really am missing DeepClone, DeepEquals, and Merge. I've written our own versions now but I'm probably not alone. (though again I understand with JsonValue being what it is it would be hard to provide useful and consistent semantics out of the box)
Beyond JsonNode I think a lot of us are still hoping for a 'one-shot' querying method on JsonDocument in the box. I'd be happy with anything given JsonPath was shot down here #31068 (comment). A lot of our code that queries json doesn't need to have a mutable model passed in. Having even the simplest workable querying options on JsonDocument/JsonElement should really come in the box and I'm sad to see any chances for it slip into 7.0.
Activity
danmoseley commentedon Jul 17, 2021
Cc @steveharter also
steveharter commentedon Jul 29, 2021
@NinoFloris thanks for the feedback as it helps determine priority and semantics. Most of the suggestions were previously considered, but scoped out for the initial feature set.
For now, I've added sample extensions below to demonstrate the easier ones including:
JsonArray.GetValues<T>(): returns a strongly-typed enumerator forT(for homogeneous arrays).GetAccessorFromPath(): returns the "JsonPath" syntax for the parent accessor which is either the property name, the array index with surrounding brackets, or$for a root node.GetValueKind(): returns theJsonValueKindfor a given node.DeepClone()andDeepCopy().For
GetValueKind()you can also call the existingjsonValue.GetValue<object>()to get the underlying value out and do any type-specific logic that way. In "read-mode" (after aJsonNode.Parse()) the underlying value will always be aJsonElementwhile in "edit-mode" the underlying type can be anything (JsonElement, object, collection, number, etc) depending on what was assigned; the extension handles both read- and edit-mode. I'm also updating the doc to make this more clear.Click for samples.
steveharter commentedon Jul 30, 2021
Moving to 7.0; 6.0 is pretty much locked down for new APIs, especially if there are workarounds.
See also the API issue here #56592.
A larger feature may be necessary for JsonPath in general, including querying, that will address the F# issue and others including those from #31068
eiriktsarpalis commentedon Jan 13, 2022
Closing in favor of #56592.
Gonkers commentedon Jan 14, 2022
Oh, my goodness, thank you @NinoFloris for suggesting this back in July to get it on the radar! I just discovered JsonNode and now that I've been using it, not being able to get the JSON data type is driving me batty.