[英]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.但我不明白为什么既然字段
id
和entries
都在那里,但它会抱怨。
What am I doing wrong?我究竟做错了什么?
Thanks in advance for the help先谢谢您的帮助
In your leafDecoder
and treeDecoder
you have the following lines:在您的
leafDecoder
和treeDecoder
中,您有以下几行:
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
,后者使用rootDecoder
和intIdDecoder
Decode.oneOf
However, in your rootDecoder
and intIdDecoder
you have the following:但是,在您的
rootDecoder
和intIdDecoder
中,您具有以下内容:
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:解决方法是删除
rootDecoder
和intIdDecoder
中对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"...
.问题是
rootDecoder
和intIdDecoder
都被定义为通过Decode.field "id"...
在 object 中查找名为"id"
的字段。 Inside treeDecoder
, you are first fetching the "id"
field, so your decoder is valid for some JSON like this在
treeDecoder
内部,您首先要获取"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.