You can use the JSON Type Provider . It understands the heterogeneous types of node. Here's the JSON from OP (fixed, so this is a valid JSON) used as a pattern to determine the type:
open FSharp.Data type MyJson = JsonProvider<"""{ "arr": [ { "node": "xyz", "type": "string" }, { "node": { "moredata": "values", "otherdata": "values2" }, "type": "node" } ] }""">
Now you can create a value of this type by calling MyJson.Parse , but if you want to look only at the JSON used as an example from which the type is derived, you can also use GetSample :
let json = MyJson.GetSample()
Now you can start exploring the data. Here's the FSI session:
> json.Arr;; val it : JsonProvider<...>.Arr [] = [|{ "node": "xyz", "type": "string" }; { "node": { "moredata": "values", "otherdata": "values2" }, "type": "node" }|] > json.Arr |> Array.map (fun x -> x.Node);; val it : JsonProvider<...>.StringOrNode [] = [|"xyz"; { "moredata": "values", "otherdata": "values2" }|]
As you can see, each Node represents a StringOrNode value, which can be accessed as follows:
> json.Arr |> Array.map (fun x -> x.Node.Record) |> Array.choose id;; val it : JsonProvider<...>.Node [] = [|{ "moredata": "values", "otherdata": "values2" }|]
Since x.Node.Record is an option , you can only select Some with Array.choose .
You can get the lines in the same way:
> json.Arr |> Array.map (fun x -> x.Node.String) |> Array.choose id;; val it : string [] = [|"xyz"|]