F# JSON Type Provider,不序列化空值

F# JSON Type Provider, do not serialize null values

背景

我正在使用 FSharp.Data JSON 类型提供程序和一个示例,该示例包含一组可能具有不同属性的对象。这是一个说明性的例子:

[<Literal>]
let sample = """
    { "input": [
        { "name": "Mickey" },
        { "year": 1928 }
       ] 
    }
"""
type InputTypes = JsonProvider< sample >

JSON 类型提供程序创建了一个输入类型,它具有可选名称和可选年份 属性。效果不错。

问题

当我尝试将此实例传递给 Web 服务时,我会执行如下操作:

InputTypes.Root(
    [|
        InputTypes.Input(Some("Mouse"), None)
        InputTypes.Input(None, Some(2028))
    |]
)

Web 服务正在接收以下内容并因空值而阻塞。

{
  "input": [
    {
      "name": "Mouse",
      "year": null
    },
    {
      "name": null,
      "year": 2028
    }
  ]
}

我试过的

我发现这行得通:

InputTypes.Root(
    [|
        InputTypes.Input(JsonValue.Parse("""{ "name": "Mouse" }"""))
        InputTypes.Input(JsonValue.Parse("""{ "year": 2028 }"""))
    |]
)

它发送这个:

{
  "input": [
    {
      "name": "Mouse"
    },
    {
      "year": 2028
    }
  ]
}

然而,在我的真实项目中,结构更大,需要更多条件 JSON 字符串构建。这有点违背了目的。

问题

作为比较点,Newtonsoft.JSON 库有一个 NullValueHandling 属性。

我不认为有一种简单的方法可以在 F# Data 中获取 JSON 格式来删除 null 字段 - 我认为类型没有清楚地区分什么是 null 以及缺少什么。

您可以通过编写一个辅助函数来删除所有 null 字段来解决这个问题:

let rec dropNullFields = function
  | JsonValue.Record flds ->
      flds 
      |> Array.choose (fun (k, v) -> 
        if v = JsonValue.Null then None else
        Some(k, dropNullFields v) )
      |> JsonValue.Record
  | JsonValue.Array arr -> 
      arr |> Array.map dropNullFields |> JsonValue.Array
  | json -> json

现在您可以执行以下操作并获得所需的结果:

let json = 
  InputTypes.Root(
      [|
          InputTypes.Input(Some("Mouse"), None)
          InputTypes.Input(None, Some(2028))
      |]
  )

json.JsonValue |> dropNullFields |> sprintf "%O"