在 Elm 中解析 JSON

Parsing JSON in Elm

我想像这样解析 JSON:

{ "shapes":[
{
    "shape": "circle",
    "x": "50",
    "y": "50",
    "r": "40"
},
{
    "shape": "rect",
    "x": "100",
    "y": "100",
    "width": "50",
    "height": "60"
},
]}

这是我的 Elm 代码:​​

type alias Model =
    { input : Shape
    , saved : List Shape
    , modal1 : String
    , modal2 : String
    , modal3 : String
    , region : String
    }

type Shape
    = Circle String String String
    | Rectangle String String String String

type Msg
    = LoadJson
    | JsonLoaded (Result Http.Error (List Shape))

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of

    LoadJson -> 
        (model, getJson)

    JsonLoaded (Ok shapes) -> 
        ({ model | saved = shapes }, Cmd.none)

    JsonLoaded (Err _) ->
        (model, Cmd.none)

getJson =
    let
        url =
          "http://www.mywebsite.de/shapes.json"
    in
        Http.send JsonLoaded (Http.get url decoder)

decoder = 
    at ["shapes"] (list shapeDecoder)

shapeDecoder = 
    decode func 
        |> required "shape" string
        |> required "x" string
        |> required "y" string
        |> optional "r" string ""
        |> optional "width" string ""
        |> optional "height" string ""

func shape x y r width height = 
    case shape of
        "circle" ->
            Circle x y r

        "rect" ->
            Rectangle x y width height

        _ -> 
            Circle "" "" ""

名为 "saved" 的列表中的所有形状都应该列在 table 中。

如果我在此列表中写入一些元素,它们会显示在 table 中,但如果我试图从我的 JSON 中获取它们,则它们不会显示。我的解码器一定有问题,但我不知道是什么。

感谢您的帮助。

你可以简化你的解码器。使用 oneOf 我们可以尝试针对每个形状针对解码器解码 json。我不能 运行 这个反对你的网站,因为那不是一个真正的网站,但你可以 运行 这里有这个解码器的演示 https://ellie-app.com/cFrSPbrYna1/0

运行这个解码器针对你提供的json,你会得到

Ok ([Circle "50" "50" "40",Rectangle "100" "100" "50" "60"])

解码器:

import Json.Decode as Decode

decoder =
    Decode.at [ "shapes" ] (Decode.list decodeShape)


decodeShape =
    Decode.oneOf [ circleDecode, rectDecode ]


circleDecode =
    Decode.map4
        circle
        (Decode.field "shape" Decode.string)
        (Decode.field "x" Decode.string)
        (Decode.field "y" Decode.string)
        (Decode.field "r" Decode.string)


rectDecode =
    Decode.map5
        rect
        (Decode.field "shape" Decode.string)
        (Decode.field "x" Decode.string)
        (Decode.field "y" Decode.string)
        (Decode.field "width" Decode.string)
        (Decode.field "height" Decode.string)


circle shape x y r =
    -- Here you can, if you wanted to, have an assertion that the
    -- `shape` is indeed a "circle" and not something else
    -- In which case you probably want to return something like
    -- `Maybe Shape` or `MaybeCircle` instead of just a Circle.
    -- Same thing for the `rect` function below
    Circle x y r


rect shape x y w h =
    Rectangle x y w h

这是我现在可以解析多边形的工作解码器:

module Main exposing (main)

import Html exposing (Html, text)
import Json.Decode exposing (decodeString, string, list, at)
import Json.Decode.Pipeline exposing (decode, required, optional)

jsonString =
"{\"shapes\":[\n{\n\"shape\": \"circle\",\n \"x\": \"50\",\n \"y\": \"50\",\n \"r\": \"40\"\n},\n{\n\"shape\": \"rect\",\n \"x\": \"100\",\n \"y\": \"100\",\n \"width\": \"50\",\n \"height\": \"60\"\n},\n{\n\"shape\": \"polygon\",\n\"points\":[\n{\n\"x\": \"80\",\n\"y\": \"80\"\n}\n]}\n]}"

main : Html msg
main =
    text <| toString <| decodeString decoder jsonString


type Shape
    = Circle String String String
    | Rectangle String String String String
    | Polygon (List ( ( String, String ) ))


decoder = 
    at ["shapes"] (list shapeDecoder)

shapeDecoder = 
    decode toShape
        |> required "shape" string
        |> optional "x" string ""
        |> optional "y" string ""
        |> optional "r" string ""
        |> optional "width" string ""
        |> optional "height" string ""
        |> optional "points" (list pointDecoder) []

pointDecoder = 
    decode toPoint
        |> required "x" string
        |> required "y" string

toShape shape x y r width height points = 
    case shape of
        "circle" ->
            Circle x y r

        "rect" ->
            Rectangle x y width height

        "polygon" -> 
            Polygon points

        _ -> 
            Circle "" "" ""

toPoint x y = 
    (x, y)

Json 看起来像这样:

{ "shapes":[
{
    "shape": "circle",
    "x": "50",
    "y": "50",
    "r": "40"
},
{
    "shape": "circle",
    "x": "300",
    "y": "50",
    "r": "40"
},
{
    "shape": "rect",
    "x": "100",
    "y": "100",
    "width": "50",
    "height": "60"
},
{
"shape": "polygon",
"points":
  [ { "x":"200", "y":"150"}
    , { "x":"250", "y":"400"}
    , { "x":"120", "y":"340"}
    , { "x":"160", "y":"250"}
    , { "x":"180", "y":"170"}
  ]
}
]
}

您可以在这里尝试:Elli-App