字典到 JSON 字符串

Dictionary to JSON string

考虑到字典将具有嵌套键的情况,如 JSON

let toConvert = dict["Id", "001"; "title", "one"; "payload.subname", "oneone"; "payload.type", "awesome" ]

如何使用嵌套对象生成 JSON string,例如:

{
  "Id": "001",
  "title": "one",
  "payload": {
    "subname": "oneone",
    "type": "awesome"
  }
}

有什么想法吗?

第一种方法


let printArgumentValue argument value = 
      [
          "\"";
          argument;
          "\": \"";
          value;
          "\""
      ] |> String.concat ""

let printDictionary (v:string*seq<KeyValuePair<string,string>>) =
    match v |> snd |> Seq.length with
    | 0 -> ""
    | 1 -> [
            printArgumentValue (v |> fst) (v |> snd |> Seq.head).Value;
            ","
           ] |> String.concat ""
    | _ -> [
              "\"";
              v |> fst;
              "\": { ";
              v |> snd |> Seq.map(fun kv -> printArgumentValue (kv.Key.Replace(([ v |> fst; "."] |> String.concat ""), "")) kv.Value) |> String.concat ",";
              "}"
           ] |> String.concat ""

toConvert
|> Seq.groupBy (fun (KeyValue(k,v)) -> k.Split('.').[0])
|> Seq.map(fun v -> printDictionary v)
|> String.concat ""

现在只是缺少递归。

使用 Newtonsoft.Json NuGet 包,这里的方法是使用递归函数将普通值构建成 JObject

open Newtonsoft.Json.Linq

let normalise rawDict = 
    rawDict
    |> Seq.map (fun (KeyValue (k, v)) -> ((k:string).Split('.') |> Array.toList), v)
    |> Seq.toList

let rec buildJsonObject values : JObject =
    values
    |> List.groupBy (fun (keys, _) ->
        match keys with
        | [] | [ _ ] -> None
        | childObjectKey :: _ -> Some childObjectKey)
    |> List.collect (fun (childObjectKey, values) ->
        match childObjectKey with
        | None ->
            values
            |> List.map (function
                | [ k ], v -> JProperty(k, JValue (v:string))
                | _ -> failwith "unpossible!")
        | Some childObjectKey ->
            let childObject = 
                values
                |> List.map (fun (keys, v) -> List.tail keys, v)
                |> buildJsonObject
            [ JProperty(childObjectKey, childObject) ])
    |> JObject

然后通过 string 调用 .ToString() 会产生您预期的输出:

dict ["Id", "001"; "title", "one"; "payload.subname", "oneone"; "payload.type", "awesome" ]
|> normalise
|> buildJsonObject
|> string