我喜欢F#类型的提供商,这就是我尽可能尝试使用FSharp.Data库的原因,但我发现了一个似乎无法覆盖的用例。
考虑这个简单的JSON文件:
{
"Foo": {
"Baz": 0,
"Bazz": "x"
},
"Bar": {
"Baz": 10,
"Bazz": "y"
}
}
我想将上面的元素解析为数组,而不是以硬编码的方式访问Foo&Bar和s的元素。也就是说,收到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...
答案 0 :(得分:3)
是否可以以某种方式使用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";}]