You could add a couple of extension methods that access a child JsonElement
value by property name or array index, returning a nullable value if not found:
public static partial class JsonExtensions
{
public static JsonElement? Get(this JsonElement element, string name) =>
element.ValueKind != JsonValueKind.Null && element.ValueKind != JsonValueKind.Undefined && element.TryGetProperty(name, out var value)
? value : (JsonElement?)null;
public static JsonElement? Get(this JsonElement element, int index)
{
if (element.ValueKind == JsonValueKind.Null || element.ValueKind == JsonValueKind.Undefined)
return null;
// Throw if index < 0
return index < element.GetArrayLength() ? element[index] : null;
}
}
Now calls to access nested values can be chained together using the null-conditional operator ?.
:
var doc = JsonSerializer.Deserialize<JsonElement>(raw);
var node = doc.Get("data")?.Get("products")?.Get("edges")?.Get(0)?.Get("node");
var productIdString = node?.Get("id")?.GetString();
var originalSrcString = node?.Get("featuredImage")?.Get("originalSrc")?.GetString();
Int64? someIntegerValue = node?.Get("Size")?.GetInt64(); // You could use "var" here also, I used Int64? to make the inferred type explicit.
Notes:
-
The extension methods above will throw an exception if the incoming element is not of the expected type (object or array or null/missing). You could loosen the checks on
ValueKind
if you never want an exception on an unexpected value type. -
There is an open API enhancement request Add JsonPath support to JsonDocument/JsonElement #31068. Querying via JSONPath, if implemented, would make this sort of thing easier.
-
If you are porting code from Newtonsoft, be aware that
JObject
returnsnull
for a missing property, whileJArray
throws on an index out of bounds. Thus you might want to use theJElement
array indexer directly when trying to emulate Newtonsoft’s behavior, like so, since it also throws on an index out of bounds:var node = doc.Get("data")?.Get("products")?.Get("edges")?[0].Get("node");
Demo fiddle here.