I have a json array with multiple comments which can be nested.
exemple:
[
{
"author": "john",
"comment" : ".....",
"reply": "",
},
{
"author": "Paul",
"comment" : ".....",
"reply": [
{
"author": "john",
"comment" : "nested comment",
"reply": [
{
"author": "Paul",
"comment": "second nested comment"
}
]
},
{
"author": "john",
"comment" : "another nested comment",
"reply": ""
}
]
},
{
"author": "Dave",
"comment" : ".....",
"reply": ""
},
]
So it's a list of comment, which every comment can have a reply with an infinite number of reply.
With Json.Decode.list
I can decode the first level of comment, but how do I checked if there is some reply and then parse again ?
This is a simplify version of what I'm try to do. I'm actually trying to decode reddit comments. exemple
Elm won't let you create a recursive record type alias, so you'll have to use a union type for Customer
. You may also want a convenience function for creating a user so you can use Json.map3
.
Your example json has an oddity: Sometimes reply
is an empty string and sometimes it's a list. You'll need a special decoder to turn that string into an empty list (assuming an empty list is synonymous with an empty list in this context).
Since you have a recursive type, you need to use lazy
for decoding the child comments to avoid a runtime error.
import Html exposing (Html, text)
import Json.Decode as Json exposing (..)
main : Html msg
main =
text <| toString <| decodeString (list commentDecoder) s
type Comment
= Comment
{ author : String
, comment : String
, reply : List Comment
}
newComment : String -> String -> List Comment -> Comment
newComment author comment reply =
Comment
{ author = author
, comment = comment
, reply = reply
}
emptyStringToListDecoder : Decoder (List a)
emptyStringToListDecoder =
string
|> andThen
(\s ->
case s of
"" ->
succeed []
_ ->
fail "Expected an empty string"
)
commentDecoder : Decoder Comment
commentDecoder =
map3 newComment
(field "author" string)
(field "comment" string)
(field "reply" <|
oneOf
[ emptyStringToListDecoder
, list (lazy (\_ -> commentDecoder))
]
)
s =
"""
[{
"author": "john",
"comment": ".....",
"reply": ""
}, {
"author": "Dave",
"comment": ".....",
"reply": ""
}, {
"author": "Paul",
"comment": ".....",
"reply": [{
"author": "john",
"comment": "nested comment",
"reply": [{
"author": "Paul",
"comment": "second nested comment",
"reply": ""
}]
}, {
"author": "john",
"comment": "another nested comment",
"reply": ""
}]
}]
"""
(Your json is also a little off in other ways: There are a few extra commas after the last parts of list and one of the reply
fields is missing)