将 JSON 多路树解码为 F# 多路树可辨别联合
Decode JSON Multiway Tree into an F# Multiway Tree Discriminated Union
我在 documentdb 中有以下 JSON 数据,我想将其解析为 F# 多路树判别联合
"commentTree": {
"commentModel": {
"commentId": "",
"userId": "",
"message": ""
},
"forest": []
}
F# 多路判别联合
type public CommentMultiTreeDatabaseModel =
| CommentDatabaseModelNode of CommentDatabaseModel * list<CommentMultiTreeDatabaseModel>
其中 CommentMultiTreeDatabaseModel 定义为
type public CommentDatabaseModel =
{ commentId : string
userId : string
message : string
}
我广泛引用了 Fold / Recursion over Multiway Tree in f#。我不确定从哪里开始将这样的 JSON 结构解析为 F# 多路树。任何建议将不胜感激。谢谢
考虑这一点的一种方法是查看构建 CommentMultiTreeDatabaseModel
所需的数据。它需要一个 CommentDatabaseModel
和一个 CommentMultiTreeDatabaseModel
的列表。所以我们需要编写如下两个函数:
let parseComment (input : JSON) : CommentDatabaseModel =
...
let parseTree (input : JSON) : CommentMultiTreeDatabaseModel =
...
等等,parseTree
函数正是我们现在要编写的函数!因此,我们无需编写新函数,只需使用 rec
关键字标记当前函数,并让它在需要时调用自身。
以下是如何完成的粗略示例。要看的关键是 parseTree
它通过递归调用自身来构建数据。我用一个简单的 DU 表示 JSON 输入数据。像 Chiron 这样的图书馆可以产生这样的东西。
请注意,此代码一次性解析所有 JSON。此外,它不是尾递归的,因此您必须注意树结构的深度。
[<RequireQualifiedAccess>]
type JSON =
| String of string
| Object of (string * JSON) list
| Array of JSON list
type public CommentDatabaseModel = {
commentId : string
userId : string
message : string
}
type public CommentMultiTreeDatabaseModel =
| CommentDatabaseModelNode of CommentDatabaseModel * list<CommentMultiTreeDatabaseModel>
let parseComment = function
| JSON.Object [ "commentId", JSON.String commentId; "userId", JSON.String userId; "message", JSON.String message ] ->
{
commentId = commentId
userId = userId
message = message
}
| _ -> failwith "Bad data"
let rec parseTree (input : JSON) : CommentMultiTreeDatabaseModel =
match input with
| JSON.Object [ "commentModel", commentModel; "forest", JSON.Array forest ] ->
CommentDatabaseModelNode (parseComment commentModel, List.map parseTree forest)
| _ -> failwith "Bad data"
let parse (input : JSON) : CommentMultiTreeDatabaseModel =
match input with
| JSON.Object [ "commentTree", commentTree ] ->
parseTree commentTree
| _ -> failwith "Bad data"
let comment text =
JSON.Object [
"commentId", JSON.String ""
"userId", JSON.String ""
"message", JSON.String text
]
let sampleData =
JSON.Object [
"commentTree", JSON.Object [
"commentModel", comment "one"
"forest", JSON.Array [
JSON.Object [
"commentModel", comment "two"
"forest", JSON.Array []
]
JSON.Object [
"commentModel", comment "three"
"forest", JSON.Array []
]
]
]
]
parse sampleData
(*
val it : CommentMultiTreeDatabaseModel =
CommentDatabaseModelNode
({commentId = "";
userId = "";
message = "one";},
[CommentDatabaseModelNode ({commentId = "";
userId = "";
message = "two";},[]);
CommentDatabaseModelNode ({commentId = "";
userId = "";
message = "three";},[])])
*)
我在 documentdb 中有以下 JSON 数据,我想将其解析为 F# 多路树判别联合
"commentTree": {
"commentModel": {
"commentId": "",
"userId": "",
"message": ""
},
"forest": []
}
F# 多路判别联合
type public CommentMultiTreeDatabaseModel =
| CommentDatabaseModelNode of CommentDatabaseModel * list<CommentMultiTreeDatabaseModel>
其中 CommentMultiTreeDatabaseModel 定义为
type public CommentDatabaseModel =
{ commentId : string
userId : string
message : string
}
我广泛引用了 Fold / Recursion over Multiway Tree in f#。我不确定从哪里开始将这样的 JSON 结构解析为 F# 多路树。任何建议将不胜感激。谢谢
考虑这一点的一种方法是查看构建 CommentMultiTreeDatabaseModel
所需的数据。它需要一个 CommentDatabaseModel
和一个 CommentMultiTreeDatabaseModel
的列表。所以我们需要编写如下两个函数:
let parseComment (input : JSON) : CommentDatabaseModel =
...
let parseTree (input : JSON) : CommentMultiTreeDatabaseModel =
...
等等,parseTree
函数正是我们现在要编写的函数!因此,我们无需编写新函数,只需使用 rec
关键字标记当前函数,并让它在需要时调用自身。
以下是如何完成的粗略示例。要看的关键是 parseTree
它通过递归调用自身来构建数据。我用一个简单的 DU 表示 JSON 输入数据。像 Chiron 这样的图书馆可以产生这样的东西。
请注意,此代码一次性解析所有 JSON。此外,它不是尾递归的,因此您必须注意树结构的深度。
[<RequireQualifiedAccess>]
type JSON =
| String of string
| Object of (string * JSON) list
| Array of JSON list
type public CommentDatabaseModel = {
commentId : string
userId : string
message : string
}
type public CommentMultiTreeDatabaseModel =
| CommentDatabaseModelNode of CommentDatabaseModel * list<CommentMultiTreeDatabaseModel>
let parseComment = function
| JSON.Object [ "commentId", JSON.String commentId; "userId", JSON.String userId; "message", JSON.String message ] ->
{
commentId = commentId
userId = userId
message = message
}
| _ -> failwith "Bad data"
let rec parseTree (input : JSON) : CommentMultiTreeDatabaseModel =
match input with
| JSON.Object [ "commentModel", commentModel; "forest", JSON.Array forest ] ->
CommentDatabaseModelNode (parseComment commentModel, List.map parseTree forest)
| _ -> failwith "Bad data"
let parse (input : JSON) : CommentMultiTreeDatabaseModel =
match input with
| JSON.Object [ "commentTree", commentTree ] ->
parseTree commentTree
| _ -> failwith "Bad data"
let comment text =
JSON.Object [
"commentId", JSON.String ""
"userId", JSON.String ""
"message", JSON.String text
]
let sampleData =
JSON.Object [
"commentTree", JSON.Object [
"commentModel", comment "one"
"forest", JSON.Array [
JSON.Object [
"commentModel", comment "two"
"forest", JSON.Array []
]
JSON.Object [
"commentModel", comment "three"
"forest", JSON.Array []
]
]
]
]
parse sampleData
(*
val it : CommentMultiTreeDatabaseModel =
CommentDatabaseModelNode
({commentId = "";
userId = "";
message = "one";},
[CommentDatabaseModelNode ({commentId = "";
userId = "";
message = "two";},[]);
CommentDatabaseModelNode ({commentId = "";
userId = "";
message = "three";},[])])
*)