Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Data——如何处理空JSON值?_Json_F#_F# Data - Fatal编程技术网

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可能不存在 尝试通

我正在尝试将FSharp.Data示例转换为我正在处理的问题的解决方案,但我只是没有走多远

问题 给定一个返回json的端点,类似于:

{
  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 [] = [||]