【问题标题】:Deserialise JSON to Dictionary<string, string >将 JSON 反序列化为 Dictionary<string, string >
【发布时间】:2021-03-30 10:10:00
【问题描述】:

当我从极其松散的 PHP 迁移到 F# 时,我确信我会提出一连串愚蠢的问题。

这个应该是直截了当的。 我有一个json文件

{
“some_ key” : “some_value”
}

这将有一个简单的键、值(字符串、字符串)格式的几百个项目的列表。

在 F# 中,我想将该字符串解码为 dictionary&lt;string, string&gt; 。 看起来很明显,但我看到的所有建议似乎都非常冗长,所以假设我遗漏了一些简单的东西。

我有 Thoth 和 FSharp.Data 供我使用,但对其他任何东西都是免费的。

【问题讨论】:

  • 当您拥有 FSharp.Data 的 JSON 类型提供程序和解析器时,为什么要使用松散的字典?
  • 不熟悉。我非常愿意使用不同的类型,但在这种情况下,json 是一个字面字典 - 单词和定义的列表 - 所以在我看来更具语义。
  • 我需要能够动态访问属性的另一个原因。例如,通过我似乎无法在 JSON 类型提供程序上执行的函数参数调用它们。
  • 此外,它似乎无法动态加载示例文件。我无法控制 JSON,它是用户提供的文件,它可能不是示例文件的确切结构(它应该是,但用户错误等。我需要能够处理丢失或额外的键)。如果我可以将示例文件加载为可以解决该问题的提供文件,但似乎无法做到。
  • 您使用的是什么版本的 .Net?不同版本的 .Net 内置了不同的 JSON 序列化程序。或者您可以在所有版本中使用(免费)nugetjson.net

标签: json f# f#-data


【解决方案1】:

开箱即用的 .NET 解决方案可能如下所示:

open System.Text.Json
open System.Collections.Generic

let json = """{
    "key": "value",
    "foo": "bar"
}"""

let dic: IReadOnlyDictionary<string, string> =
    JsonSerializer.Deserialize(json);


// Usage example
dic.["foo"] = "bar" // true

let someKey = "dimdi"
match dic.TryGetValue someKey with
| false, _ -> printfn "Missing key %s" someKey
| _, v -> printfn "Found %s" v

【讨论】:

    【解决方案2】:

    纯 .NET Core 示例,如果您只追求简单的东西:

    let json = """{
      "some_ key" : "some_value"
    }"""
    
    let data = 
        System.Text.Json.JsonDocument.Parse(json)
            .RootElement
            .EnumerateObject()
        |> Seq.map (fun o -> o.Name, o.Value.GetString())
        |> dict
    

    【讨论】:

      【解决方案3】:

      使用透特的神奇方法是 Decode.keyValuePairs。

      open Thoth.Json.Net
      
      let json = """{
      “some_ key” : “some_value”
      }"""
      
      let decoder : Decoder<(string * string) list> = Decode.keyValuePairs Decode.string 
      Decode.fromString decoder json |> Result.map dict 
      
      // Ok System.Collections.Generic.IDictionary<string,string>
      

      【讨论】:

      • 返回 PHP 或 Javascript 的令人信服的论据?我如何访问这些值? let decoder : Decoder&lt;(string * string) list&gt; = Decode.keyValuePairs Decode.string let arr = Decode.fromString decoder json |&gt; Result.map dict arr.["some_key"] 给我一个“无法对表达式应用索引”
      • 错误处理是比这更大的问题。您可以打开类型并引发错误。阅读此fsharpforfunandprofit.com/posts/recipe-part2
      • 展开:让展开=函数|好的 v -> v |错误 e -> failwithf "%O" e
      • 是 arr.["some_key"] 在 IDE 中失败,因此无法构建。实际的解码代码似乎工作正常(虽然推断类型是 Result&lt;IDictionary&lt;string,string&gt;,string&gt; 我还在学习 ASP.NET 和 F#,所以我的调试技能不好,并不期望 json 解码会提供任何问题,但似乎“系统”我正在“移植”只是真的依赖于动态类型,所以 F# 可能是这个工作的错误工具。我会睡在它上面并再次更详细地问这个问题,因为我有越来越多的问题我越深入深入研究 FSharp.Data 和 Thoth。
      • 这肯定是一种不同的思维方式
      【解决方案4】:

      如果您使用 FSharp.Data 并且 Json 提供程序不是一个选项,您可以使用 Fleece 代替 Thoth,它与 FSharp.Data 完美配合

      #r "nuget: Fleece.FSharpData"
      
      open System.Collections.Generic
      open Fleece.FSharpData
      
      let (x: Result<Dictionary<string,string>, _>) = parseJson """{"some_ key" : "some_value"}"""
      
      (* 
      val x : Result<Dictionary<string,string>,Fleece.FSharpData.DecodeError> =
        Ok dict [("some_ key", "some_value")]
      *)
      

      parseJson 函数可以处理文本,但如果你的 json 已经用 FSharp.Data 解析,你可以改用ofJson

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-15
        • 2020-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-10
        相关资源
        最近更新 更多