给出以下 JSON:
[
{
"id": 0,
"name": "Item 1",
"desc": "The first item"
},
{
"id": 1,
"name": "Item 2"
}
]
如何将其解码为以下模型:
type alias Model =
{ id : Int
, name : String
, desc : Maybe String
}
Brian Hicks 有一系列关于 JSON 解码器的帖子,您可能需要专门查看
Adding New Fields to Your JSON Decoder
(它处理您可能会或可能不会从 JSON 对象接收字段的情况)。
首先,您可能需要使用 elm-decode-pipeline 包。然后,您可以使用
optional
函数 来声明您的 desc
字段可能不存在。正如 Brian 在文章中指出的那样,您可以使用 核心 maybe
包中的 Json.Decode
解码器,但它会针对 任何故障生成
Nothing
,而不仅仅是 null
。有 is 一个 nullable
解码器,如果您不想使用管道模块,也可以考虑使用它。
你的解码器可能看起来像这样:
modelDecoder : Decoder Model
modelDecoder =
decode Model
|> required "id" int
|> required "name" string
|> optional "desc" (Json.map Just string) Nothing
因此,如果您正在寻找不需要
Json.Decode.Pipeline
的零依赖解决方案。
import Json.Decode as Decode exposing (Decoder)
modelDecoder : Decoder Model
modelDecoder =
Decode.map3 Model
(Decode.field "id" Decode.int)
(Decode.field "name" Decode.string)
(Decode.maybe (Decode.field "desc" Decode.string))
如果您想使用
Model
构造函数作为应用函子来执行此操作(因为您需要更多 8 个项目)。
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra as Decode
modelDecoder : Decoder Model
modelDecoder =
Decode.succeed Model
|> Decode.andMap (Decode.field "id" Decode.int)
|> Decode.andMap (Decode.field "name" Decode.string)
|> Decode.andMap (Decode.maybe (Decode.field "desc" Decode.string))
两者都可以与
List
和 Decode.list modelDecoder
一起使用。我希望应用函数位于标准库中,但您必须访问所有 *-extra 库才能获得这些功能。了解应用函子的工作原理将帮助您更好地理解,所以我建议阅读它们。解码管道解决方案抽象了这个简单的概念,但是当您遇到需要 Result.andMap
或任何其他 andMap
(因为您的模块或 DSL 没有 mapN
)时,您将知道如何获取给你的解决方案。
由于解码器的应用性质,所有字段都应该能够异步和并行处理,并具有较小的性能增益,而不是像
andThen
那样同步处理,这适用于您使用andMap
而不是andThen
的每个地方
。也就是说,在调试时切换到 andThen
可以让您为每个字段提供一个可用的错误,当您知道一切都恢复正常时,可以将其更改为 andMap
。
在底层,
JSON.Decode.Pipeline
使用Json.Decode.map2
(即andMap
),因此没有性能差异,但使用了可以忽略不计的更“友好”的DSL。
(此内容可在 CC-BY-SA-4.0 下使用,且不得用于闭源 LLM 培训)
Brian Hicks 的 “向 JSON 解码器添加新字段” 帖子帮助我开发了以下内容。有关工作示例,请参阅Ellie
import Html exposing (..)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline as JP
import String
type alias Item =
{ id : Int
, name : String
, desc : Maybe String
}
main =
Decode.decodeString (Decode.list itemDecoder) payload
|> toString
|> String.append "JSON "
|> text
itemDecoder : Decoder Item
itemDecoder =
JP.decode Item
|> JP.required "id" Decode.int
|> JP.required "name" Decode.string
|> JP.optional "desc" (Decode.map Just Decode.string) Nothing