Let’s say I have the following JSON values.
{
"fieldName1": 5,
"value1": "Hello"
}
and
{
"fieldName2": 7,
"value1": "Welcome"
}
I have the following type in Haskell.
data Greeting
= Greeting
{
count :: Int,
name :: Text
}
deriving (Generic, Show, Eq)
How do I parse this JSON into Haskell where fieldName1
or fieldName2
values should be parsed as count
value?
I tried to solve this by doing something like shown below.
instance FromJSON Greeting where
parseJSON = withObject "Greeting" $ obj -> do
count1 <- obj .:? "fieldName1"
count2 <- obj .:? "fieldName2"
name <- obj .: "value1"
count <-
case (count1, count2) of
(Just count, Nothing) -> return count
(Nothing, Just count) -> return count
_ -> fail $ Text.unpack "Field missing"
return Greeting {count = count, name = name}
It works but is very cumbersome and if there are more than 2 alternative values, it becomes a lot more complex. Is there any way to solve this in a simpler way?
2
Answers
A slightly better variant:
Essentially,
c1 <|> ... <|> cn
is the firstJust
if there is one, andNothing
otherwise.You can also use
case of
instead ofmaybe
, if you prefer. If this is frequently used, I’d putmaybe (fail $ ...) return
in a separate definition, so to give it a nice name.The
Parser
monad whereparseJSON
runs is itself anAlternative
, so you can use the alternation(<|>)
operator within the parser definition:If multiple "count" fields are present, this will take the first one that parses.