json - 解码递归多路树

标签 json elm multiway-tree

我正在研究这种类型的递归树

type Node anyType
  = Leaf Id (Maybe anyType) Name
  | Tree Id (List (Node anyType)) Name

哪里

type Id
  = Id Int
  | Root

我正在尝试将这种 json 解码为它

{
  "id": "root",
  "entries": [
    {
      "id": 1,
      "value": 0,
      "name": "New Entry"
    },
    {
      "id": 2,
      "entries": [
        {
          "id": 4,
          "value": 0,
          "name": "New Entry"
        }
      ],
      "name": "New Entry"
    }
  ],
  "name": "Budget"
}

为了解码 Id 类型,我正在使用这些解码器

rootDecoder =
(Decode.field "id" Decode.string)
    |> Decode.andThen
        (\str ->
            if str == "root" then
                (Decode.succeed Root)

            else
                Decode.fail <| "[exactMatch] tgt: " ++ "root" ++ " /= " ++ str
        )


intIdDecoder =
    Decode.map Id (Decode.field "id" Decode.int)


idDecoder =
    Decode.oneOf
        [ rootDecoder
        , intIdDecoder
        ]

为了解码树结构,我尝试了以下操作,使用 Json.Decode.Pipeline:

leafDecoder valueDecoder =
    Decode.succeed Leaf
        |> required "id" idDecoder
        |> required "value" valueDecoder
        |> required "name" Decode.string


treeDecoder valueDecoder =
    Decode.succeed Tree
        |> required "id" idDecoder
        |> required "entries"
            (Decode.list
                (Decode.lazy
                    (\_ ->
                        Decode.oneOf
                            [ leafDecoder valueDecoder
                            , treeDecoder valueDecoder
                            ]
                    )
                )
            )
        |> required "name" Decode.string

但是当我尝试解码该结构时,出现以下错误:

The Json.Decode.oneOf at json.budget.entries[0] failed in the following 2 ways: (1) The Json.Decode.oneOf at json.id failed in the following 2 ways: (1) Problem with the given value: 1 Expecting an OBJECT with a field named `id` (2) Problem with the given value: 1 Expecting an OBJECT with a field named `id` (2) Problem with the given value: { "id": 1, "value": 0, "name": "New Entry" } Expecting an OBJECT with a field named `entries`

但我不明白为什么,因为字段 identries 都在那里,但它还是提示。

我做错了什么?

最佳答案

在您的 leafDecodertreeDecoder 中,您有以下几行:

leafDecoder valueDecoder =
    Decode.succeed Leaf
        |> required "id" idDecoder
        -- rest of function omitted...

treeDecoder valueDecoder =
    Decode.succeed Tree
        |> required "id" idDecoder
        -- rest of function omitted...

它们都会提取当前对象中的字段 id 的值,并将该值传递给 idDecoder,后者调用 Decode.oneOfrootDecoderintIdDecoder

但是,在您的 rootDecoderintIdDecoder 中,您有以下内容:

rootDecoder =
    (Decode.field "id" Decode.string)
        |> Decode.andThen
            -- rest of function omitted...

intIdDecoder =
    Decode.map Id (Decode.field "id" Decode.int)

这些解码器尝试从当前对象中提取名为 id 的字段的值。但是您向这些函数传递的是 id 属性的值,而不是包含此属性的对象。

如果您的 id 嵌套在仅包含 id 属性的对象中,这些解码器将起作用,例如:

{
  "id": {"id": "root"},
  "entries": [
    {
      "id": {"id": 1},
      "value": 0,
      "name": "New Entry"
    },
    ...

修复方法是删除 rootDecoderintIdDecoder 中对 Decode.field 的调用,因为这些解码器已经传递了id 字段:

rootDecoder =
    Decode.string
        |> Decode.andThen
            -- rest of function as before, and omitted for brevity...


intIdDecoder =
    Decode.map Id Decode.int

关于json - 解码递归多路树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71070087/

相关文章:

ios - 如何从 json Result In swift 中删除可选文本

json - asp web api json序列化返回私有(private)属性

haskell - 如何使用函数式响应式(Reactive)编程在每个时间步查询 URL?

在 Elm 0.19 中合并具有可扩展记录的模型

tree - OCaml 中多路树的最大值

java - 从 PlayFramework 表单发布 JSON 数据

javascript - 如何在这个基于正则表达式的 JSON 到 XML 转换器中处理嵌套数组

elm - 如何为 Elm 中的嵌套记录制作通用更新功能

java - 数据结构 : Which should I use for these conditions?

f# - 在 f# 中折叠/递归多路树