'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
{
"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
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:
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.
What am I doing wrong?
Thanks in advance for the help
Solution 1:[1]
The problem is that both rootDecoder and intIdDecoder are defined as looking for a field named "id" in an object via Decode.field "id" .... Inside treeDecoder, you are first fetching the "id" field, so your decoder is valid for some JSON like this
// Not what you're looking for
{
"id": {
"id": ...
},
...
}
You can fix this by removing the Decode.field "id" portion in those decoders:
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Chad Gilbert |
