Discussion:
[elm-discuss] [JSON Decoder Pipeline] Decoding a model attribute from either one of two JSON fields
Mehdi Elaoufir
2017-06-14 12:42:06 UTC
Permalink
Hi,

I have the following json that i want to Decode :

{
...
"otherAttr" : 123,
"city1" : "",
"city2" : "Cupertino",
"yetAnotherAttr" : 123,
...
}

Here's my target model :


type alias User =
{...
, otherAttr : Int,
, city : String
, yetAnotherAttr : Int,
...
}



I want city to be decoded from city1 if present and fallback to city2, do
you have any clue?

So far i've tried using Decoder.oneOf then Decoder.at without success


userDecoder : Decoder User
userDecoder =
decode user
|> ...
|> required "otherAttr" int
|> cityDecoder
|> required "yetAnotherAttr" int
|> ...

cityDecoder : Decoder String
cityDecoder =
Decode.at [ "city1", "city2" ] Decode.string -- Not working !!




Any help appreciated!

Cheers,
Mehdi
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Matthew Cheely
2017-06-14 14:53:50 UTC
Permalink
It sounds like you were on the right track with using Decode.oneOf to
create a cityDecoder. It's hard to tell from the samples above, but one
issue you might have run into is that for Decode.oneOf to fall back to the
second decoder, the first decoder must fail. In your sample data, "city1"
is an empty string, which the default string decoder will happily decode to
an empty string. So you'd also need a string decoder that rejected empty
strings. Something like this, perhaps:


userDecoder : Decoder User
userDecoder =
decode User
|> required "otherAttr" int
|> custom cityDecoder
|> required "yetAnotherAttr" int


cityDecoder : Decoder String
cityDecoder =
Decode.oneOf
[ Decode.field "city1" notEmptyStr
, Decode.field "city2" notEmptyStr
]


notEmptyStr : Decoder String
notEmptyStr =
Decode.string
|> Decode.andThen
(\str ->
if String.isEmpty str then
Decode.fail "string length 0"
else
Decode.succeed str
)

Fiddle with it here: https://ellie-app.com/3ttLP8cPmfLa1/1


Also worth noting is that

Decode.at [ "city1", "city2" ] ...

would be for decoding a structure like:

{
"city1": {
"city2": "value"
}
}
Hi,
{
Enter code here...
...
"otherAttr" : 123,
"city1" : "",
"city2" : "Cupertino",
"yetAnotherAttr" : 123,
...
}
type alias User =
{...
, otherAttr : Int,
, city : String
, yetAnotherAttr : Int,
...
}
I want city to be decoded from city1 if present and fallback to city2, do
you have any clue?
So far i've tried using Decoder.oneOf then Decoder.at without success
userDecoder : Decoder User
userDecoder =
decode user
|> ...
|> required "otherAttr" int
|> cityDecoder
|> required "yetAnotherAttr" int
|> ...
cityDecoder : Decoder String
cityDecoder =
Decode.at [ "city1", "city2" ] Decode.string -- Not working !!
Any help appreciated!
Cheers,
Mehdi
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Mehdi Elaoufir
2017-06-14 16:58:07 UTC
Permalink
It works like a charm, overwhelming!

Thanks a lot, really !
Post by Mehdi Elaoufir
Hi,
{
...
"otherAttr" : 123,
"city1" : "",
"city2" : "Cupertino",
"yetAnotherAttr" : 123,
...
}
type alias User =
{...
, otherAttr : Int,
, city : String
, yetAnotherAttr : Int,
...
}
I want city to be decoded from city1 if present and fallback to city2, do
you have any clue?
So far i've tried using Decoder.oneOf then Decoder.at without success
userDecoder : Decoder User
userDecoder =
decode user
|> ...
|> required "otherAttr" int
|> cityDecoder
|> required "yetAnotherAttr" int
|> ...
cityDecoder : Decoder String
cityDecoder =
Decode.at [ "city1", "city2" ] Decode.string -- Not working !!
Any help appreciated!
Cheers,
Mehdi
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...