将JSON多路树解码为F#多路树判别联合。

4

我在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#多路树。 任何建议将不胜感激。谢谢。


我猜你真正想问的问题是如何将递归的JSON结构解析为相应的递归数据类型在F#中? - scrwtp
1个回答

3

一个思考这个问题的方法是看看构建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";},[])])
*)

谢谢您的回复。我已经暂时推迟了在我的应用程序中实现这个功能,但我会回来处理它的。再次感谢。 - Jonathan Fishbein
1
感谢您的回复。我刚刚实现了它,并使用了Chiron。 - Jonathan Fishbein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接