JsonSift 1.0.0

dotnet add package JsonSift --version 1.0.0
                    
NuGet\Install-Package JsonSift -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JsonSift" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="JsonSift" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="JsonSift" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add JsonSift --version 1.0.0
                    
#r "nuget: JsonSift, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package JsonSift@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=JsonSift&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=JsonSift&version=1.0.0
                    
Install as a Cake Tool

Nuget Nuget

JsonSift

A small, safe, bounded expression language over in-memory JSON (System.Text.Json). Point it at a JsonNode and:

  • navigate with $-paths — $.user.name, $.items[0], $.items[*].id
  • filter arrays with one comparison — $.items[?id == $.current.id].name
  • evaluate boolean conditions — $.amount > 1000 && $.country in ['ES','PT']
  • interpolate strings — "Hi {name}" with a {hole} → path map

It is a deliberately small subset: no recursive descent (..), no functions, no arithmetic, no code execution. The whole surface is hand-written and auditable — you navigate data, nothing else. That makes it a good fit for user-supplied templates, rules, and config where you must not hand over a general expression engine.

Install

dotnet add package JsonSift

Multi-targets net8.0, net9.0, net10.0. Only dependency: System.Text.Json (in-box).

Quickstart

using JsonSift;                 // SiftContext, JsonExpr, exceptions
using JsonSift.Paths;           // PathExpression, CompiledPath
using JsonSift.Conditions;      // ConditionParser, ConditionEvaluator
using JsonSift.Interpolation;   // StringInterpolator
using System.Text.Json.Nodes;

// 1) Build the root document from heterogeneous inputs (or use any JsonNode you already have)
JsonObject root = new SiftContext()
    .AddNode("payload", payloadJsonElement)   // JsonElement / JsonDocument / JsonNode / any T
    .AddNode("user", new { id = "u2", name = "Bob" })
    .Build();

// 2) Compile once (this validates syntax and throws ExpressionParseException on errors)
CompiledPath path = PathExpression.Parse("$.user.name");
CompiledCondition cond = ConditionParser.Parse("$.payload.amount > 1000");
CompiledTemplateString tpl = StringInterpolator.Compile(
    "Hi {name}", new Dictionary<string, string> { ["name"] = "$.user.name" });

// 3) Evaluate against any JsonNode root
JsonNode? name = PathExpression.ResolveSingle(path, root);   // "Bob"
bool ok        = ConditionEvaluator.Evaluate(cond, root);   // true/false
string text    = StringInterpolator.Interpolate(tpl, root); // "Hi Bob"

// Typed resolution with coercion:
string? n = JsonExpr.ResolveAs<string>(path, root);

Grammar at a glance

Form Meaning
$.a.b / $['weird key'] member access
$.a[0] array index
$.a[*] wildcard projection → a list
$.a[?field op operand] keep array elements where one comparison holds
operators == != > >= < <= (filters & conditions)
conditions && \|\| ! (...), x in ['a','b'], x matches 'regex', bare path = truthy
operand literal ('str', number, true/false/null) or an absolute $... path

A path with [*] or a filter yields a list; otherwise a single value. A missing member/index resolves to null (never throws).

Two things to know

  • == coerces numeric strings (SQL-like): "1" == 1 is true. This is not RFC 9535 behaviour — see Documents/07-vs-rfc-9535.md.
  • Filters use a bare field name ([?id == ...]), not @.id. One comparison only — no &&/||/nesting inside a filter.

Documentation

Full docs live in Documents/:

  1. Overview — concepts, types, API map
  2. Grammar — paths, indices, wildcards, filters, cardinality
  3. Conditions — booleans, in, matches, truthiness
  4. Interpolation — literals, bare paths, {holes}
  5. SiftContext — assembling the root from JsonElement/JsonDocument/T
  6. Coercion — equality, ordering, dates, truthiness, to-string
  7. vs RFC 9535 — how this differs from standard JSONPath

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 131 6/30/2026