ELM 解析嵌套 json
ELM parse nested json
我有一个 json 数组,其中包含多个可以嵌套的注释。
示例:
[
{
"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": ""
},
]
所以这是一个评论列表,每条评论都可以有一个回复,回复次数是无限的。
使用 Json.Decode.list
我可以解码第一级评论,但是我如何检查是否有回复然后再次解析?
这是我尝试做的事情的简化版本。我实际上是在尝试解码 reddit 评论。 exemple
Elm 不允许您创建递归记录类型别名,因此您必须为 Customer
使用联合类型。您可能还需要一个方便的功能来创建用户,以便您可以使用 Json.map3
.
您的示例 json 有一个奇怪之处:有时 reply
是一个空字符串,有时它是一个列表。您将需要一个特殊的解码器将该字符串转换为一个空列表(假设空列表与此上下文中的空列表同义)。
因为你有一个递归类型,你需要使用 lazy
来解码子注释以避免运行时错误。
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": ""
}]
}]
"""
(您的 json 在其他方面也有一点偏差:在列表的最后部分之后有一些额外的逗号并且 reply
字段之一丢失了)
我有一个 json 数组,其中包含多个可以嵌套的注释。
示例:
[
{
"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": ""
},
]
所以这是一个评论列表,每条评论都可以有一个回复,回复次数是无限的。
使用 Json.Decode.list
我可以解码第一级评论,但是我如何检查是否有回复然后再次解析?
这是我尝试做的事情的简化版本。我实际上是在尝试解码 reddit 评论。 exemple
Elm 不允许您创建递归记录类型别名,因此您必须为 Customer
使用联合类型。您可能还需要一个方便的功能来创建用户,以便您可以使用 Json.map3
.
您的示例 json 有一个奇怪之处:有时 reply
是一个空字符串,有时它是一个列表。您将需要一个特殊的解码器将该字符串转换为一个空列表(假设空列表与此上下文中的空列表同义)。
因为你有一个递归类型,你需要使用 lazy
来解码子注释以避免运行时错误。
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": ""
}]
}]
"""
(您的 json 在其他方面也有一点偏差:在列表的最后部分之后有一些额外的逗号并且 reply
字段之一丢失了)