简体   繁体   English

Elm - 解码递归多路树

[英]Elm - decoding a recursive multiway tree

I'm working on a recursive tree of this type我正在研究这种类型的递归树

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

where在哪里

type Id
  = Id Int
  | Root

and I'm trying to decode a json of this kind into it我正在尝试将这种类型的 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"
}

To decode the Id type I'm using these decoders要解码我使用这些解码器的 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
        ]

To decode the tree structure i tried the following, using Json.Decode.Pipeline:为了解码树结构,我尝试了以下方法,使用 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

But when I try to decode the structure I get the following error:但是当我尝试解码结构时,出现以下错误:

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`

But I don't understand why since both the field id and entries are there, and yet it complains.但我不明白为什么既然字段identries都在那里,但它会抱怨。

What am I doing wrong?我究竟做错了什么?

Thanks in advance for the help先谢谢您的帮助

In your leafDecoder and treeDecoder you have the following lines:在您的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...

These will both pull out the value of the field id within the current object and pass this value on to idDecoder , which calls Decode.oneOf with rootDecoder and intIdDecoder .这些都将提取当前 object 中字段id的值,并将该值传递给idDecoder ,后者使用rootDecoderintIdDecoder Decode.oneOf

However, in your rootDecoder and intIdDecoder you have the following:但是,在您的rootDecoderintIdDecoder中,您具有以下内容:

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

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

These decoders attempt to pull the value of a field named id from the current object. But you pass these functions the value of the id property, not an object containing this property.这些解码器试图从当前 object 中提取名为id的字段的值。但是您将id属性的值传递给这些函数,而不是包含该属性的 object。

These decoders would work if your id s were nested in objects that only contained id properties, for example:如果您的id嵌套在仅包含id属性的对象中,这些解码器将起作用,例如:

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

The fix is to remove the calls to Decode.field in rootDecoder and intIdDecoder , as these decoders already get passed the value of the id field:解决方法是删除rootDecoderintIdDecoder中对Decode.field的调用,因为这些解码器已经传递了id字段的值:

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


intIdDecoder =
    Decode.map Id Decode.int

The problem is that both rootDecoder and intIdDecoder are defined as looking for a field named "id" in an object via Decode.field "id"... .问题是rootDecoderintIdDecoder都被定义为通过Decode.field "id"...在 object 中查找名为"id"的字段。 Inside treeDecoder , you are first fetching the "id" field, so your decoder is valid for some JSON like thistreeDecoder内部,您首先要获取"id"字段,因此您的解码器对某些 JSON 有效

// Not what you're looking for
{
  "id": {
    "id": ...
  },
  ...
}

You can fix this by removing the Decode.field "id" portion in those decoders:您可以通过删除这些解码器中的Decode.field "id"部分来解决此问题:

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

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


intIdDecoder =
    Decode.map Id Decode.int

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

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