解码字符串列表

时间:2016-11-09 23:24:52

标签: elm

如何从JSON解码字符串列表?我有这个代码,每次都失败了:

import Html exposing (..)
import Html.App as App
import Html.Attributes exposing (..)
import Html.Events exposing (onInput, onClick)
import Http
import Json.Decode as Json exposing ((:=))
import Json.Decode exposing (object3)
import Task



main =
  App.program
    { view = view
    , init = init
    , update = update
    , subscriptions = subscriptions
    }



init : (Model, Cmd Msg)
init =
  (Model "" { productName = "", brand = "", alternateImagePaths = [] }, Cmd.none)


-- MODEL

type alias Product =
  { productName : String
  , brand : String
  , alternateImagePaths : List String
  }

type alias Model =
  { id : String
  , product : Product}

-- UPDATE


type Msg
  = GetProduct
  | UpdateText String
  | FetchSucceed Product
  | FetchFail Http.Error


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    GetProduct ->
      (model, getData model.id)

    UpdateText text ->
      ({ model | id = text }, Cmd.none )

    FetchSucceed p ->
      ({ model | product = p } , Cmd.none)

    FetchFail _ ->
      ({ model | id = "" }, Cmd.none)


-- VIEW


view : Model -> Html Msg
view model =
  div []
    [ input [ type' "text", onInput UpdateText ] []
    , button [ type' "button", onClick GetProduct ] [ text "Search" ]
    , br [] []
    , pre [] [ text model.id ]
    , pre [] [ text (toString model.product) ]
    ]


-- HTTP


getData : String -> Cmd Msg
getData id =
  let
    url = "https://localhost:3000/v2/product/" ++ id
  in
    Task.perform FetchFail FetchSucceed (Http.get decodeData url)


decodeData : Json.Decoder Product
decodeData =
  object3 Product
    ("productName" := Json.string)
    ("brand" := Json.string)
    ("alternateImagePaths" := Json.list Json.string)


subscriptions : Model -> Sub Msg
subscriptions model =
  Sub.none

如果我删除了alternateImagePaths,它会点击FetchSucceed功能,但如果我离开它,则会点击FetchFail功能。

数据结构(实际响应):

{
  "productName": "Men's San Francisco 49ers Design Your Own T-Shirt-",
  "team": [
    "San Francisco 49ers"
  ],
  "brand": "Pro Line",
  "shippingTimeFrame": 3
}

编辑:当您以某种方式获得不再存在的属性时,这显然会发生。

2 个答案:

答案 0 :(得分:1)

您确定自己拥有有效的JSON吗?你应该总是验证它 在让客户端代码使用它之前。

这是一个小修复后的工作代码。

import Html exposing (text)
import Json.Decode exposing (..)

json = """
{
  "productName": "Panthers Shirt",
  "brand": "Nike",
  "alternateImagePaths": ["url.com", "url2.com"],
  "dummy": "dummyval"
}
"""

main =
  text <| toString (decodeString decodeData json)

type alias Product =
  { productName : String
  , brand : String
  , alternateImagePaths : List String
  }

decodeData : Decoder Product
decodeData =
  object3 Product
    ("productName" := string)
    ("brand" := string)
    ("alternateImagePaths" := list string)

答案 1 :(得分:1)

据我了解,问题是alternateImagePaths可能包含也可能不包含在您要解码的json中。有几种方法可以解决这个问题。

  1. 您可以使用oneOf查找alternateImagePaths,如果它是是字符串列表,则可以成功。这是一种快速处理它的方法,因为如果alternateImagePaths是其他东西,你仍然会得到一个空列表,如整数:
  2. decodeData : Json.Decoder Product
    decodeData =
        Json.object3 Product
            ("productName" := Json.string)
            ("brand" := Json.string)
            (Json.oneOf ["alternateImagePaths" := Json.list Json.string, Json.succeed []])
    
    1. 您还可以使用NoRedInk/elm-decode-pipeline软件包,使用optional解码器明确处理此案例。
    2. decodeData : Json.Decoder Product
      decodeData =
          decode Product
              |> required "productName" Json.string
              |> required "brand" Json.string
              |> optional "alternateImagePaths" (Json.list Json.string) []
      

      我建议使用elm-decode-pipeline版本。在我看来,它使事情更容易阅读,它处理核心包遗漏的这些边缘情况。