A lightweight and efficient C# library designed to extract deep-nested values from a JsonDocument using a simple slash-separated (/) path syntax (similar to JSON Pointer).
- Path-based Extraction: Retrieve data using simple paths like
company/departments/0/name. - Zero-allocation Traversal: Traverses the JSON tree efficiently without parsing the entire structure upfront.
- Two Flavors Available:
- Dynamic Approach (
JsonExtensions): Returns objects as primitive types, arrays, orExpandoObjectfor easydynamicusage. - Optimized Approach (
JsonExtensionsOptimized): Returns objects asJsonObject(implementingIDictionary<string, JsonNode?>), tailored for high-performance and modernSystem.Text.Jsonfeatures.
- Dynamic Approach (
Ensure your project targets at least .NET 10.0 or higher, as it relies on the built-in System.Text.Json ecosystem.
This method fits best if you prefer working with the dynamic keyword in C# and want objects converted into ExpandoObject.
using System;
using System.Text.Json;
using JsonExplorer;
string json = """
{
"user": {
"name": "John Doe",
"skills": ["C#", "F#"]
}
}
""";
using JsonDocument doc = JsonDocument.Parse(json);
// 1. Get a primitive value
string? name = doc.GetDynamicValueByPath("user/name") as string;
Console.WriteLine(\$"Name: {name}"); // Output: John Doe
// 2. Get an element from an array by index
string? firstSkill = doc.GetDynamicValueByPath("user/skills/0") as string;
Console.WriteLine(\$"First Skill: {firstSkill}"); // Output: C#
// 3. Get an object dynamically
dynamic? user = doc.GetDynamicValueByPath("user");
if (user != null)
{
Console.WriteLine(\$"Dynamic Name: {user.name}");
}This method returns nested JSON objects as JsonObject, allowing you to leverage type-safe JsonNode APIs. It is highly optimized for modern .NET applications.
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes;
using JsonExplorer;
string json = """
{
"server": {
"port": 8080,
"status": "active"
}
}
""";
using JsonDocument doc = JsonDocument.Parse(json);
// 1. Get a primitive value directly
long port = (long)(doc.GetValueByPath("server/port") ?? 0L);
Console.WriteLine(\$"Port: {port}"); // Output: 8080
// 2. Safely cast an object to a dictionary interface
var serverObj = doc.GetValueByPath("server") as IDictionary<string, JsonNode?>;
if (serverObj != null)
{
string? status = serverObj["status"]?.GetValue<string>();
Console.WriteLine(\$"Status: {status}"); // Output: active
}When a path points to a specific JSON token, the methods map them to native C# types as follows:
| JSON Value Kind | GetDynamicValueByPath Result |
GetValueByPath Result |
|---|---|---|
| String | string |
string |
| Number (Integer) | long |
long |
| Number (Float) | double |
double |
| True / False | bool |
bool |
| Null / Undefined | null |
null |
| Object | ExpandoObject |
JsonObject |
| Homogeneous Array | Typed Array (e.g., string[], long[]) |
Typed Array (e.g., string[], long[]) |
| Mixed Array | object[] |
object[] |
The project comes with a comprehensive suite of unit tests written using NUnit.
To execute all tests, run the following command in your terminal from the project root directory:
dotnet test- Retrieval of all primitive data types (
string,long,double,bool,null). - Deep path resolution through nested objects and array indices.
- Type mapping checks for homogeneous arrays vs mixed-type arrays.
- Validation for empty paths throwing an
ArgumentException.