我喜欢F#类型提供程序,这就是我尽可能尝试使用FSharp.Data库的原因,但我发现了一个似乎没有覆盖的用例。
考虑这个简单的JSON文件:
{
"Foo": {
"Baz": 0,
"Bazz": "x"
},
"Bar": {
"Baz": 10,
"Bazz": "y"
}
}
我想将上面的元素解析为数组,而不是以硬编码方式访问Foo和Bar的元素。也就是说,接收一个IEnumerable<SomeRecord>
,其中SomeRecord有2名成员Baz
和Bazz
。是否有可能以某种方式使用JsonProvider API来实现这一目标?
我尝试了SampleIsList=true
选项,但似乎不起作用:
type MyJsonProvider = JsonProvider<"./elements.json",
EmbeddedResource="MyAssemblyName, elements.json",
SampleIsList=true>
let SomeReadingMethod() =
let assembly = Assembly.GetExecutingAssembly()
let embeddedServerListFileName = "elements.json"
use stream = assembly.GetManifestResourceStream(embeddedServerListFileName)
use reader = new StreamReader(stream)
let list = reader.ReadToEnd()
let elements = MyJsonProvider.Parse(list)
for element in elements do
...
我得到编译器错误:The type JsonProvider<...>.Root is not a type whose values can be enumerated with this syntax...
是否有可能以某种方式使用JsonProvider API来实现这一目标?
不,您提供的示例输入是从键/字段到值的映射 - 而不是值的枚举。 SampleIsList
适用于您的样本本身是一个包含您所推断类型的多个实例的集合。如果你想使用JsonProvider
,我认为你需要在设计和运行时改变你的JSON模式。
或者,我考虑编写一个简单的解析器,使用JSON parsing features in FSharp.Data或其他OSS F#JSON解析库之一。这是一个基本的例子:
open FSharp.Data
open FSharp.Data.JsonExtensions
let info =
JsonValue.Parse("""
{
"Foo": {
"Baz": 0,
"Bazz": "x"
},
"Bar": {
"Baz": 10,
"Bazz": "y"
}
} """)
type MyRecord = {
Baz : int;
Bazz : string
}
let parse props =
seq {
for (_k,v) in props ->
{Baz = v?Baz.AsInteger(); Bazz = v?Bazz.AsString()}
}
> parse info.Properties;;
val it : seq<MyRecord> =
seq [{Baz = 0; Bazz = "x";};
{Baz = 10; Bazz = "y";}]