How do you deserialize JSON to a map/dictionary of records in F#? How do you deserialize JSON to a map/dictionary of records in F#? json json

How do you deserialize JSON to a map/dictionary of records in F#?


If you don't want to (or cannot) use FSharp.Data for any reason you could also try Thoth.Json which is available for both Fable as well as normal .NET. In Thoth you can either use Autoencoders/Autodecoder which will try to handle the conversion for you if your F# types closely resemble the used JSON or you write your own encoding/decoding functions.

A typed example (as a console app) that should fit your usecase (if I understood it correctly) could look like this.

let testString = """{  "Alice": {    "Age": 30,    "Address": {      "City": "New York",      "State": "NY"    }  },  "Bob": {    "Age": 6,    "Address": {      "City": "Chicago",      "State": "IL"    }  }}"""open Thoth.Json.Nettype Address =    { City : string      State : string }type Person =    { Age : int      Address: Address}let decodeAddress : Decoder<Address> =    Decode.object        (fun get ->            { City = get.Required.Field "City" Decode.string              State = get.Required.Field "State" Decode.string })let decodePerson : Decoder<Person> =    Decode.object        (fun get ->            { Age = get.Required.Field "Age" Decode.int              Address = get.Required.Field "Address" decodeAddress})let decodeMap jsonString =    Decode.fromString (Decode.keyValuePairs decodePerson) jsonString    |> Result.map (fun namePersonList ->        namePersonList        |> Map.ofList)[<EntryPoint>]let main argv =    match decodeMap testString with    | Ok res -> printfn "%A" res    | Error e -> printfn "%s" e    0


You still can use FSharp.Data's JsonValue instead of the provider:

JsonValue.Parse(json).Properties()|> Seq.iter (printfn "%A")

output:

("Alice", {  "Age": 30,  "Address": {    "City": "New York",    "State": "NY"  }})("Bob", {  "Age": 6,  "Address": {    "City": "Chicago",    "State": "IL"  }})


As pointed out in the comments, the problem is that your JSON structure is using a record to represent a list of people (with names as the key). If you can change it as suggested in the comment, then that's probably the best approach.

Alternatively, you can still read this with F# Data by using the type provider to define a type for the person:

type Person = JsonProvider<"""{    "Age": 30,    "Address": { "City": "New York", "State": "NY" }  }""">

Now, assuming input is your input string with multiple people, you can read it using the JsonValue parser, iterate over all the top-level record fields manually, but then parse individual people in your JSON using your new Person type:

[ for name, person in JsonValue.Parse(input).Properties() ->    name, Person.Root(person) ]

This gives you a list of tuples containing a name and a typed object for each person (and you get the usual benefits of type providers, i.e. you can access address and age using .)