如何用FSharp.Data的JsonProvider枚举式访问JSON文件元素?
解决FSharp.Data JsonProvider解析对象值为序列的问题
嘿,太懂你这种不想硬编码键名、想灵活把JSON对象里的值转成统一记录序列的需求了!我之前也在这个点上卡过——SampleIsList=true确实帮不上忙,因为它是给顶层就是数组的JSON设计的,而你的JSON是一个键值对对象,键是Foo/Bar这类自定义名称,值才是你要的SomeRecord结构。
下面给你两种实用的解决思路:
方法一:双Provider配合提取属性值
先定义单个记录的样本,再定义顶层JSON的Provider,最后提取所有属性值转成目标序列:
open FSharp.Data open System.IO // 先定义单个SomeRecord的样本,匹配你的Baz/Bazz结构 type SomeRecord = JsonProvider<""" { "Baz": 123, "Bazz": "test" } """> // 定义顶层JSON的Provider(用你的实际JSON样本) type RootJson = JsonProvider<""" { "Foo": { "Baz": 1, "Bazz": "a" }, "Bar": { "Baz": 2, "Bazz": "b" } } """> // 加载JSON并提取所有值转成SomeRecord序列 let loadRecords filePath = let root = RootJson.Load(filePath) // 遍历顶层对象的所有属性,只取值部分转成SomeRecord root.Properties |> Seq.map (fun (_, value) -> SomeRecord.Parse(value.JsonValue.ToString()))
方法二:直接用JsonValue动态处理(更灵活)
如果不想定义顶层的RootJson Provider,可以直接用JsonValue解析整个文件,然后手动遍历对象属性:
open FSharp.Data open System.IO type SomeRecord = JsonProvider<""" { "Baz": 123, "Bazz": "test" } """> let loadRecords filePath = let jsonContent = File.ReadAllText(filePath) match JsonValue.Parse(jsonContent) with // 确认顶层是JSON对象(键值对集合) | JsonValue.Record properties -> properties |> Seq.map (fun (_, value) -> SomeRecord.Parse(value)) // 处理非对象的异常情况 | _ -> failwith "JSON顶层不是预期的对象结构"
关键说明
- 为什么
SampleIsList=true没用?这个参数是告诉Provider“我的样本是一个数组,生成的类型直接对应这个数组”,但你的JSON顶层是对象,所以完全不匹配。 - 两种方法的核心都是提取JSON对象的所有属性值,而不是硬编码访问
Foo/Bar。 - 如果你的
SomeRecord有可选字段,只需要在样本里把可选字段设为null或者省略,Provider会自动生成可选类型(比如int option)。
内容的提问来源于stack exchange,提问作者knocte
相关产品推荐
相关产品推荐

