简体   繁体   English

将JSON多路树解码为F#多路树区分的联合

[英]Decode JSON Multiway Tree into an F# Multiway Tree Discriminated Union

I have the following JSON data in a documentdb and I would like to parse this into an F# multiway tree discriminated union 我在documentdb中具有以下JSON数据,我想将其解析为F#多向树区分的联合

"commentTree": {
    "commentModel": {
        "commentId": "",
        "userId": "",
        "message": ""
      },
      "forest": []
    }

F# multiway discriminated union F#多路歧视工会

type public CommentMultiTreeDatabaseModel = 
| CommentDatabaseModelNode of CommentDatabaseModel * list<CommentMultiTreeDatabaseModel>

where CommentMultiTreeDatabaseModel is defined as 其中CommentMultiTreeDatabaseModel定义为

type public CommentDatabaseModel =
{ commentId : string
  userId : string
  message : string
}

I am referencing Fold / Recursion over Multiway Tree in f# extensively. 在f#中广泛引用了Multiway Tree上的Fold /递归 I am not sure where to begin to parse such a JSON structure into an F# multiway tree. 我不确定从哪里开始将这种JSON结构解析为F#多路树。 Any suggestions will be much appreciated. 任何建议将不胜感激。 Thanks 谢谢

One way to think about this is by looking at what data you need in order to construct a CommentMultiTreeDatabaseModel . 考虑这一点的一种方法是查看需要哪些数据以构造CommentMultiTreeDatabaseModel It needs a CommentDatabaseModel and a list of CommentMultiTreeDatabaseModel . 它需要一个CommentDatabaseModel和一个CommentMultiTreeDatabaseModel列表。 So we need to write the following two functions: 因此,我们需要编写以下两个函数:

let parseComment (input : JSON) : CommentDatabaseModel =
    ...

let parseTree (input : JSON) : CommentMultiTreeDatabaseModel =
    ...

But wait, the parseTree function is the one we're trying to write right now! 但是,等等, parseTree函数是我们现在正在尝试编写的函数! So instead of writing a new function, we just mark our current function with the rec keyword and have it call itself where needed. 因此,我们无需编写新函数,而只是使用rec关键字标记当前函数,并在需要时调用它自己。

Below is a rough example of how it could be done. 下面是一个大概的例子。 The key thing to look at is parseTree which builds up the data by recursively calling itself. 要查看的关键是parseTree ,它通过递归调用自身来构建数据。 I've represented the JSON input data with a simple DU. 我已经用一个简单的DU表示了JSON输入数据。 A library like Chiron can produce something like this. Chiron这样的库可以产生这样的东西。

Note that this code parses all of the JSON in one go. 请注意,此代码可以一次性解析所有JSON。 Also, it's not tail-recursive, so you'll have to be careful with how deep your tree structure is. 另外,它不是尾递归的,因此您必须注意树结构的深度。

[<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";},[])])
*)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM