解码列表时忽略无效项
Ignore invalid item when decoding list
是否可以在解码列表时忽略无效项?
示例:我有一个模型
type Type
= A
| B
type alias Section =
{ sectionType : Type
, index : Int
}
getTypeFromString : String -> Maybe Type
getTypeFromString input =
case input of
“a” ->
Just A
“b” ->
Just B
_ ->
Nothing
decodeType : Decoder Type
decodeType =
Decode.string
|> Decode.andThen
(\str ->
case getTypeFromString str of
Just sectionType ->
Decode.succeed sectionType
Nothing ->
Decode.fail <| ("Unknown type" ++ str)
)
decodeSection : Decoder Section
decodeSection =
Decode.map2 Section
(Decode.field "type" decodeType)
(Decode.field "index" Decode.int)
如果我解码 JSON
{
"sections": [{type: "A", index: 1}, {type: "invalid-type", index: 2}]
}
我希望我的部分 = [ {type = A, index= 1} ]
通常处理这些问题的方法是将其解码为表达选项的 Elm 类型,然后 post 使用 map
.
处理
所以例如在你的例子中,我会选择这样的东西:
decodeMaybeType : Decoder (Maybe Type)
decodeMaybeType =
Decode.string
|> Decode.map getTypeFromString
decodeMaybeSection : Decoder (Maybe Section)
decodeMaybeSection =
Decode.map2 (\maybeType index -> Maybe.map (\t -> Section t index) maybeType)
(Decode.field "type" decodeMaybeType)
(Decode.field "index" Decode.int)
decodeSections : Decoder (List Section)
decodeSections =
Decode.list decodeMaybeSection
|> Decode.map (List.filterMap identity)
注意:List.filterMap identity
是一个 List (Maybe a) -> List a
,它会一次性过滤掉 Nothing
并去掉 Maybe
。
鉴于 Quan Vo 关于许多字段之一的评论可能无效,使用 Decode.oneOf
可能更合适。
您为每个字段编写解码器。如果任何字段不合法,Section
解码器将失败,并在 oneOf
中返回 Nothing
。
(这里我也用了NoRedInk的Json.Decode.Pipeline
)。
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (required)
type Type
= A
| B
type alias Section =
{ sectionType : Type
, index : Int
}
getTypeFromString : String -> Maybe Type
getTypeFromString input =
case input |> String.toLower of
"a" ->
Just A
"b" ->
Just B
_ ->
Nothing
decodeType : Decoder Type
decodeType =
Decode.string
|> Decode.andThen
(\str ->
case getTypeFromString str of
Just sectionType ->
Decode.succeed sectionType
Nothing ->
Decode.fail <| ("Unknown type" ++ str)
)
decodeSection : Decoder Section
decodeSection =
Decode.succeed Section
|> required "type" decodeType
|> required "index" Decode.int
-- Either we succeed in decoding a Section or fail on some field.
decodeMaybeSection : Decoder (Maybe Section)
decodeMaybeSection =
Decode.oneOf
[ decodeSection |> Decode.map Just
, Decode.succeed Nothing
]
decodeSections : Decoder (List Section)
decodeSections =
Decode.list decodeMaybeSection
|> Decode.map (List.filterMap identity)
是否可以在解码列表时忽略无效项? 示例:我有一个模型
type Type
= A
| B
type alias Section =
{ sectionType : Type
, index : Int
}
getTypeFromString : String -> Maybe Type
getTypeFromString input =
case input of
“a” ->
Just A
“b” ->
Just B
_ ->
Nothing
decodeType : Decoder Type
decodeType =
Decode.string
|> Decode.andThen
(\str ->
case getTypeFromString str of
Just sectionType ->
Decode.succeed sectionType
Nothing ->
Decode.fail <| ("Unknown type" ++ str)
)
decodeSection : Decoder Section
decodeSection =
Decode.map2 Section
(Decode.field "type" decodeType)
(Decode.field "index" Decode.int)
如果我解码 JSON
{
"sections": [{type: "A", index: 1}, {type: "invalid-type", index: 2}]
}
我希望我的部分 = [ {type = A, index= 1} ]
通常处理这些问题的方法是将其解码为表达选项的 Elm 类型,然后 post 使用 map
.
所以例如在你的例子中,我会选择这样的东西:
decodeMaybeType : Decoder (Maybe Type)
decodeMaybeType =
Decode.string
|> Decode.map getTypeFromString
decodeMaybeSection : Decoder (Maybe Section)
decodeMaybeSection =
Decode.map2 (\maybeType index -> Maybe.map (\t -> Section t index) maybeType)
(Decode.field "type" decodeMaybeType)
(Decode.field "index" Decode.int)
decodeSections : Decoder (List Section)
decodeSections =
Decode.list decodeMaybeSection
|> Decode.map (List.filterMap identity)
注意:List.filterMap identity
是一个 List (Maybe a) -> List a
,它会一次性过滤掉 Nothing
并去掉 Maybe
。
鉴于 Quan Vo 关于许多字段之一的评论可能无效,使用 Decode.oneOf
可能更合适。
您为每个字段编写解码器。如果任何字段不合法,Section
解码器将失败,并在 oneOf
中返回 Nothing
。
(这里我也用了NoRedInk的Json.Decode.Pipeline
)。
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (required)
type Type
= A
| B
type alias Section =
{ sectionType : Type
, index : Int
}
getTypeFromString : String -> Maybe Type
getTypeFromString input =
case input |> String.toLower of
"a" ->
Just A
"b" ->
Just B
_ ->
Nothing
decodeType : Decoder Type
decodeType =
Decode.string
|> Decode.andThen
(\str ->
case getTypeFromString str of
Just sectionType ->
Decode.succeed sectionType
Nothing ->
Decode.fail <| ("Unknown type" ++ str)
)
decodeSection : Decoder Section
decodeSection =
Decode.succeed Section
|> required "type" decodeType
|> required "index" Decode.int
-- Either we succeed in decoding a Section or fail on some field.
decodeMaybeSection : Decoder (Maybe Section)
decodeMaybeSection =
Decode.oneOf
[ decodeSection |> Decode.map Just
, Decode.succeed Nothing
]
decodeSections : Decoder (List Section)
decodeSections =
Decode.list decodeMaybeSection
|> Decode.map (List.filterMap identity)