Data——如何处理空JSON值?
我正在尝试将FSharp.Data示例转换为我正在处理的问题的解决方案,但我只是没有走多远 问题 给定一个返回json的端点,类似于:Data——如何处理空JSON值?,json,f#,f#-data,Json,F#,F# Data,我正在尝试将FSharp.Data示例转换为我正在处理的问题的解决方案,但我只是没有走多远 问题 给定一个返回json的端点,类似于: { Products:[{ Id:43, Name:"hi" }, { Id:45, Name:"other prod" } ] } 如何加载数据,然后仅从真实的现有数据中获取Ids 我不明白如何“模式匹配”以下可能性: 它什么也回不来 该root.Products可能不存在/为空 Id可能不存在 尝试通
{
Products:[{
Id:43,
Name:"hi"
},
{
Id:45,
Name:"other prod"
}
]
}
如何加载数据,然后仅从真实的现有数据中获取Id
s
我不明白如何“模式匹配”以下可能性:
- 它什么也回不来
- 该
可能不存在/为空root.Products
可能不存在Id
名称空间打印
开放系统
打开FSharp.Data
打开FSharp.Data.JsonExtensions
模块PrintioApi=
输入ApiProducts=JsonProvider
让getProductIds url=
异步的{
让!json=ApiProducts.AsyncLoad url
让ids=将json与
|空->[| |]
| _ ->
将json.Products与
|空->[| |]
|->Array.map(fun(x:apicroducts.Product)->x.Id)json.Products
返回ID
}
如果您对源数据有一定程度的信心,您可能不需要模式匹配来检查它是否为空数组。像这样的东西可能很管用:-
let getProductIds url =
async {
let! json = ApiProducts.AsyncLoad url
return json.Products |> Seq.map(fun p -> p.Id) |> Seq.cache
}
注意,在异步{}块中不应使用Async.RunSynchronously-您可以使用let!将异步等待结果的绑定。编辑:当我写这个答案时,我没有完全理解JSON类型提供程序的功能。事实证明,您可以使用示例JSON文档列表来填充它,这使您能够处理各种可能存在或不存在数据的场景。最近我经常使用它,所以我不再相信我最初写的东西。我将把原始答案留在这里,以防任何人都能从中得到任何价值 看看我今天如何做的示范
虽然类型提供程序很好,但我认为,试图将JSON这样没有模式、也没有类型安全性的东西视为强类型数据在概念上是错误的。我没有使用类型提供程序,而是使用和来编写如下查询:
let response = client.GetAsync("").Result
let json = response.Content.ReadAsJsonAsync().Result
let links = json?links :> obj seq
let address =
links
|> Seq.filter (fun l -> l?rel <> null && l?href <> null)
|> Seq.filter (fun l -> l?rel.ToString() = rel)
|> Seq.map (fun l -> Uri(l?href.ToString()))
|> Seq.exactlyOne
type HttpContent with
member this.ReadAsJsonAsync() =
let readJson (t : Task<string>) =
JsonConvert.DeserializeObject t.Result
this.ReadAsStringAsync().ContinueWith(fun t -> readJson t)
给类型提供程序提供足够的示例来推断这些情况。例如:
[<Literal>]
let sample = """
{
Products:[{
Id:null,
Name:"hi"
},
{
Id:45,
Name:"other prod"
}
]
}
"""
type MyJsonType = JsonProvider<sample>
[]
让样本为“”
{
产品:[{
Id:null,
姓名:“你好”
},
{
身份证号码:45,
名称:“其他产品”
}
]
}
"""
类型MyJsonType=JsonProvider
但是请注意,如果json不够规则,它永远不会是100%安全的如果您怀疑您的数据源可能包含一些缺少的值,您可以在JsonProvider中设置
SampleIsList=true
,并为其提供一个示例列表,而不是一个示例:
open FSharp.Data
type ApiProducts = JsonProvider<"""
[
{
"Products": [{
"Id": 43,
"Name": "hi"
}, {
"Name": "other prod"
}]
},
{}
]
""", SampleIsList = true>
请注意,它使用了数组。选择而不是数组。映射,因为数组。选择只会自动选择那些Id
值,这些值是一些
现在,您可以使用各种值进行测试,以查看它是否有效:
> getProductIds """{ "Products": [{ "Id": 43, "Name": "hi" }, { "Id": 45, "Name": "other prod" }] }""";;
> val it : int [] = [|43; 45|]
> getProductIds """{ "Products": [{ "Id": 43, "Name": "hi" }, { "Name": "other prod" }] }""";;
> val it : int [] = [|43|]
> getProductIds "{}";;
> val it : int [] = [||]
不过,它仍然会在空输入时崩溃;如果JsonProvider
有TryParse
函数或类似函数,我还没有找到它…序列缓存是用来做什么的?我在MSDN上查找了它,但有没有具体的理由将它与JsonTypeProvider一起使用?没有。简单地说,序列是惰性计算的,因此如果多次使用该序列,则会为每个序列调用map函数(C#中的Linq的.Select()也是如此)。Seq.cache保证只枚举一次。您可以使用Seq.toList或Seq.toArray.Hmmmm获得类似的效果。我不确定您不存在模式的观点。是的,这个模式可能不是由JSON强制执行的,但是仍然有很多模式。与CSV相同。与Mongo DB相同。等等。提供数据的服务可能有也可能没有底层模式,但从客户的角度来看,这是不相关的。基于示例数据自动生成.NET类型不会保护作为客户端开发人员的您不受服务模式更改的影响。当您编写分布式软件时,建议您:;基于样本数据的快照生成类型并不是特别健壮。然而,人们乐于使用JSON和推断模式,比如XML和XSD——事实上,更乐于使用IMHO。这取决于预期的用例。这些类型提供程序及其推理算法的设计考虑了探索性编程,因此它们不为您提供任何类型安全保证。但在实践中,在许多情况下,xml、json或csv实际上是足够规则的,因此可以安全地使用TPs@MarkSeemann存在一个JSON模式建议(现在IETF中的Draft4)。我认为这将使类型提供程序选项更加有趣。
let getProductIds json =
let root = ApiProducts.Parse json
root.Products |> Array.choose (fun p -> p.Id)
> getProductIds """{ "Products": [{ "Id": 43, "Name": "hi" }, { "Id": 45, "Name": "other prod" }] }""";;
> val it : int [] = [|43; 45|]
> getProductIds """{ "Products": [{ "Id": 43, "Name": "hi" }, { "Name": "other prod" }] }""";;
> val it : int [] = [|43|]
> getProductIds "{}";;
> val it : int [] = [||]