Elm:解析嵌套的 json

问题描述

我正在尝试解析一些 JSON,但似乎没有加载任何内容。当我加载页面时,我可以在 Chrome 调试器中看到 JSON 响应,但视图加载了“网络错误”文本。

JSON 有效负载

{"results":[{"gender":"female","name":{"title":"Miss","first":"آیناز","last":"سلطانی نژاد"},"location":{"street":{"number":2947,"name":"شهید رحمانی"},"city":"شیراز","state":"بوشهر","country":"Iran","postcode":80573,"coordinates":{"latitude":"33.5772","longitude":"113.9587"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"aynz.sltnynjd@example.com","login":{"uuid":"25054693-ce95-451b-8b35-dbcb518c4911","username":"greenswan774","password":"call","salt":"7JvweTbR","md5":"87b9692b8d3c50f2addc99763ffd6b44","sha1":"0480a79a2087646add3f54261ce9871abae40839","sha256":"a71d7407cecac726852c2abf4a1fb15e9c67c9ce99ce9d8f0783463101606ff4"},"dob":{"date":"1988-03-28T06:33:18.348Z","age":33},"registered":{"date":"2014-07-03T22:30:18.654Z","age":7},"phone":"005-72600454","cell":"0936-203-1121","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/33.jpg","medium":"https://randomuser.me/api/portraits/med/women/33.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/33.jpg"},"nat":"IR"}],"info":{"seed":"e887b219e4314703","results":1,"page":1,"version":"1.3"}}

模型.elm

module Model exposing (..)

import Json.Decode as Decode exposing (Decoder,int,string,float)
import Json.Decode.Pipeline exposing (required,optional,hardcoded)
import Html.Attributes exposing (list)


-- {"results": [
--   {
--     "gender": "male",--     "name": {
--       "title": "Mr",--       "first": "Habacuc",--       "last": "da Mota"
--     },--     "location": {
--       "street": {
--         "number": 9305,--         "name": "Rua Dois"
--       },--       "city": "São Leopoldo",--       "state": "Mato Grosso do Sul",--       "country": "Brazil",--       "postcode": 94950,--       "coordinates": {
--         "latitude": "-78.8074",--         "longitude": "-143.2939"
--       },--       "timezone": {
--         "offset": "0:00",--         "description": "Western Europe Time,London,Lisbon,Casablanca"
--       }
--     },--     "email": "habacuc.damota@example.com",--     "login": {
--       "uuid": "747e4d7f-31fd-4607-ac85-32b2c91e8822",--       "username": "lazyfrog284",--       "password": "shooter",--       "salt": "mf82yaB6",--       "md5": "faf67ad9fc3aa0962211b2722ecb18f1",--       "sha1": "1ea07c8be37a3fe1d647ad801597f4335a976ba9",--       "sha256": "a685e68ff871073a1d04488ff3ae46235e60b61663ff92b92b850460b75bf79b"
--     },--     "dob": {
--       "date": "1953-02-25T08:30:12.318Z",--       "age": 68
--     },--     "registered": {
--       "date": "2014-07-13T17:56:19.517Z",--       "age": 7
--     },--     "phone": "(76) 0855-1123",--     "cell": "(13) 3195-1920",--     "id": {
--       "name": "",--       "value": null
--     },--     "picture": {
--       "large": "https://randomuser.me/api/portraits/men/15.jpg",--       "medium": "https://randomuser.me/api/portraits/med/men/15.jpg",--       "thumbnail": "https://randomuser.me/api/portraits/thumb/men/15.jpg"
--     },--     "nat": "BR"
--   }
-- ],-- "info": {
--   "seed": "4ad06236fb06ef08",--   "results": 1,--   "page": 1,--   "version": "1.3"
-- }
-- } 

type alias ProfileName = 
    {
        title: String,first: String,last: String
    }

type alias Login = 
    {
        uuid: String,username: String,password: String,salt: String,md5: String,sha1: String,sha256: String
    }

type alias Location = 
    {
        street: Street,city: String,state: String,country: String,postcode: String,coordinates: Coordinates

    }

type alias Street = 
    {
        name: String,number: String
    }

type alias dob = 
    {
        date: String,age: String
    }

type alias Coordinates =   
    {
        latitude: String,longitude: String
    }

type alias Picture  = 
    {
        large: String,medium: String,thumbnail: String
    }

type alias Registered = 
    {
        date: String,age: String
    }


type alias Profile = 
            {
                gender: String,name: ProfileName,location: Location,email: String,login: Login,dob: dob,phone: String,cell: String,registered: Registered,picture: Picture,nat: String
                
            }


resultsDecoder: Decoder JsonResults
resultsDecoder =
    Decode.succeed JsonResults
        |> required "results" profilesDecoder


coordinatesDecoder: Decoder Coordinates
coordinatesDecoder = 
    Decode.succeed Coordinates
        |> required "latitude" string
        |> required "longitude" string


dobDecoder: Decoder dob
dobDecoder = 
    Decode.succeed dob
        |> required "date" string
        |> required "age" string


registeredDecoder: Decoder Registered
registeredDecoder = 
    Decode.succeed Registered
        |> required "date" string
        |> required "age" string

pictureDecoder: Decoder Picture
pictureDecoder = 
    Decode.succeed Picture
        |> required "large" string
        |> required "medium" string
        |> required "thumbnail"  string

loginDecoder: Decoder Login
loginDecoder = 
    Decode.succeed Login
        |> required "uuid" string
        |> required "username" string
        |> required "password" string
        |> required "salt" string
        |> required "md5" string
        |> required "sha1" string
        |> required "sha256" string


streetDecoder: Decoder Street
streetDecoder = 
    Decode.succeed Street
        |> required "name" string
        |> required "number" string


locationDecoder: Decoder Location
locationDecoder = 
    Decode.succeed Location
        |> required "street" (streetDecoder)
        |> required "city" string
        |> required "state" string
        |> required "country" string
        |> required "postcode" string
        |> required "coordinates" (coordinatesDecoder)


profileNameDecoder: Decoder ProfileName
profileNameDecoder = 
    Decode.succeed ProfileName
        |> required "title" string
        |> required "first" string
        |> required "last" string

profileDecoder: Decoder Profile
profileDecoder = 
    Decode.succeed Profile
        |> required "gender" string
        |> required "name" (profileNameDecoder)
        |> required "location" (locationDecoder)
        |> required "email" string
        |> required "login" (loginDecoder)
        |> required "dob" (dobDecoder)
        |> required "phone" string
        |> required "cell" string
        |> required "registered" (registeredDecoder)
        |> required "picture" (pictureDecoder)
        |> required "nat" string

type alias Profiles = 
    List Profile
profilesDecoder: Decoder Profiles
profilesDecoder = 
    Decode.list profileDecoder

type alias JsonResults =
    {
        results: List Profile
    }

Main.elm

module GetProfile exposing (..)

import browser
import Html exposing (..)
import Html.Events exposing (onClick)

import Http 
import RemoteData exposing (..)
import Model exposing (Profile,Profiles,JsonResults)
import Http exposing (Response(..))

type alias Model = 
    {
        results: WebData JsonResults
    }



init: Model
init = 
    {results = Loading}

type Msg
    = ResultsResponse (WebData JsonResults)


update : Msg -> Model -> ( Model,Cmd Msg )
update msg model =
    case msg of
        ResultsResponse response ->
            ( { model | results = response },Cmd.none
            )

getProfiles : Cmd Msg
getProfiles = 
    Http.get
        { url = "https://randomuser.me/api/",expect =
            Http.expectJson
                (RemoteData.fromresult >> ResultsResponse)
                Model.resultsDecoder
        }


viewProfile : Profile -> Html msg
viewProfile profile =
    div
        []
        [ h2 [] [ text profile.email ],p [] [ text profile.gender ]
        ]

viewProfiles : JsonResults -> Html msg
viewProfiles jsonresult =
    div [] (List.map viewProfile jsonresult.results)


view : Model -> Html msg
view model =
    case model.results of
        NotAsked ->
            div [] [ text "Initializing" ]

        Loading ->
            div [] [ text "Loading" ]

        Failure _ ->
            div [] [ text "Network Error"]

        Success results ->
            viewProfiles results

main : Program () Model Msg
main =
    browser.element
        { init = \_ -> ( init,getProfiles ),view = view,update = update,subscriptions = \_ -> Sub.none
        }

解决方法

尝试使用 Debug.log 获取有关错误的更多信息:

        Failure err ->
            let
                _ = Debug.log "Failed" err
            in
            div [] [ text "Network Error"]

否则很难确定解码错误。