2016-02-06 9 views
5

ich eine Notwendigkeit, JSON in eine Ulme Art zu entschlüsseln wie unten:Elm komplexe benutzerdefinierte JSON-Decoder

Typ

type User = Anonymous | LoggedIn String 

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

JSON Nachricht 1

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

in Typwert

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

JSON Nachricht 2

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

in Typwert

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

Decoder Informationen

Oben, "message" ist nicht immer vorhanden und email_id/id/Token sind nicht immer Geschenk.

Wie diese Art der bedingten Decodierung in Ulme auf dem Wert eines Feldes

Antwort

8

Json.Decode.andThen können Sie tun Bedingte syntaktische Analyse tun basiert. In diesem Fall sieht es so aus, als ob Sie zunächst den Wert des Feldes "status" (andThen) herausziehen möchten, abhängig davon, ob es sich um eine 1 oder 0 handelt.

bearbeiten 2016.12.15: Aktualisiert Ulme-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

Nochmals vielen Dank für die wunderbare Lösung. Es klappt. Könnten Sie mir ein paar Links geben, um zu verstehen, wie der JSON-Decoder funktioniert, da es ein wenig unklar scheint, warum Tasks und 'andThen' hier verwendet werden. Obwohl es sehr allgemeiner Zweck ist, dachte ich zuerst an Aufgaben als Versprechen mit Aufgabe. Dann Feature und damit die Verwirrung. –

+1

Sehen Sie sich den Link noch einmal an. Es verwendet nicht ['Task.andThen'] (http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Task#andThen), es verwendet eine Funktion desselben Name für Json-Decoder. Sehen Sie sich beide APIs an und Sie werden weitere Ähnlichkeiten sehen, wie zum Beispiel 'success' und' fail'. Dies richtet sich nach grundlegenden Monad-Mustern, die in funktionalen Sprachen üblich sind, obwohl Elm es absichtlich vermeidet, sie Monaden zu nennen, weil das Verständnis von Monaden entmutigend sein kann. Sie müssen Monads nicht verstehen, um Json zu parsen. –