Reputation: 5098
I would like to parse the following JSON using Aeson in Haskell:
{
"foo": {
"name": "name 1",
"location": "location 1"
},
"bar": {
"name": "name 2",
"location": "location 2"
}
}
The keys name
and location
are known, but foo
and bar
are unknown.
I would like to load the JSON data as a list of the following data type ([Entry]
):
data Entry = Entry
{ id :: String -- "foo" or "bar" etc.
, name :: String -- "name 1" or "name 2" etc.
, location :: String -- "location 1" or "location 2" etc.
} deriving Show
My first try looks as follows (it does not work, yet):
instance FromJSON Entry where
parseJSON (Object o) = do
map (\(id, (name, location)) -> Entry id name location) o
parseJSON o
How would I parse the JSON correctly?
Upvotes: 3
Views: 895
Reputation: 19637
This should work:
{-# LANGUAGE FlexibleInstances, OverloadedStrings #-}
import Data.Aeson
import Data.Aeson.Types
import Data.HashMap.Strict
data Entry = Entry
{ id :: String
, name :: String
, location :: String
}
deriving Show
instance FromJSON [Entry] where
parseJSON x =
parseJSON x >>= mapM parseEntry . toList
parseEntry :: (String, Value) -> Parser Entry
parseEntry (i, v) =
withObject "entry body" (\ o ->
Entry i <$> o .: "name" <*> o .: "location")
v
Considering the way you want to parse entries, you cannot really parse single entries, only several at once, because you need the outer object structure.
The JSON parser for [Entry]
then proceeds by first parsing the outer
object as a hashmap and turning that into a list of pairs using toList
,
then processing each resulting (String, Value)
pair with parseEntry
.
Upvotes: 6