FSharp.Data.JsonPath
1.1.3
dotnet add package FSharp.Data.JsonPath --version 1.1.3
NuGet\Install-Package FSharp.Data.JsonPath -Version 1.1.3
<PackageReference Include="FSharp.Data.JsonPath" Version="1.1.3" />
<PackageVersion Include="FSharp.Data.JsonPath" Version="1.1.3" />
<PackageReference Include="FSharp.Data.JsonPath" />
paket add FSharp.Data.JsonPath --version 1.1.3
#r "nuget: FSharp.Data.JsonPath, 1.1.3"
#:package FSharp.Data.JsonPath@1.1.3
#addin nuget:?package=FSharp.Data.JsonPath&version=1.1.3
#tool nuget:?package=FSharp.Data.JsonPath&version=1.1.3
FSharp.Data.JsonPath
JsonPath queries for FSharp.Data’s JsonValue. Find the parts of a JSON document you care about—without converting to JObject or changing your data model.
- Targets: developers using FSharp.Data JsonValue
- Use cases: robust querying, filtering, and slicing of JSON in functional pipelines
- Zero conversion: operate directly on JsonValue
- Focus: correctness, performance, and real-world practicality
Install
- Using the Package Manager Console:
PM> Install-Package FSharp.Data.JsonPath
- Using paket:
> dotnet paket add FSharp.Data.JsonPath --project MyProject
Quick start
// F#
open FSharp.Data
open FSharp.Data.JsonPath
let json =
JsonValue.Parse """
{
"store": {
"book": [
{ "category": "ref", "author": "Nigel", "price": 8.95 },
{ "category": "fic", "author": "Evelyn", "price": 12.99, "isbn": "X" }
]
}
}"""
// All authors
let authors = json |> JsonPath.findList "$.store.book[*].author"
// First match (throws if none)
let firstCheap = json |> JsonPath.find "$..book[?(@.price<10)]"
// Safe try
let maybeIsbn = json |> JsonPath.tryFind "$..book[?(@.isbn)].isbn"
API
JsonPath.find query json -> JsonValue- Returns the first match. Throws if no match.
JsonPath.findList query json -> JsonValue list- Returns all matches in document order.
JsonPath.findSeq query json -> seq<JsonValue>- Lazy sequence of matches.
JsonPath.tryFind query json -> JsonValue option- First match, or None.
Queries are strings in standard JsonPath syntax, beginning with $.
Supported JsonPath features
- Root:
$ - Exact child:
$.a.b - Recursive descent:
$..b(any depth) - Wildcards:
- Properties:
$.* - Arrays:
$.[*],$.a[*][*],$..*
- Properties:
- Array selectors:
- Literal indices:
$.[0,2,-1](supports negative indices) - Slices:
$.[start:finish:step]with negatives and omissions, e.g.$.[1:],$.[-2:],$.[::2],$.[0:-1] - Wildcard:
[*]
- Literal indices:
- Filters and expressions:
- Presence:
$..book[?(@.isbn)] - Numeric comparison:
$..book[?(@.price<10)] - Index expression passthrough:
$..book[(@.length-1)]
- Presence:
Notes:
- Recursive descent works for both properties and arrays.
- Wildcards match any property name or any array index.
- Slices follow Python-like semantics; finish is exclusive, negative indices count from the end.
Practical recipes
Get a value by path:
// F#
json |> JsonPath.find "$.store.book[0].category"
Gather all nested occurrences of a key:
// F#
json |> JsonPath.findList "$..price"
Select all items from any array named "items":
// F#
json |> JsonPath.findList "$..items[*]"
Safely try for an optional field:
// F#
json |> JsonPath.tryFind "$.profile.address.postcode"
Last element of any "book" array:
// F#
json |> JsonPath.findList "$..book[-1:]"
Top sellers under $10 across a catalog:
// F#
json
|> JsonPath.findList "$..book[?(@.price<10)]"
|> List.map (fun b -> b)
Extract all leaf values:
// F#
json |> JsonPath.findList "$..*"
Work with root arrays:
// F#
let arr = JsonValue.Parse """[ { "a": 1 }, { "a": 2 } ]"""
let values = arr |> JsonPath.findList "$.[*].a"
Real-world scenarios
- Observability logs:
$..attributes.userId - E-commerce catalog:
$..products[*].price - Feature flags:
$..flags[?(@.enabled=true)].name - ETL slice checks:
$.records[0:100] - Event stream payloads with variable nesting:
$..payload.*.idor$..id - Document migrations: find missing fields
$..users[*][?(!@.email)]via presence check patterns
Behavior and edge cases
- Identity:
$.returns the current JsonValue (root identity). - Missing paths: find throws; prefer tryFind for optional data.
- Out-of-range literals: ignored (non-matching indices are skipped).
- Negative indices: count from end;
-1is last. - Slices:
- finish is exclusive
- step must be positive; step 0 yields no matches
- Ordering: matches are returned in document traversal order (preorder).
- Performance: traversal is streaming-friendly; prefer findSeq for large documents.
Testing-style examples
- Recursive property:
$..a.bfinds anybnested beneath anya, at any depth.
- Wildcard property at root:
$.*returns all top-level property values.
- Any + wildcard combination:
$..c.*.bfindsbunder any child of anyc.
Error handling
- find: throws if no match
- tryFind: returns None
- findList/findSeq: return empty if no matches
Choose tryFind or findList for resilient pipelines.
Interop tips
- Keep your data in JsonValue; avoid converting to JObject.
Compose with F# pipelines:
// F#
let cheapAuthors =
json
|> JsonPath.findList "$..book[?(@.price<10)].author"
Compatibility
- Designed for FSharp.Data’s JsonValue
- JsonPath syntax aligned with broadly used conventions: recursive descent, wildcards, filters, array literals and slices
Contributing
- Issues and PRs welcome for additional operators, performance improvements, and docs/examples.
- Add unit tests mirroring expected JsonPath semantics for new behaviors.
License
- Open source. See package/license details on NuGet.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 is compatible. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 3.1
- FSharp.Core (>= 9.0.303)
- FSharp.Data (>= 6.6.0)
-
.NETFramework 4.8.1
- FSharp.Core (>= 9.0.303)
- FSharp.Data (>= 6.6.0)
-
.NETStandard 2.0
- FSharp.Core (>= 9.0.303)
- FSharp.Data (>= 6.6.0)
-
net8.0
- FSharp.Core (>= 9.0.303)
- FSharp.Data (>= 6.6.0)
-
net9.0
- FSharp.Core (>= 9.0.303)
- FSharp.Data (>= 6.6.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.