字典到 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
考虑到字典将具有嵌套键的情况,如 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