2015-12-18 14 views
5

Say Mam plik JSON znajdujący się http://www.randomurl.com/jobs.json, wygląda to tak:Czytaj w danych z pliku JSON

{ "jobs": [ 
    { "task" : "turn burgers" , 
    "who" : "Anni" , 
    "place" : "Quick"} 
    , 
    { "task" : "dishes" , 
    "who" : "Bob" , 
    "place" : "McDo"} 
]} 

Zrobiłem dekoder:

type alias Job = { 
    task : String 
, who : String 
, place: String 
} 

type alias Jobs = List Job 

decoder : Decoder Job 
decoder = 
    Decode.object3 Job 
    (Decode.at ["attributes", "task"] Decode.string) 
    (Decode.at ["attributes", "who"] Decode.string) 
    (Decode.at ["attributes", "place"] Decode.string) 

decoderColl : Decoder Jobs 
decoderColl = 
    Decode.object1 identity 
    ("jobs" := Decode.list decoder) 

Jak można odczytać w plik z tej strony za pomocą mojego dekodera? Zakładam, że potrzebuję pakietu Http, ale nie wiem, jak go zastosować.

Odpowiedz

9

Po pierwsze - Twoja funkcja decoder jest lekko wyłączona. Nie ma pośredni „atrybuty” obiektu, dzięki czemu można go zmienić na to:

decoder : Decoder Job 
decoder = 
    Decode.object3 Job 
    ("task" := Decode.string) 
    ("who" := Decode.string) 
    ("place" := Decode.string) 

Masz rację, że trzeba pakiet elm-http. Za pomocą tego można utworzyć zadanie Http.get, które odwzorowuje wynik na akcję.

Jako podstawowy przykład, zróbmy przycisk, który wyciągnie listę zadań z adresu URL. Będziemy potrzebować akcji GetJobs do wyzwalania żądania HTTP oraz akcji ShowJobs, która zostanie uruchomiona po pomyślnym powrocie żądania.

Zakładając naszą typu działania wygląda następująco:

type Action 
    = NoOp 
    | GetJobs 
    | ShowJobs (Maybe Jobs) 

Następnie możemy stworzyć getJobs funkcję, która buduje zadania, które mogą być uruchamiane. W tym prostym przykładzie możemy użyć Task.toMaybe, aby wyłączyć wszelkie błędy dekodowania HTTP lub JSON.

getJobs : Effects Action 
getJobs = 
    Http.get decoderColl jobsUrl 
    |> Task.toMaybe 
    |> Task.map ShowJobs 
    |> Effects.task 

W celu klej to wszystko razem użyjemy StartApp ponieważ pozwala nam skorzystać z zadania i efekty. Oto działający przykład, który można zbudować lokalnie, zakładając, że plik jobs.json istnieje w tym samym katalogu.

import Http 
import StartApp 
import Effects exposing (Effects,Never) 
import Task 
import Html exposing (..) 
import Html.Events exposing (..) 
import Json.Decode as Decode exposing (Decoder, (:=)) 

jobsUrl = "./jobs.json" 

-- StartApp plumbing 
app = 
    StartApp.start { init = init, view = view, update = update, inputs = [] } 

main = 
    app.html 

port tasks : Signal (Task.Task Never()) 
port tasks = 
    app.tasks 


type Action 
    = NoOp 
    | GetJobs 
    | ShowJobs (Maybe Jobs) 

type alias Model = 
    { jobs : Maybe Jobs } 

init = 
    ({ jobs = Nothing }, Effects.none) 

update action model = 
    case action of 
    NoOp -> 
     (model, Effects.none) 
    GetJobs -> 
     ({ model | jobs = Nothing }, getJobs) 
    ShowJobs maybeJobs -> 
     ({ model | jobs = maybeJobs }, Effects.none) 

view address model = 
    div [] 
    [ button [ onClick address GetJobs ] [ text "Click to get jobs!" ] 
    , viewJobs model.jobs 
    ] 

viewJobs maybeJobs = 
    let 
    viewJob job = 
     li [] [ text ("Task: " ++ job.task ++ "; Who: " ++ job.who ++ "; Place: " ++ job.place) ] 
    in 
    case maybeJobs of 
     Nothing -> 
     div [] [ text "No jobs to display. Try clicking the button" ] 
     Just jobs -> 
     ul [] (List.map viewJob jobs) 

-- This is the key to map the result of the HTTP GET to an Action 
-- Note: Task.toMaybe swallows any HTTP or JSON decoding errors 
getJobs : Effects Action 
getJobs = 
    Http.get decoderColl jobsUrl 
    |> Task.toMaybe 
    |> Task.map ShowJobs 
    |> Effects.task 

-- An alternative to Task.toMaybe which dumps error information to the console log 
toMaybeWithLogging : Task.Task x a -> Task.Task y (Maybe a) 
toMaybeWithLogging task = 
    Task.map Just task `Task.onError` (\msg -> Debug.log (toString msg) (Task.succeed Nothing)) 

-- The Job type aliases from the question 
type alias Job = { 
    task : String 
    , who : String 
    , place: String 
} 

type alias Jobs = List Job 

-- The updated Job decoder 
decoder : Decoder Job 
decoder = 
    Decode.object3 Job 
    ("task" := Decode.string) 
    ("who" := Decode.string) 
    ("place" := Decode.string) 

decoderColl : Decoder Jobs 
decoderColl = 
    Decode.object1 identity 
    ("jobs" := Decode.list decoder) 
+0

Z jakiegoś powodu, kiedy próbuję skompilować twój kod, zabrakło mu pamięci, nigdy wcześniej tego nie robiłem. – Stanko

+0

Znalazłem problem, musiałem zmienić '({model | jobs = Nic}, getJobs)' na '({model | jobs <- Nic}, getJobs)'. Jaka jest różnica między '=' a '<-'? – Stanko

+0

'<-' został zmieniony na' = 'w tym kontekście ostatnio w wersji 0.16. Wygląda na to, że potrzebujesz najnowszej wersji wiązu. –