Let's say there is a JSON like:
{
"bob_id" : {
"name": "bob",
"age" : 20
},
"jack_id" : {
"name": "jack",
"age" : 25
}
}
Is it possible to parse it to [Person]
with Person
defined like below?
data Person = Person {
id :: Text
,name :: Text
,age :: Int
}
mniip's answer converts the JSON
Object
to aMap
, which leads to a result list sorted by ID. If you don't need the results sorted in that fashion, it's probably better to use a more direct approach to speed things up. In particular, anObject
is really just aHashMap Text Value
, so we can useHashMap
operations to work with it.Note that I renamed the
id
field toident
, because most Haskell programmers will assume thatid
refers to the identity function inPrelude
or to the more general identity arrow inControl.Category
.Note that, like Alexander VoidEx Ruchkin's answer, this sequences the conversion from
PersonInfo
toPerson
explicitly within theParser
monad. It would therefore be easy to modify it to produce a parse error if thePerson
fails some sort of high-level validation. Alexander's answer also demonstrates the utility of thewithObject
combinator, which I'd have used if I'd known it existed.You cannot define an instance for
[Person]
literally, because aeson already includes an instance for[a]
, however you can create a newtype, and provide an instance for that.Aeson also includes the instance
FromJSON a => FromJSON (Map Text a)
, which means if aeson knows how to parse something, it knows how to parse a dict of that something.You can define a temporary datatype resembling a value in the dict, then use the Map instance to define
FromJSON PersonList
, wherenewtype PersonList = PersonList [Person]
:If you enable
FlexibleInstances
, you can make instance for[Person]
. You can parse your object toMap Text Value
and then parse each element in map: