Декодировать JSON Multiway Tree в F# Multiway Tree Discriminated Union

У меня есть следующие данные JSON в documentdb, и я хотел бы проанализировать это в многостороннем разделенном объединении дерева 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 в f#. Я не уверен, с чего начать анализировать такую ​​структуру JSON в многоканальном дереве F#. Любые предложения будут высоко оценены. Спасибо


person Jonathan Fishbein    schedule 05.01.2017    source источник
comment
Я предполагаю, что настоящий вопрос, который вы хотите задать, заключается в том, как разобрать рекурсивную структуру json на соответствующий рекурсивный тип данных в F #?   -  person scrwtp    schedule 07.01.2017


Ответы (1)


Один из способов подумать об этом — посмотреть, какие данные вам нужны для построения CommentMultiTreeDatabaseModel. Ему нужен CommentDatabaseModel и список CommentMultiTreeDatabaseModel. Итак, нам нужно написать следующие две функции:

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

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

Но подождите, функцию parseTree мы пытаемся написать прямо сейчас! Поэтому вместо того, чтобы писать новую функцию, мы просто помечаем нашу текущую функцию ключевым словом rec и заставляем ее вызывать себя там, где это необходимо.

Ниже приведен грубый пример того, как это можно сделать. Главное, на что стоит обратить внимание, это parseTree, который создает данные, рекурсивно вызывая сам себя. Я представил входные данные JSON с помощью простого DU. Библиотека, например 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";},[])])
*)
person Dave    schedule 09.01.2017
comment
Благодарю за ваш ответ. Я временно отложил реализацию этой функции в своем приложении, но я вернусь к ней. Спасибо еще раз - person Jonathan Fishbein; 07.02.2017
comment
Спасибо за ответ. Я только что реализовал это вместе с использованием Chiron - person Jonathan Fishbein; 20.04.2017