2015-12-18 110 views
5

說我有位於http://www.randomurl.com/jobs.json一個JSON文件,它看起來像這樣:讀取數據從JSON文件

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

我做了一個解碼器:

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) 

我怎麼能讀該網站使用我的解碼器的文件?我認爲我需要Http包,但我不知道如何應用它。

回答

9

首先 - 你的decoder功能稍微關閉。沒有中間的「屬性」的對象,所以你可以把它改成這樣:

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

你是正確的,你需要的elm-http包。使用此功能,您可以創建一個將結果映射到操作的Http.get任務。

作爲一個基本的例子,讓我們製作一個按鈕,從網址中下拉作業列表。我們需要一個GetJobs操作來觸發HTTP請求,以及一個ShowJobs操作,當請求成功返回時將觸發該操作。

假設我們的操作類型如下:

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

然後,我們可以創建一個getJobs函數,建立可運行的任務。對於這個簡單的例子,我們可以使用Task.toMaybe來抑制任何HTTP或JSON解碼錯誤。

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

爲了膠水都在一起,我們將使用StartApp因爲它可以讓我們用任務和作用。假設jobs.json存在於同一個目錄中,這是一個可以在本地構建的工作示例。

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

由於某些原因,當我嘗試編譯代碼時,它的內存不足,從來沒有這樣做過。 – Stanko

+0

發現問題,我需要將'({model | jobs = Nothing},getJobs)'改爲'({model | jobs < - Nothing},getJobs)'。 '='和'<-'有什麼區別? – Stanko

+0

最近在版本0.16中,<-'在該上下文中被更改爲「=」。聽起來像你只需要最新版本的elm –