2016-02-06 22 views
5

Ho un bisogno di decodificare JSON in un tipo di olmo come di seguito:Elm personalizzato complesso JSON decoder

Tipo

type User = Anonymous | LoggedIn String 

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

JSON Messaggio 1

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

in valore tipo

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

JSON Messaggio 2

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

in valore tipo

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

Decoder informazioni

Sopra, "messaggio" non è sempre presente e EMAIL_ID/id/gettone non sono sempre presente.

come fare questo tipo di decodifica condizionale in olmo

risposta

8

Json.Decode.andThen ti permette di fare l'analisi condizionale in base al valore di un campo. In questo caso, sembra che prima desideri estrarre il valore del campo "stato", andThen gestirlo separatamente in base al fatto che si tratti di un valore 1 o 0.

Edit 2016/12/15: aggiornato per olmo-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

Grazie ancora per la soluzione meravigliosa. Funziona. Potresti passarmi qualche link per capire come funziona il decodificatore JSON visto che sembra un po 'oscuro sul perché Task e 'andThen' sono usati qui. Anche se è uno scopo molto generale, inizialmente ho pensato a Task come promesse con task.Tale caratteristica e quindi confusione. –

+1

Dai un altro sguardo al link. Non sta usando ['Task.andThen'] (http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Task#andThen), sta usando una funzione della stessa nome per i decoder Json. Dai un'occhiata a entrambi i set di API e vedrai altre somiglianze come 'succeed' e' fail'. Questo si allinea con i modelli base di Monad, che sono un modello comune nei linguaggi funzionali, sebbene Elm eviti di chiamarli semplicemente Monadi perché comprendere le Monadi può essere scoraggiante. Non hai bisogno di capire Monads per analizzare Json. –

Problemi correlati