Elm JSON 非字符串 JSON 数组的解码器
Elm JSON Decoder for non-string JSON Array
我正在学习 Elm,并且 运行 已经用 JSON 个解码器撞墙了。我正在构建一个 Elm 前端,我想从后端 API 提供 URLs,其中 returns 以下 JSON 数组 URL 字符串:
["http://www.example.com?param=value","http://www.example2.com?param=value"]
如果我尝试在 Elm 中使用 List String 解码器解析它,它会失败,因为上面没有作为字符串引用或转义。我的示例解码器:
stringListDecoder : Json.Decode.Decoder (List String)
stringListDecoder = Json.Decode.list Json.Decode.string
myArrDec2 = D.list D.string
D.decodeString myArrDec2 ["http://www.example.com?param=value","http://www.example2.com?param=value"]
这会失败,因为 JSON 数组在 Elm 中被视为字符串列表,而不是 Json.Decode.decodeString 函数接受的扁平字符串。如果我要引用和转义数组以使用此解码器,它将采用以下格式:
"[\"http://www.example.com?param=value\",\"http://www.example2.com?param=value\"]"
我如何编写一个 Elm 解码器来解析 unquote/unescaped JSON 数组,格式为我的 API?
更新
我想我没有很好地表达我的问题;为此,我深表歉意。 API 返回此值(有效 JSON):
["http://www.example.com?param=value","http://www.example2.com?param=value"]
我正在用 Http.get 抓取这个 JSON 并尝试 运行 结果的解码器,但失败了,因为它不是字符串。
-- HTTP
getUrls : Cmd Msg
getUrls =
Http.get
{ url = "http://127.0.0.1:3000/request" -- This is the endpoint returning ["http://www.example.com?param=value","http://www.example2.com?param=value"]
, expect = Http.expectJson GotUrls urlDecoder
}
urlDecoder : Decoder (List String)
urlDecoder =
Json.Decode.list Json.Decode.string
由于 Elm 无法接受这个 JSON 而不将其转义为字符串,我可以使用 Http.get 调用将其转换为一个,然后再使用我的解码器进行解析吗?还是由于我对 Elm 缺乏经验而遗漏了一些明显的东西?如果我可以进一步澄清,请告诉我,感谢您的帮助!
最终编辑
在使用了 Robert 的优秀示例后,结果证明我自己的示例由于不相关的问题而失败。作为 Elm 的 HTTP 包的新手,我不知道 Robert 的 Http 错误函数处理的 Http.NetworkError 消息。这导致我 并最终在 API.
中揭示了 CORS 配置错误
Bare JSON 不能存在于 Elm 模块中。在 Elm 中编写要解码的示例 JSON 时,必须将其包装在其他表示形式中。
但是,该表示是特定于 Elm 的;它是 而不是 解码器期望从 API.
当后端发送文字 JSON ["a","b"]
.
时,您的解码器应该可以正常工作
在代码中:
module Example exposing (..)
import Json.Decode as JD
stringListDecoder : JD.Decoder (List String)
stringListDecoder =
JD.list JD.string
{-| Bare JSON cannot exist inside Elm syntax; it must be wrapped in something
else. In this case, in a string.
-}
jsonFromApi : String
jsonFromApi =
"[ \"http://www.example.com?param=value\", \"http://www.example2.com?param=value\" ]"
decoded : Result JD.Error (List String)
decoded =
JD.decodeString stringListDecoder jsonFromApi
expectedResult : Result JD.Error (List String)
expectedResult =
Result.Ok [ "http://www.example.com?param=value", "http://www.example2.com?param=value" ]
decodesAsExpected : Bool
decodesAsExpected =
decoded == expectedResult
编辑:Here's an example 适合 运行 和 elm reactor
:
src/request.json
["http://www.example.com?param=value","http://www.example2.com?param=value"]
src/Main.elm
module Main exposing (..)
import Browser
import Html exposing (Html, code, div, p, pre, span, text)
import Http
import Json.Decode as JD
type alias Model =
{ data : RemoteData Http.Error (List String) }
type RemoteData err a
= NotAsked
| Loading
| Loaded a
| Failed err
type Msg
= GotUrls (Result Http.Error (List String))
initialModel =
{ data = NotAsked }
getUrls : Cmd Msg
getUrls =
Http.get
{ url = "/src/request.json"
-- This is the endpoint returning ["http://www.example.com?param=value","http://www.example2.com?param=value"]
, expect = Http.expectJson GotUrls urlDecoder
}
urlDecoder : JD.Decoder (List String)
urlDecoder =
JD.list JD.string
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotUrls result ->
case result of
Ok strings ->
( { model | data = Loaded strings }, Cmd.none )
Err error ->
( { model | data = Failed error }, Cmd.none )
view : Model -> Html Msg
view model =
div []
(case model.data of
NotAsked ->
[ text "no data yet" ]
Loading ->
[ text "loading" ]
Failed err ->
[ text "Failed... ", show err ]
Loaded strings ->
strings |> List.map (\s -> p [] [ text s ])
)
show : Http.Error -> Html Msg
show error =
case error of
Http.BadUrl string ->
span [] [ text "Bad Url: ", text string ]
Http.Timeout ->
text "Timeout"
Http.NetworkError ->
text "Network error"
Http.BadStatus int ->
span [] [ text "Bad Status: ", int |> String.fromInt |> text ]
Http.BadBody string ->
span [] [ text "Bad Body: ", pre [] [ code [] [ text string ] ] ]
main : Program () Model Msg
main =
Browser.element
{ init = always ( initialModel, getUrls )
, view = view
, update = update
, subscriptions = always Sub.none
}
我正在学习 Elm,并且 运行 已经用 JSON 个解码器撞墙了。我正在构建一个 Elm 前端,我想从后端 API 提供 URLs,其中 returns 以下 JSON 数组 URL 字符串:
["http://www.example.com?param=value","http://www.example2.com?param=value"]
如果我尝试在 Elm 中使用 List String 解码器解析它,它会失败,因为上面没有作为字符串引用或转义。我的示例解码器:
stringListDecoder : Json.Decode.Decoder (List String)
stringListDecoder = Json.Decode.list Json.Decode.string
myArrDec2 = D.list D.string
D.decodeString myArrDec2 ["http://www.example.com?param=value","http://www.example2.com?param=value"]
这会失败,因为 JSON 数组在 Elm 中被视为字符串列表,而不是 Json.Decode.decodeString 函数接受的扁平字符串。如果我要引用和转义数组以使用此解码器,它将采用以下格式:
"[\"http://www.example.com?param=value\",\"http://www.example2.com?param=value\"]"
我如何编写一个 Elm 解码器来解析 unquote/unescaped JSON 数组,格式为我的 API?
更新 我想我没有很好地表达我的问题;为此,我深表歉意。 API 返回此值(有效 JSON):
["http://www.example.com?param=value","http://www.example2.com?param=value"]
我正在用 Http.get 抓取这个 JSON 并尝试 运行 结果的解码器,但失败了,因为它不是字符串。
-- HTTP
getUrls : Cmd Msg
getUrls =
Http.get
{ url = "http://127.0.0.1:3000/request" -- This is the endpoint returning ["http://www.example.com?param=value","http://www.example2.com?param=value"]
, expect = Http.expectJson GotUrls urlDecoder
}
urlDecoder : Decoder (List String)
urlDecoder =
Json.Decode.list Json.Decode.string
由于 Elm 无法接受这个 JSON 而不将其转义为字符串,我可以使用 Http.get 调用将其转换为一个,然后再使用我的解码器进行解析吗?还是由于我对 Elm 缺乏经验而遗漏了一些明显的东西?如果我可以进一步澄清,请告诉我,感谢您的帮助!
最终编辑
在使用了 Robert 的优秀示例后,结果证明我自己的示例由于不相关的问题而失败。作为 Elm 的 HTTP 包的新手,我不知道 Robert 的 Http 错误函数处理的 Http.NetworkError 消息。这导致我
Bare JSON 不能存在于 Elm 模块中。在 Elm 中编写要解码的示例 JSON 时,必须将其包装在其他表示形式中。
但是,该表示是特定于 Elm 的;它是 而不是 解码器期望从 API.
当后端发送文字 JSON ["a","b"]
.
在代码中:
module Example exposing (..)
import Json.Decode as JD
stringListDecoder : JD.Decoder (List String)
stringListDecoder =
JD.list JD.string
{-| Bare JSON cannot exist inside Elm syntax; it must be wrapped in something
else. In this case, in a string.
-}
jsonFromApi : String
jsonFromApi =
"[ \"http://www.example.com?param=value\", \"http://www.example2.com?param=value\" ]"
decoded : Result JD.Error (List String)
decoded =
JD.decodeString stringListDecoder jsonFromApi
expectedResult : Result JD.Error (List String)
expectedResult =
Result.Ok [ "http://www.example.com?param=value", "http://www.example2.com?param=value" ]
decodesAsExpected : Bool
decodesAsExpected =
decoded == expectedResult
编辑:Here's an example 适合 运行 和 elm reactor
:
src/request.json
["http://www.example.com?param=value","http://www.example2.com?param=value"]
src/Main.elm
module Main exposing (..)
import Browser
import Html exposing (Html, code, div, p, pre, span, text)
import Http
import Json.Decode as JD
type alias Model =
{ data : RemoteData Http.Error (List String) }
type RemoteData err a
= NotAsked
| Loading
| Loaded a
| Failed err
type Msg
= GotUrls (Result Http.Error (List String))
initialModel =
{ data = NotAsked }
getUrls : Cmd Msg
getUrls =
Http.get
{ url = "/src/request.json"
-- This is the endpoint returning ["http://www.example.com?param=value","http://www.example2.com?param=value"]
, expect = Http.expectJson GotUrls urlDecoder
}
urlDecoder : JD.Decoder (List String)
urlDecoder =
JD.list JD.string
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotUrls result ->
case result of
Ok strings ->
( { model | data = Loaded strings }, Cmd.none )
Err error ->
( { model | data = Failed error }, Cmd.none )
view : Model -> Html Msg
view model =
div []
(case model.data of
NotAsked ->
[ text "no data yet" ]
Loading ->
[ text "loading" ]
Failed err ->
[ text "Failed... ", show err ]
Loaded strings ->
strings |> List.map (\s -> p [] [ text s ])
)
show : Http.Error -> Html Msg
show error =
case error of
Http.BadUrl string ->
span [] [ text "Bad Url: ", text string ]
Http.Timeout ->
text "Timeout"
Http.NetworkError ->
text "Network error"
Http.BadStatus int ->
span [] [ text "Bad Status: ", int |> String.fromInt |> text ]
Http.BadBody string ->
span [] [ text "Bad Body: ", pre [] [ code [] [ text string ] ] ]
main : Program () Model Msg
main =
Browser.element
{ init = always ( initialModel, getUrls )
, view = view
, update = update
, subscriptions = always Sub.none
}