榆树复杂的自定义JSON解码器

alp*_*cod 6 elm

我需要将JSON解码为elm类型,如下所示:

类型

type User = Anonymous | LoggedIn String

type alias Model =
  { email_id : User
  , id : Id
  , status : Int
  , message : String
  , accessToken : AccessToken
  }
Run Code Online (Sandbox Code Playgroud)

JSON消息1

{
  "status": 0,
  "message": "Error message explaining what happened in server"
}
Run Code Online (Sandbox Code Playgroud)

进入类型值

Model {
   "email_id": Anonymous
   , id: 0
   , status: 0
   , message: json.message
   , accessToken: ""
}
Run Code Online (Sandbox Code Playgroud)

JSON消息2

{
  "status": 1,
  "email_id": "asdfa@asdfa.com"
  "token": "asdfaz.adfasggwegwegwe.g4514514ferf"
  "id": 234
}
Run Code Online (Sandbox Code Playgroud)

进入类型值

Model {
   "email_id": LoggedIn json.email_id
   , id: json.id
   , status: json.status
   , message: ""
   , accessToken: json.token
}
Run Code Online (Sandbox Code Playgroud)

解码器信息

上面,"消息"并不总是存在,并且始终不存在email_id/id/token.

如何在elm中进行这种类型的条件解码

Cha*_*ert 9

Json.Decode.andThen允许您根据字段的值进行条件分析.在这种情况下,它看起来像你首先要拔出"状态"字段的值,andThen处理它单独基于它是否是10.

编辑2016-12-15:更新为elm-0.18

import Html as H
import Json.Decode exposing (..)

type User = Anonymous | LoggedIn String

type alias Id = Int

type alias AccessToken = String

type alias Model =
  { email_id : User
  , id : Id
  , status : Int
  , message : String
  , accessToken : AccessToken
  }

modelDecoder : Decoder Model
modelDecoder =
  (field "status" int) |> andThen modelDecoderByStatus

modelDecoderByStatus : Int -> Decoder Model
modelDecoderByStatus status =
  case status of
    0 ->
      map5
        Model
        (succeed Anonymous)
        (succeed 0)
        (succeed status)
        (field "message" string)
        (succeed "")
    1 ->
      map5
        Model
        (map LoggedIn (field "email_id" string))
        (field "id" int)
        (succeed status)
        (succeed "")
        (field "token" string)
    _ ->
      fail <| "Unknown status: " ++ (toString status)

main = H.div []
  [ H.div [] [ decodeString modelDecoder msg1 |> Result.toMaybe |> Maybe.withDefault emptyModel |> toString |> H.text ]
  , H.div [] [ decodeString modelDecoder msg2 |> Result.toMaybe |> Maybe.withDefault emptyModel |> toString |> H.text ]
  ]

emptyModel = Model Anonymous 0 0 "" ""

msg1 = """
{
  "status": 0,
  "message": "Error message explaining what happened in server"
}
"""

msg2 = """
{
  "status": 1,
  "email_id": "asdfa@asdfa.com"
  "token": "asdfaz.adfasggwegwegwe.g4514514ferf"
  "id": 234
}
"""
Run Code Online (Sandbox Code Playgroud)