Query JsonValue documents from F# using ad-hoc JsonPath queries.
$ dotnet add package FSharp.Data.JsonPathJsonPath 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.
PM> Install-Package FSharp.Data.JsonPath
> dotnet paket add FSharp.Data.JsonPath --project MyProject
// 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"
JsonPath.find query json -> JsonValue
JsonPath.findList query json -> JsonValue list
JsonPath.findSeq query json -> seq<JsonValue>
JsonPath.tryFind query json -> JsonValue option
Queries are strings in standard JsonPath syntax, beginning with $.
$$.a.b$..b (any depth)$.*$.[*], $.a[*][*], $..*$.[0,2,-1] (supports negative indices)$.[start:finish:step] with negatives and omissions, e.g. $.[1:], $.[-2:], $.[::2], $.[0:-1][*]$..book[?(@.isbn)]$..book[?(@.price<10)]$..book[(@.length-1)]Notes:
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"$..attributes.userId$..products[*].price$..flags[?(@.enabled=true)].name$.records[0:100]$..payload.*.id or $..id$..users[*][?(!@.email)] via presence check patterns$. returns the current JsonValue (root identity).-1 is last.$..a.b finds any b nested beneath any a, at any depth.$.* returns all top-level property values.$..c.*.b finds b under any child of any c.Choose tryFind or findList for resilient pipelines.
Compose with F# pipelines:
// F#
let cheapAuthors =
json
|> JsonPath.findList "$..book[?(@.price<10)].author"