[英]F# Data JSON type provider: How to handle a JSON property that can be an array or a property?
I am using the JSON type provider from the F# Data library to access JSON documents from an API. 我正在使用F#Data库中的JSON类型提供程序从API访问JSON文档。 The documents contain a property (let's call it 'car') that sometimes is an array of objects and sometimes a single object.
文档包含一个属性(让我们称之为'car'),有时候是一个对象数组,有时候是一个对象。 It is either this:
这是:
'car': [
{ ... },
{ ... }
]
or this: 或这个:
'car': { ... }
The object in { ... }
has the same structure in both cases. { ... }
的对象在两种情况下都具有相同的结构。
The JSON type provider indicates that the property is of type: JSON类型提供程序指示属性的类型为:
JsonProvider<"../data/sample.json">.ArrayOrCar
where sample.json
is my sample document. 其中
sample.json
是我的示例文档。
My question is then: How can I figure out whether the property is an array (so that I can process it as an array) or a single object (so that I can process it as an object)? 我的问题是:我怎样才能弄清楚属性是一个数组(以便我可以将它作为数组处理)还是单个对象(以便我可以将它作为一个对象处理)?
UPDATE: A simplified sample JSON would look like this: 更新:简化的示例JSON将如下所示:
{
"set": [
{
"car": [
{
"brand": "BMW"
},
{
"brand": "Audi"
}
]
},
{
"car": {
"brand": "Toyota"
}
}
]
}
And with the following code it will be pointed out that the type of doc.Set.[0].Car
is JsonProvider<...>.ArrayOrCar
: 并且使用以下代码将指出
doc.Set.[0].Car
的类型是JsonProvider<...>.ArrayOrCar
:
type example = JsonProvider<"sample.json">
let doc = example.GetSample()
doc.Set.[0].Car
If the type of the JSON value in the array is the same as the type of the directly nested JSON value, then JSON type provider will actually unify the two types and so you can process them using the same function. 如果数组中JSON值的类型与直接嵌套的JSON值的类型相同,那么JSON类型提供程序实际上将统一这两种类型,因此您可以使用相同的函数处理它们。
Using your minimal JSON document as an example, the following works: 以最小的JSON文档为例,以下工作原理:
type J = JsonProvider<"sample.json">
// The type `J.Car` is the type of the car elements in the array
// but also of the car record directly nested in the "car" field
let printBrand (car:J.Car) =
printfn "%s" car.Brand
// Now you can use pattern matching to check if the current element
// has an array of cars or just a single record - then you can call
// `printBrand` either on all cars or on just a single car
let doc = J.GetSample()
for set in doc.Set do
match set.Car.Record, set.Car.Array with
| Some c, _ -> printBrand c
| _, Some a -> for c in a do printBrand c
| _ -> failwith "Wrong input"
After playing around with the library, I found that you can do something like this: 在玩完图书馆之后,我发现你可以这样做:
let car = doc.Set.[0].Car
let processObject (car:example.ArrayOrCar) =
match car.Array with
| Some a -> printfn "do stuff with an array %A" a
| None -> match car.Record with
| Some c -> printfn "do stuff with an object %A" c
| None -> printfn "fail here?"
To process the whole Set[]
you can do something where you apply processObject to each element using something like Array.map
. 要处理整个
Set[]
您可以使用像Array.map
这样的Array.map
将processObject应用于每个元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.