在 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
我想像这样解析 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