Elm 以不同的格式解码 json
Elm decode json in different format
我尝试在 elm 中解码一些 json。
我收到的物体可能有两种不同的形状。
第一种情况:
{
...
"ChipId": "NotSet"
...
}
第二种情况:
{
...
"ChipId": {
"Item": "0000000000"
},
...
}
所以第一个可以很容易地用 field "ChipId" string
解码,但如果它是复杂的对象,它就会失败。
我已经用 Decode.andThen
试过了,但我无法解决它。
感谢您的帮助!
更新 1 - 失败的解码器
我尝试的方法是使用 Maybe
.
chipIdDecoder : Decoder String
chipIdDecoder =
let
chipIdIdDecoder : Decoder String
chipIdIdDecoder =
field "ChipId" (field "Fields" (firstElementDecoder string))
chooseChipId : Maybe String -> Decoder String
chooseChipId c =
case c of
Just id ->
case id of
"ChipId" ->
chipIdIdDecoder
_ ->
succeed ""
Nothing ->
fail "Chip Id is invalid"
in
nullable (field "ChipId" string)
|> andThen chooseChipId
我想这里的问题是 Maybe
期望某些东西或 null
而不是某些东西或其他东西。 ^^
tl;dr: 使用 oneOf
在 Elm 中编写 json 解码器的一个好方法是从最小的部分开始,编写独立解码每个部分的解码器,然后向上移动到下一个级别并为此编写解码器将您已经制作的较小的部分放在一起。
这里,例如,我会首先编写一个解码器来分别处理 "ChipId"
的两种可能形式。第一个只是一个字符串,它当然是用 elm/json
开箱即用的,所以这很简单。另一个是具有单个字段的对象,我们将其解码为简单的 String
:
chipIdObjectDecoder : Decoder String
chipIdObjectDecoder =
field "Item" string
然后我们需要将它们放在一起,这似乎是您最费力的部分。这里 oneOf
函数来拯救我们,它的描述是:
Try a bunch of different decoders. This can be useful if the JSON may come in a couple different formats.
听起来正是我们需要的!要同时尝试 string
解码器和我们的 chipIdObjectDecoder
我们可以这样写:
eitherStringOrChipIdObject : Decoder String
eitherStringOrChipIdObject =
oneOf [ string, chipIdObjectDecoder ]
最后我们需要解码 "ChipId"
字段本身:
field "ChipId" eitherStringOrChipIdObject
所有这些都放在一个函数中:
chipIdDecoder : Decoder String
chipIdDecoder =
let
chipIdObjectDecoder : Decoder String
chipIdObjectDecoder =
field "Item" string
eitherStringOrChipIdObject : Decoder String
eitherStringOrChipIdObject =
oneOf [ string, chipIdObjectDecoder ]
in
field "ChipId" eitherStringOrChipIdObject
或者稍微简化一下,因为上面的内容相当冗长:
chipIdDecoder : Decoder String
chipIdDecoder =
let
chipIdObjectDecoder =
field "Item" string
in
field "ChipId" (oneOf [ string, chipIdObjectDecoder ])
最后一点,因为不清楚您的代码是否过于简化。如果无法将 "ChipId"
对象简化为简单的字符串,则必须使用可以同时包含 String
和 ChipIdObject
以及 map
的通用类型将值解码为该通用类型。 eitherStringOrChipIdObject
可能是这样的:
type alias ChipIdObject = { ... }
type ChipId
= ChipIdString String
| ChipIdObject ChipIdObject
eitherStringOrChipIdObject : Decoder ChipId
eitherStringOrChipIdObject =
oneOf
[ string |> map ChipIdString
, chipIdObjectDecoder |> map ChipIdObject
]
我尝试在 elm 中解码一些 json。
我收到的物体可能有两种不同的形状。
第一种情况:
{
...
"ChipId": "NotSet"
...
}
第二种情况:
{
...
"ChipId": {
"Item": "0000000000"
},
...
}
所以第一个可以很容易地用 field "ChipId" string
解码,但如果它是复杂的对象,它就会失败。
我已经用 Decode.andThen
试过了,但我无法解决它。
感谢您的帮助!
更新 1 - 失败的解码器
我尝试的方法是使用 Maybe
.
chipIdDecoder : Decoder String
chipIdDecoder =
let
chipIdIdDecoder : Decoder String
chipIdIdDecoder =
field "ChipId" (field "Fields" (firstElementDecoder string))
chooseChipId : Maybe String -> Decoder String
chooseChipId c =
case c of
Just id ->
case id of
"ChipId" ->
chipIdIdDecoder
_ ->
succeed ""
Nothing ->
fail "Chip Id is invalid"
in
nullable (field "ChipId" string)
|> andThen chooseChipId
我想这里的问题是 Maybe
期望某些东西或 null
而不是某些东西或其他东西。 ^^
tl;dr: 使用 oneOf
在 Elm 中编写 json 解码器的一个好方法是从最小的部分开始,编写独立解码每个部分的解码器,然后向上移动到下一个级别并为此编写解码器将您已经制作的较小的部分放在一起。
这里,例如,我会首先编写一个解码器来分别处理 "ChipId"
的两种可能形式。第一个只是一个字符串,它当然是用 elm/json
开箱即用的,所以这很简单。另一个是具有单个字段的对象,我们将其解码为简单的 String
:
chipIdObjectDecoder : Decoder String
chipIdObjectDecoder =
field "Item" string
然后我们需要将它们放在一起,这似乎是您最费力的部分。这里 oneOf
函数来拯救我们,它的描述是:
Try a bunch of different decoders. This can be useful if the JSON may come in a couple different formats.
听起来正是我们需要的!要同时尝试 string
解码器和我们的 chipIdObjectDecoder
我们可以这样写:
eitherStringOrChipIdObject : Decoder String
eitherStringOrChipIdObject =
oneOf [ string, chipIdObjectDecoder ]
最后我们需要解码 "ChipId"
字段本身:
field "ChipId" eitherStringOrChipIdObject
所有这些都放在一个函数中:
chipIdDecoder : Decoder String
chipIdDecoder =
let
chipIdObjectDecoder : Decoder String
chipIdObjectDecoder =
field "Item" string
eitherStringOrChipIdObject : Decoder String
eitherStringOrChipIdObject =
oneOf [ string, chipIdObjectDecoder ]
in
field "ChipId" eitherStringOrChipIdObject
或者稍微简化一下,因为上面的内容相当冗长:
chipIdDecoder : Decoder String
chipIdDecoder =
let
chipIdObjectDecoder =
field "Item" string
in
field "ChipId" (oneOf [ string, chipIdObjectDecoder ])
最后一点,因为不清楚您的代码是否过于简化。如果无法将 "ChipId"
对象简化为简单的字符串,则必须使用可以同时包含 String
和 ChipIdObject
以及 map
的通用类型将值解码为该通用类型。 eitherStringOrChipIdObject
可能是这样的:
type alias ChipIdObject = { ... }
type ChipId
= ChipIdString String
| ChipIdObject ChipIdObject
eitherStringOrChipIdObject : Decoder ChipId
eitherStringOrChipIdObject =
oneOf
[ string |> map ChipIdString
, chipIdObjectDecoder |> map ChipIdObject
]