Class JsonUtil
- Namespace
- Invex.Extensions.Json
- Assembly
- Invex.Extensions.Json.dll
Provides extension members on System.Text.Json.Nodes.JsonObject for flattening a hierarchical JSON structure into a single level and reconstructing (unflattening) it again.
Path conventions used by this class:
-
Object property segments are joined with a configurable separator (default
":"), e.g.,"user:address:city". -
Array elements are addressed with bare zero-based numeric segments, e.g.,
"users:0:name".
Note: this differs from Flatten(JsonNode, string), which uses bracketed
indices such as "users:[0]:name".
public static class JsonUtil
- Inheritance
-
objectJsonUtil
Methods
HasNestedObjects(JsonObject)
Determines whether this System.Text.Json.Nodes.JsonObject contains any nested containers, i.e., whether any direct property value is a System.Text.Json.Nodes.JsonObject or System.Text.Json.Nodes.JsonArray.
public static bool HasNestedObjects(this JsonObject jsonObject)
Parameters
jsonObjectJsonObject
Returns
- bool
trueif at least one direct property value is an object or array; otherwise,false.
Remarks
Only the top level is inspected; this is a quick check for whether the object is already "flat".
ToFlattenedDictionary(JsonObject, string)
Flattens this System.Text.Json.Nodes.JsonObject into a System.Collections.Generic.Dictionary<TKey, TValue> mapping each leaf path to its string representation.
public static Dictionary<string, string?> ToFlattenedDictionary(this JsonObject jsonObject, string separator = ":")
Parameters
jsonObjectJsonObjectseparatorstringThe string used to join path segments. May be more than one character. Defaults to
":".
Returns
- Dictionary<string, string>
A dictionary in which:
-
Each key is the separator-joined path to a leaf value (array elements use bare numeric
segments, e.g.,
"users:0:name"). -
String values are stored verbatim; numbers use their raw JSON text; booleans become
"true"/"false"; JSON nulls becomenullentries.
Keys appear in depth-first, insertion order. The source object is not modified.
-
Each key is the separator-joined path to a leaf value (array elements use bare numeric
segments, e.g.,
Examples
var obj = JsonNode.Parse("""{ "user": { "age": 42, "active": true } }""").AsObject();
var flat = obj.ToFlattenedDictionary();
// { ["user:age"] = "42", ["user:active"] = "true" }
Remarks
Because all values are converted to strings, the original JSON value kinds (number vs. string vs. boolean) are not recoverable from the result. Use ToFlattenedJsonObject(JsonObject, string) when type fidelity matters.
Empty nested objects and arrays produce no entries in the output.
Exceptions
- InvalidOperationException
Thrown if a leaf node reports an unexpected System.Text.Json.JsonValueKind (e.g., System.Text.Json.JsonValueKind.Undefined); this is not expected for well-formed JSON.
ToFlattenedJsonObject(JsonObject, string)
Flattens this System.Text.Json.Nodes.JsonObject into a new single-level System.Text.Json.Nodes.JsonObject whose keys are full paths to each leaf value.
public static JsonObject ToFlattenedJsonObject(this JsonObject jsonObject, string separator = ":")
Parameters
jsonObjectJsonObjectseparatorstringThe string used to join path segments. May be more than one character. Defaults to
":".
Returns
- JsonObject
A new System.Text.Json.Nodes.JsonObject in which:
-
Each key is the separator-joined path to a leaf value (array elements use bare numeric
segments, e.g.,
"users:0:name"). - Each value is a deep clone of the original leaf node, so JSON types (string, number, boolean) are preserved and no references are shared with the source object.
- JSON null leaves are preserved as null values.
Keys appear in depth-first, insertion order. The source object is not modified.
-
Each key is the separator-joined path to a leaf value (array elements use bare numeric
segments, e.g.,
Examples
var obj = JsonNode.Parse("""{ "user": { "name": "John", "tags": ["admin", "user"] } }""").AsObject();
var flat = obj.ToFlattenedJsonObject();
// {"user:name":"John","user:tags:0":"admin","user:tags:1":"user"}
Remarks
Empty nested objects and arrays produce no entries in the output, so they are not round-trippable via ToUnflattenedJsonObject(JsonObject, string).
Choose a separator that does not occur in any property name; otherwise unflattening will split those names incorrectly.
ToUnflattenedJsonObject(JsonObject, string)
Reconstructs a hierarchical System.Text.Json.Nodes.JsonObject from a flattened object whose keys are separator-joined paths, reversing ToFlattenedJsonObject(JsonObject, string).
public static JsonObject ToUnflattenedJsonObject(this JsonObject jsonObject, string separator = ":")
Parameters
jsonObjectJsonObjectseparatorstringThe string used to split keys into path segments. Must match the separator used when flattening. May be more than one character. Defaults to
":".
Returns
- JsonObject
A new System.Text.Json.Nodes.JsonObject with nested objects and arrays rebuilt from the paths:
- A purely numeric segment causes its parent container to be created as a System.Text.Json.Nodes.JsonArray; any other segment creates a System.Text.Json.Nodes.JsonObject.
- Leaf values are deep clones of the source values, so no references are shared.
-
Sparse array indices are padded with nulls (e.g., a single key
"items:2"yields[null, null, value]).
The source object is not modified.
Examples
var flat = new JsonObject
{
["user:name"] = "John",
["user:tags:0"] = "admin",
["user:tags:1"] = "user",
};
var obj = flat.ToUnflattenedJsonObject();
// {"user":{"name":"John","tags":["admin","user"]}}
Remarks
Property names that are purely numeric are indistinguishable from array indices and will be reconstructed as array elements.
If the same path is supplied more than once, the last value wins.
Exceptions
- InvalidOperationException
Thrown when a non-numeric segment is used where an array index is required (i.e., the structure implied by one key conflicts with an array created for another key).