将 JSON 解码为 Elm Maybe

Decode JSON into Elm Maybe

给出以下 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 package. You can then use the optional function to declare that your desc field may not be there. As Brian points out in the article, you can use the maybe decoder from the core Json.Decode package, but it will produce Nothing for any failure, not just being null. There is a nullable 解码器,如果您不想使用管道模块,也可以考虑使用它。

您的解码器可能看起来像这样:

modelDecoder : Decoder Model
modelDecoder =
    decode Model
        |> required "id" int
        |> required "name" string
        |> optional "desc" (Json.map Just string) Nothing

Here's a live example on Ellie.

布赖恩·希克斯的 "Adding New Fields to Your JSON Decoder" post helped me develop the following. For a working example, see 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

因此,如果您正在寻找不需要 Json.Decode.Pipeline.

的 zero-dependency 解决方案
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))

两者都可以与 ListDecode.list modelDecoder 一起使用。我希望应用函数在标准库中,但您必须访问所有 *-extra 库才能获得这些功能。了解应用仿函数的工作原理将帮助您进一步了解,因此我建议您阅读它们。解码管道解决方案抽象了这个简单的概念,但是当您 运行 需要 Result.andMap 或任何其他 andMap 时,因为您的模块没有 mapN 或DSL,你就会知道如何找到你的解决方案。

由于解码器的应用特性,所有字段都应该能够异步和并行处理,性能增益很小,而不是像 andThen 那样同步处理,这适用于您使用的每个地方andMap 超过 andThen。也就是说,当调试切换到 andThen 时,您可以为每个字段提供一个可用错误,当您知道一切正常时,可以将其更改为 andMap

在幕后,JSON.Decode.Pipeline 使用 Json.Decode.map2(即 andMap),因此没有性能差异,但使用的 DSL 可忽略不计 "friendly"。