Один из способов подумать об этом, посмотрев, какие данные вам нужны, чтобы построить 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";},[])])
*)
Я думаю, что реальный вопрос, который вы хотите задать, состоит в том, как проанализировать рекурсивную структуру json в соответствующий рекурсивный тип данных в F #? – scrwtp