2016-02-06 2 views
5

У меня есть необходимость для декодирования JSON в типа ильма, как показано ниже:Элх комплекс пользовательских JSON декодер

Типа

type User = Anonymous | LoggedIn String 

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

JSON Сообщения 1

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

в значение типа

Model { 
    "email_id": Anonymous 
    , id: 0 
    , status: 0 
    , message: json.message 
    , accessToken: "" 
} 

JSON Сообщение 2

{ 
    "status": 1, 
    "email_id": "[email protected]" 
    "token": "asdfaz.adfasggwegwegwe.g4514514ferf" 
    "id": 234 
} 

в значение типа

Model { 
    "email_id": LoggedIn json.email_id 
    , id: json.id 
    , status: json.status 
    , message: "" 
    , accessToken: json.token 
} 

Decoder информация

Выше, "сообщение" не всегда присутствует и email_id/идентификатор/маркер всегда не настоящее время.

Как сделать этот тип условного декодирования в вяз

ответ

8

Json.Decode.andThen позволяет сделать условный синтаксический анализ на основе значения поля. В этом случае, похоже, вы сначала захотите вытащить значение поля «статус», andThen обрабатывать его отдельно в зависимости от того, является ли он 1 или 0.

Edit 2016-12-15: Обновление для вяза-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": "[email protected]" 
    "token": "asdfaz.adfasggwegwegwe.g4514514ferf" 
    "id": 234 
} 
""" 
+0

Еще раз спасибо за замечательным решение. Оно работает. Не могли бы вы передать мне некоторые ссылки, чтобы понять, как работает декодер JSON, поскольку кажется немного непонятным, почему здесь используются задачи и 'andThen'. Хотя это очень общая цель, изначально я думал о Задачах как о обещаниях с заданием. –

+1

Еще раз взгляните на ссылку. Он не использует ['Task.andThen'] (http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Task#andThen), он использует функцию того же имя для декодеров Json. Взгляните на оба набора API, и вы увидите другие сходства, такие как 'success' и' fail'. Это связано с основными шаблонами Monad, которые являются общим образцом на функциональных языках, хотя Elm намеренно избегает вызова их Monads, потому что понимание Monads может быть сложным. Вам не нужно понимать Monads для разбора Json. –

Смежные вопросы