Blazing.Json.JSONPath
1.1.0
dotnet add package Blazing.Json.JSONPath --version 1.1.0
NuGet\Install-Package Blazing.Json.JSONPath -Version 1.1.0
<PackageReference Include="Blazing.Json.JSONPath" Version="1.1.0" />
<PackageVersion Include="Blazing.Json.JSONPath" Version="1.1.0" />
<PackageReference Include="Blazing.Json.JSONPath" />
paket add Blazing.Json.JSONPath --version 1.1.0
#r "nuget: Blazing.Json.JSONPath, 1.1.0"
#:package Blazing.Json.JSONPath@1.1.0
#addin nuget:?package=Blazing.Json.JSONPath&version=1.1.0
#tool nuget:?package=Blazing.Json.JSONPath&version=1.1.0
Blazing.Json.JSONPath
Table of Contents
- Overview
- Key Features
- Why Choose Blazing.Json.JSONPath?
- RFC 9535 Compliance
- Getting Started
- Usage
- JSONPath Syntax
- How It Works
- Performance Characteristics
- Samples
- Give a ⭐
- Support
- History
Overview
Blazing.Json.JSONPath is a high-performance, 100% RFC 9535 compliant JSONPath implementation for .NET. This library enables powerful querying of JSON documents using standardized JSONPath syntax, providing a robust and reliable solution for navigating complex JSON structures.
Unlike other JSONPath implementations that may use custom or non-standard syntax, Blazing.Json.JSONPath strictly adheres to the RFC 9535 specification, ensuring predictable behavior and maximum interoperability with other RFC-compliant tools.
Whether you're querying API responses, processing configuration files, or analyzing complex data structures, Blazing.Json.JSONPath provides the precision and reliability you need with the familiar JSONPath syntax you already know.
Key Features
- ✅ 100% RFC 9535 Compliant: Certified through 324 comprehensive unit tests
- ✅ Standards-Based: Official RFC 9535 JSONPath specification support
- ✅ All Selector Types: Name, wildcard, index, slice, and filter selectors
- ✅ Recursive Descent: Navigate nested structures with
..operator - ✅ Filter Expressions: Complex filtering with comparison and logical operators
- ✅ Built-in Functions: All 5 RFC functions (length, count, match, search, value)
- ✅ Type System: Full RFC type system (ValueType, NodesType, LogicalType)
- ✅ Unicode Support: Complete Unicode handling including surrogate pairs
- ✅ .NET 10 Optimized: Built for the latest .NET with modern C# features
- ✅ High Performance: Zero-allocation design with efficient buffer management
- ✅ Production Ready: Zero compiler warnings, comprehensive documentation
Why Choose Blazing.Json.JSONPath?
Standards Compliance
Blazing.Json.JSONPath is 100% RFC 9535 compliant, validated through comprehensive testing:
Test Summary:
Total: 324 tests
Passed: 324 tests ✅
Failed: 0 tests ✅
Skipped: 0 tests
Success: 100% ✅
This compliance ensures:
- Predictable Behavior: Queries work exactly as specified in RFC 9535
- Interoperability: Compatible with other RFC-compliant JSONPath tools
- Future-Proof: Based on official IETF standard, not custom syntax
- Trustworthy: Every RFC feature thoroughly tested and validated
Official RFC 9535 Specification
The RFC 9535 specification defines the standard JSONPath query language. Blazing.Json.JSONPath implements every aspect of this specification:
| RFC Component | Compliance | Tests |
|---|---|---|
| Lexer (2.1) | ✅ 100% | 100+ |
| Parser (2.2-2.3) | ✅ 100% | 50+ |
| Evaluator (2.3-2.4) | ✅ 100% | 120+ |
| Filter Expressions (2.3.5) | ✅ 100% | 80+ |
| Functions (2.4) | ✅ 100% | 35+ |
| TOTAL | ✅ 100% | 324 |
For detailed compliance verification, see:
When to Use This Library
✅ Use Blazing.Json.JSONPath When:
- You need standards-compliant JSONPath queries
- Working with complex JSON structures (nested objects/arrays)
- Filtering JSON data with sophisticated expressions
- Extracting specific values from large JSON documents
- Querying API responses with predictable JSONPath syntax
- Building tools that require RFC 9535 compliance
- Need production-ready, well-tested implementation
RFC 9535 Compliance
Blazing.Json.JSONPath is certified 100% compliant with RFC 9535 - JSONPath: Query Expressions for JSON.
Compliance Certification
Certification Date: January 11, 2026
Standard Version: RFC 9535
Test Coverage: 324 passing tests (0 failures)
Validation: All RFC features, semantics, and edge cases verified
Complete Feature Implementation
All RFC 9535 features are fully implemented and tested:
- ✅ Lexical Grammar - All token types (100+ tests)
- ✅ Syntax Parsing - Full ABNF compliance (50+ tests)
- ✅ Selectors - All 5 selector types (80+ tests)
- Name, Wildcard, Index, Slice, Filter
- ✅ Segments - Child and Descendant (40+ tests)
- ✅ Filter Expressions - Complete (80+ tests)
- Logical operators (AND, OR, NOT)
- Comparison operators (==, !=, <, ⇐, >, >=)
- Existence tests
- RFC Table 11 semantics
- ✅ Functions - All 5 built-in functions (35+ tests)
- length(), count(), match(), search(), value()
- ✅ Type System - Full compliance
- ValueType, NodesType, LogicalType
- Type conversions per RFC 2.4.2
Semantic Correctness
Perfect implementation of all RFC semantics:
- ✅ Comparison Engine - RFC Table 11 exact match
- ✅ Array Slicing - RFC 2.3.4.2.2 normalization
- ✅ Filter Truthiness - RFC 2.3.5.3 compliance
- ✅ Unicode Support - Complete surrogate pair handling
For complete compliance details, see RFC9535_COMPLIANCE_VERIFICATION.md.
Getting Started
Installation
Install via NuGet Package Manager:
<PackageReference Include="Blazing.Json.JSONPath" Version="1.0.0" />
Or via the .NET CLI:
dotnet add package Blazing.Json.JSONPath
Or via the Package Manager Console:
Install-Package Blazing.Json.JSONPath
Requirements
- .NET 10.0 or later
- System.Text.Json (included with .NET)
Quick Start
using System.Text.Json;
using Blazing.Json.JSONPath.Parser;
using Blazing.Json.JSONPath.Evaluator;
// Sample JSON data
var json = JsonDocument.Parse("""
{
"store": {
"book": [
{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95},
{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "price": 8.99},
{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "price": 22.99}
],
"bicycle": {"color": "red", "price": 19.95}
}
}
""");
// Parse JSONPath query
var query = JsonPathParser.Parse("$.store.book[?@.price < 10]");
// Evaluate query
var evaluator = new JsonPathEvaluator();
var results = evaluator.Evaluate(query, json.RootElement);
// Process results
foreach (var result in results)
{
Console.WriteLine($"{result.NormalizedPath}: {result.Value}");
}
// Output:
// $['store']['book'][0]: {"category":"reference","author":"Nigel Rees",...}
// $['store']['book'][1]: {"category":"fiction","author":"Herman Melville",...}
Usage
Basic Queries
Navigate JSON structures with standard JSONPath syntax:
var bookstore = JsonDocument.Parse("""
{
"store": {
"book": [
{"title": "Book 1", "price": 8.95},
{"title": "Book 2", "price": 12.99},
{"title": "Book 3", "price": 8.99}
]
}
}
""").RootElement;
// Root identifier
var query1 = JsonPathParser.Parse("$");
var all = evaluator.Evaluate(query1, bookstore);
// Name selector (dot notation)
var query2 = JsonPathParser.Parse("$.store.book");
var books = evaluator.Evaluate(query2, bookstore);
// Name selector (bracket notation)
var query3 = JsonPathParser.Parse("$['store']['book']");
var booksAlt = evaluator.Evaluate(query3, bookstore);
// Array index
var query4 = JsonPathParser.Parse("$.store.book[0]");
var firstBook = evaluator.Evaluate(query4, bookstore);
// Negative index (from end)
var query5 = JsonPathParser.Parse("$.store.book[-1]");
var lastBook = evaluator.Evaluate(query5, bookstore);
// Wildcard selector
var query6 = JsonPathParser.Parse("$.store.book[*].title");
var allTitles = evaluator.Evaluate(query6, bookstore);
Filter Expressions
Powerful filtering with comparison and logical operators:
var products = JsonDocument.Parse("""
{
"products": [
{"name": "Laptop", "price": 1200, "category": "electronics", "inStock": true},
{"name": "Mouse", "price": 25, "category": "electronics", "inStock": true},
{"name": "Desk", "price": 350, "category": "furniture", "inStock": true},
{"name": "Chair", "price": 200, "category": "furniture", "inStock": false}
]
}
""").RootElement;
// Comparison operators
var cheap = JsonPathParser.Parse("$.products[?@.price < 100]");
var expensive = JsonPathParser.Parse("$.products[?@.price >= 200]");
var exactPrice = JsonPathParser.Parse("$.products[?@.price == 350]");
// Logical AND
var cheapElectronics = JsonPathParser.Parse(
"$.products[?@.price < 100 && @.category == 'electronics']");
// Logical OR
var furnitureOrCheap = JsonPathParser.Parse(
"$.products[?@.category == 'furniture' || @.price < 50]");
// Logical NOT
var outOfStock = JsonPathParser.Parse("$.products[?!@.inStock]");
// Existence tests
var withOptionalField = JsonPathParser.Parse("$.products[?@.optional]");
// Complex nested conditions
var complex = JsonPathParser.Parse(
"$.products[?(@.price > 100 && @.inStock) || @.category == 'electronics']");
Built-in Functions
All RFC 9535 functions are supported:
var data = JsonDocument.Parse("""
{
"users": [
{"name": "Alice", "email": "alice@example.com", "tags": ["admin", "user"]},
{"name": "Bob", "email": "bob@test.org", "tags": ["user"]},
{"name": "Charlie", "email": "charlie@example.com", "tags": ["user", "moderator"]}
]
}
""").RootElement;
// length() - String, array, or object length
var longNames = JsonPathParser.Parse("$.users[?length(@.name) > 5]");
var manyTags = JsonPathParser.Parse("$.users[?length(@.tags) > 1]");
// count() - Count nodelist elements
var userCount = JsonPathParser.Parse("$[?count($.users[*]) > 2]");
// match() - Full regex match (I-Regexp RFC 9485)
var dotComEmails = JsonPathParser.Parse("$.users[?match(@.email, '.*\\.com$')]");
// search() - Substring regex search
var hasExample = JsonPathParser.Parse("$.users[?search(@.email, 'example')]");
// value() - Convert singular nodelist to value
var singleUser = JsonPathParser.Parse("$.users[?@.name == 'Alice']");
// Use value() in filter: "$.users[?value(@.tags[0]) == 'admin']"
Array Slicing
RFC-compliant array slicing with start, end, and step:
var numbers = JsonDocument.Parse("""
{
"items": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}
""").RootElement;
// Basic slicing [start:end]
var firstThree = JsonPathParser.Parse("$.items[0:3]"); // [0, 1, 2]
var middleItems = JsonPathParser.Parse("$.items[3:7]"); // [3, 4, 5, 6]
// Default start (from beginning)
var upToFive = JsonPathParser.Parse("$.items[:5]"); // [0, 1, 2, 3, 4]
// Default end (to end of array)
var fromFive = JsonPathParser.Parse("$.items[5:]"); // [5, 6, 7, 8, 9]
// Negative indices (from end)
var lastTwo = JsonPathParser.Parse("$.items[-2:]"); // [8, 9]
var exceptLast = JsonPathParser.Parse("$.items[:-1]"); // [0, 1, 2, ..., 8]
// Step (every nth element)
var everyOther = JsonPathParser.Parse("$.items[::2]"); // [0, 2, 4, 6, 8]
var everyThird = JsonPathParser.Parse("$.items[1::3]"); // [1, 4, 7]
// Negative step (reverse)
var reversed = JsonPathParser.Parse("$.items[::-1]"); // [9, 8, 7, ..., 0]
var reverseEvery2 = JsonPathParser.Parse("$.items[::-2]"); // [9, 7, 5, 3, 1]
Recursive Descent
Navigate deeply nested structures with the descendant operator:
var company = JsonDocument.Parse("""
{
"company": {
"departments": [
{
"name": "Engineering",
"employees": [
{"name": "Alice", "role": "Senior Dev"},
{"name": "Bob", "role": "Developer"}
]
},
{
"name": "Sales",
"teams": [
{
"region": "North",
"members": [
{"name": "Charlie", "role": "Sales Manager"}
]
}
]
}
]
}
}
""").RootElement;
// Find all 'name' fields at any depth
var allNames = JsonPathParser.Parse("$..name");
// Find all employees arrays
var allEmployees = JsonPathParser.Parse("$..employees");
// Combine recursive descent with filters
var allManagers = JsonPathParser.Parse("$..[?@.role == 'Sales Manager']");
// Recursive descent with wildcards
var allArrayElements = JsonPathParser.Parse("$..[*]");
JSONPath Syntax
Selectors
| Selector | Syntax | Description | Example |
|---|---|---|---|
| Root | $ |
Root node | $ |
| Name | .name or ['name'] |
Object member | $.store.book |
| Wildcard | * or [*] |
All elements | $.store.* |
| Index | [index] |
Array element | $.book[0] |
| Slice | [start:end:step] |
Array slice | $.book[0:3] |
| Filter | ?[expr] |
Filtered elements | $.book[?@.price < 10] |
Segments
| Segment | Syntax | Description | Example |
|---|---|---|---|
| Child | . or [] |
Direct children | $.store.book |
| Descendant | .. |
All descendants | $..author |
Filter Expressions
Filter expressions use @ for the current node and support:
Comparison Operators
| Operator | Description | Example |
|---|---|---|
== |
Equal | @.price == 8.95 |
!= |
Not equal | @.category != 'fiction' |
< |
Less than | @.price < 10 |
<= |
Less than or equal | @.price <= 10 |
> |
Greater than | @.price > 10 |
>= |
Greater than or equal | @.price >= 10 |
Logical Operators
| Operator | Description | Example |
|---|---|---|
&& |
Logical AND | @.price < 10 && @.inStock |
\|\| |
Logical OR | @.category == 'fiction' \|\| @.price < 5 |
! |
Logical NOT | !@.inStock |
Existence Tests
Test if a field exists (non-empty nodelist):
// Has optional field
$.items[?@.optional]
// Has nested property
$.users[?@.profile.avatar]
Built-in Functions
| Function | Signature | Description | Example |
|---|---|---|---|
length() |
length(value) |
String/array/object length | length(@.name) > 5 |
count() |
count(nodelist) |
Count nodes in nodelist | count(@.tags) > 2 |
match() |
match(string, pattern) |
Full regex match | match(@.email, '.*\\.com$') |
search() |
search(string, pattern) |
Substring regex search | search(@.name, 'Smith') |
value() |
value(nodelist) |
Singular nodelist to value | value(@.items[0]) |
How It Works
Blazing.Json.JSONPath uses a three-stage processing pipeline:
Lexical Analysis (Lexer): Tokenizes JSONPath query strings
- Recognizes all RFC 9535 token types
- Handles string escaping and Unicode
- Source-generated regex for performance
Syntax Analysis (Parser): Builds Abstract Syntax Tree (AST)
- Validates query syntax against RFC grammar
- Constructs selector and segment nodes
- Parses filter expressions and function calls
Evaluation (Evaluator): Executes query against JSON document
- Applies selectors to navigate JSON structure
- Evaluates filter expressions with proper type handling
- Executes built-in functions
- Returns normalized paths and values
Execution Flow Example
// Query: Find books under $10
var query = "$.store.book[?@.price < 10]";
// 1. Lexer: Tokenize
// $ . store . book [ ? @ . price < 10 ]
// ROOT DOT NAME DOT NAME LBRACKET FILTER ...
// 2. Parser: Build AST
// Query
// ?? RootSegment ($)
// ?? ChildSegment (.store)
// ?? ChildSegment (.book)
// ?? FilterSelector (?@.price < 10)
// 3. Evaluator: Execute
// - Start at root
// - Navigate to store
// - Navigate to book array
// - For each book:
// * Evaluate @.price < 10
// * If true, include in results
// - Return matching nodes with normalized paths
Performance Characteristics
Zero-Allocation Design
- ✅
ArrayPool<T>for buffer management - ✅ Span-based string operations
- ✅ Value types for tokens and nodes
- ✅ Lazy evaluation with
yield return
Optimization Features
- ✅ Complexity analyzer for fast-path routing
- ✅ Source-generated regex for lexer
- ✅ Efficient buffer growth strategies
- ✅ Short-circuit evaluation in logical operators
Typical Performance
| Operation | Time | Allocations |
|---|---|---|
| Parse simple query | ~1-5 µs | Minimal |
| Parse complex filter | ~10-20 µs | Low |
| Evaluate small JSON | ~5-10 µs | Pooled buffers |
| Evaluate 1MB JSON | ~100-500 µs | Constant memory |
Note: Performance varies based on query complexity and JSON structure. Run benchmarks in your specific scenarios.
Samples
The library includes comprehensive sample projects demonstrating different usage patterns:
Sample Projects
All samples are located in the samples/Blazing.Json.JSONPath.Samples directory:
- Basic Selectors - Name, wildcard, index, slice selectors
- Filter Expressions - Comparison and logical operators
- Built-in Functions - All five RFC 9535 functions
- Advanced Features - Recursive descent and complex queries
- RFC Examples - Direct examples from RFC 9535 specification
Running the Samples
# Clone the repository
git clone https://github.com/gragra33/Blazing.Json.JSONPath.git
cd Blazing.Json.JSONPath
# Run the samples project
dotnet run --project samples/Blazing.Json.JSONPath.Samples
The samples include:
- Interactive console demonstrations
- All RFC 9535 selector types
- Filter expression examples
- Function usage patterns
- Real-world query scenarios
Give a ⭐
If you like or are using this project to learn or start your solution, please give it a star. Thanks!
Also, if you find this library useful and you're feeling really generous, please consider buying me a coffee ☕.
Support
- Documentation: Full API documentation included in NuGet package
- Samples: Comprehensive samples in the repository
- Compliance Docs:
- Issues: Report bugs or request features on GitHub Issues
- Discussions: Ask questions on GitHub Discussions
History
V1.1.0 - 15 January, 2026
Enhanced Testing and Utilities
Test Coverage Expansion:
- Added more comprehensive new tests for RFC 9535 compliance validation
- Total test count increased to 536 tests
JsonPathHelper Utility:
- Added
HasFeatures()method for lightweight RFC 9535 feature detection (not syntax validation) - Added
AnalyzeComplexity()method to categorize queries as Simple, Moderate, or Complex - Zero-allocation for high-performance scenarios
- Early return optimizations for common scenarios
- Added
V1.0.1 - 11 January, 2026
RFC 9535 Compliance Fix
Parser Enhancement:
- Fixed RFC 9535 Section 2.3.5.1 compliance
- LogicalType functions (
match(),search()) can now be used as standalone test expressions in filter selectors - Added
LogicalTestExpressionnode type for proper AST representation - Updated
ParseComparisonOrExistence()to recognize LogicalType functions without requiring comparison operators - Updated
FilterEvaluatorto handleLogicalTestExpressionnodes correctly
Examples:
$[?match(@.email, '.*@example\.com$')]- Filter by regex match (now works correctly)$[?search(@.name, 'Admin')]- Filter by substring search (now works correctly)$[?!match(@.code, '^TEMP-.*')]- Logical NOT with match function$[?@.price < 100 && search(@.name, 'Chair')]- Combined with other expressions
V1.0.0 - 11 January, 2026
Initial Release - 100% RFC 9535 Certified
Core Features:
- Complete RFC 9535 JSONPath implementation
- 324 passing unit tests (0 failures)
- 100% compliance certification
Selector Support:
- Name selector (dot and bracket notation)
- Wildcard selector (objects and arrays)
- Index selector (positive and negative)
- Array slice selector (start:end:step)
- Filter selector (complex expressions)
Segment Types:
- Child segment (direct navigation)
- Descendant segment (recursive descent)
Filter Expressions:
- Comparison operators (==, !=, <, ⇐, >, >=)
- Logical operators (&&, ||, !)
- Existence tests
- Nested queries
- RFC Table 11 comparison semantics
Built-in Functions:
length()- String/array/object lengthcount()- Nodelist element countmatch()- Full regex match (I-Regexp)search()- Substring regex searchvalue()- Singular nodelist conversion
Type System:
- ValueType (JSON values)
- NodesType (nodelists)
- LogicalType (boolean results)
- Automatic type conversions per RFC 2.4.2
Performance Optimizations:
- Zero-allocation design with ArrayPool
- Span-based string operations
- Source-generated regex
- Lazy evaluation
- Efficient buffer management
Unicode Support:
- Complete Unicode handling
- Surrogate pair detection
- Escape sequence processing
- Unicode scalar value counting
Quality Assurance:
- Zero compiler warnings
- 100% XML documentation
- Comprehensive test coverage
- Production-ready error handling
- Code quality enforcement
Documentation:
- Comprehensive README
- Full API documentation
- RFC compliance reports
- Sample project with demonstrations
- RFC section cross-references
License: MIT License - see LICENSE file for details
Copyright © 2026 Graeme Grant. All rights reserved.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Blazing.Json.JSONPath:
| Package | Downloads |
|---|---|
|
Blazing.Json.Queryable
High-performance LINQ provider for JSON data that processes JSON directly without full deserialization. Supports standard string, UTF-8, streaming, and RFC 9535 compliant JSONPath operations. Dramatically improves performance and memory efficiency for medium to large JSON files through early termination and constant memory usage. Includes native IAsyncEnumerable support and .NET 10 async LINQ integration. |
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.1.0: Added JsonPathHelper utility with HasFeatures() and AnalyzeComplexity() methods for lightweight feature detection (not syntax validation). Includes zero-allocation ReadOnlySpan overloads. Extended test coverage - Total: 536 tests, all passing.