Generate LINQ expressions from Kubernetes JSONPath paths over CLR and System.Text.Json object graphs.
JsonPathLINQ converts Kubernetes JSONPath-style paths into LINQ expressions:
Expression<Func<T, TResult>>It is intended for querying:
- regular CLR object graphs
- dictionaries
- collections
- mixed CLR +
System.Text.Jsonobject graphs
The public API is:
var expression = JsonPath.GetExpression<T>(jsonPath, addNullChecks: false);
var typedExpression = JsonPath.GetExpression<T, TResult>(jsonPath, addNullChecks: false);This library is focused on expression generation for the Kubernetes JSONPath dialect used by kubectl.
- Inputs follow the Kubernetes JSONPath template/path dialect used by
kubectl. - RFC 9535 style paths beginning with
$are supported only for the subset implemented by the expression generator. - The primary goal of the package is expression generation over CLR and
System.Text.Jsonobject graphs, not complete JSONPath evaluation compatibility.
Install-Package JsonPathLINQThe current expression generator supports:
- field/property access:
.name,.parent.child - case-insensitive CLR member lookup
- dictionary key access:
.labels.key,.labels.crossplane\.io/external-name - array index and slice access:
.items[0],.items[-1],.items[1:4],.items[0:6:2] - wildcard segments:
* - recursive descent:
.. - unions
- collection filtering with
FirstOrDefault:.items[?(@.status=="Ready")] - filter operators:
==,!=,<,>,<=,>= - null literal in filters:
.items[?(@.nullable==null)] - optional null-propagation via
addNullChecks: true System.Text.Jsontraversal through:JsonElementJsonDocumentJsonNodeJsonObjectJsonArrayJsonValue
When the terminal JSON value is a scalar, the compiled expression returns a natural CLR value where practical:
- string ->
string - number -> numeric CLR type
- boolean ->
bool - null ->
null
When the terminal JSON value is an object or array, the expression keeps it as an STJ container so it can still be traversed naturally:
JsonElementcontainers remainJsonElementJsonObject/JsonArrayremain node containers
The library does not currently generate expressions for:
- multi-select roots or templates with multiple root actions
- full Kubernetes template evaluation semantics
- full RFC 9535 JSONPath compliance
The broader tests in this repository cover more parser and template behavior, but the generated expression API is still intentionally scoped to the features listed above.
public sealed class TestObject
{
public string? StringValue { get; set; }
}
var expression = JsonPath.GetExpression<TestObject>(".StringValue");
var compiled = expression.Compile();
var result = compiled(new TestObject { StringValue = "hello" });
// "hello"public sealed class Pod
{
public List<Container> Containers { get; set; } = [];
}
public sealed class Container
{
public string? Name { get; set; }
public string? Status { get; set; }
}
var expression = JsonPath.GetExpression<Pod>(
".Containers[?(@.Status==\"Ready\")].Name");
var compiled = expression.Compile();public sealed class MyClass
{
public JsonNode? MyNode { get; set; }
public JsonElement MyElement { get; set; }
public JsonDocument MyDocument { get; set; } = JsonDocument.Parse("{}");
}
var instance = new MyClass
{
MyNode = JsonNode.Parse("""{ "foo": { "bar": "node" } }"""),
MyElement = JsonDocument.Parse("""{ "foo": { "bar": "element" } }""").RootElement.Clone(),
MyDocument = JsonDocument.Parse("""{ "foo": { "bar": "document" } }""")
};
var fromNode = JsonPath
.GetExpression<MyClass>(".MyNode.foo.bar")
.Compile()(instance);
var fromElement = JsonPath
.GetExpression<MyClass>(".MyElement.foo.bar")
.Compile()(instance);
var fromDocument = JsonPath
.GetExpression<MyClass>(".MyDocument.foo.bar")
.Compile()(instance);var expression = JsonPath.GetExpression<MyClass>(
".MyNode.foo.missing.value",
addNullChecks: true);
var compiled = expression.Compile();
var result = compiled(instance);
// null- Kubernetes-style paths may be passed with or without outer
{}. - Template-style inputs such as
hello {.Name}are part of the Kubernetes JSONPath dialect, not RFC 9535 JSONPath. $...paths use the RFC-oriented parser path, but only the subset listed above is currently supported for expression generation.- The generator expects a single root action.
- The generated filter behavior is based on
Enumerable.FirstOrDefault(...), so a filter selects one matching item rather than projecting all matches. - Paths that naturally project multiple values such as wildcards, unions, recursive descent, and slices return an
object?[]when used throughGetExpression<T>(...).