Following on from a previous post, I've found I'm totally stuck. I'm trying to parse a JSON structure into my own type, and not only am I stuck on how to parse the Array, I'm not even sure if I'm using the Aeson library as intended. Any help would be greatly appreciated.
The code:
data Exif = Exif [(T.Text, ExifValue)] deriving (Show)
data ExifValue =
ExifText T.Text |
ExifInt Integer |
ExifDouble Double |
ExifBool Bool |
ExifArray [ExifValue]
deriving (Show)
instance FromJSON ExifValue where
parseJSON (Number (I n)) = return $ ExifInt n
parseJSON (Number (D n)) = return $ ExifDouble n
parseJSON (String s) = return $ ExifText s
parseJSON (Bool b) = return $ ExifBool b
-- parseJSON (Array a) = ?????
instance FromJSON Exif where
parseJSON (Object o) = do
x <- sequence $ map f (M.assocs o)
return $ Exif x
where
f (t, x) = do
y <- parseJSON x
return ((t, y) :: (T.Text, ExifValue))
parseExifFile = fmap parseExifData . B.readFile
parseExifData :: B.ByteString -> Data.Attoparsec.Result (Data.Aeson.Result [Exif])
parseExifData content = parse (fmap fromJSON json) content
The test file:
[{
"SourceFile": "test.jpg",
"ExifTool:ExifToolVersion": 8.61,
"File:FileName": "test.jpg",
"File:FileSize": 2174179,
"File:FileModifyDate": "2011:07:27 16:53:49-07:00",
"File:FilePermissions": 644,
"File:FileType": "JPEG",
"File:MIMEType": "image/jpeg",
"File:ExifByteOrder": "MM",
"File:CurrentIPTCDigest": "32d6a77098a73aa816f2570c9472735a",
"File:ImageWidth": 2592,
"File:ImageHeight": 1936,
"File:EncodingProcess": 0,
"File:BitsPerSample": 8,
"File:ColorComponents": 3,
"File:YCbCrSubSampling": "2 2",
"XMP:Subject": ["alpha","beta","gamma"]
}]
You have to follow the type of
parseJSON
a little bit down a rabbit trail, but once you recognize what(Array a)
represents, it should be straightforward.parseJSON
has typeValue -> Parser a
, so(Array a)
has typeValue
. One of the variants in theValue
type isArray Array
, so thea
in(Array a)
must be of the typeArray
, which is defined asVector Value
. TheValue
s inside thatVector
are what you want to callparseJSON
on to return your list, so check out what you can do with aVector
.The easiest approach would probably to convert
a
to a list withVector.toList
, and then usemapM
to parse theValues
.Alternately, you could avoid the
Vector
to list conversion by changing yourExifArray
variant to holdVector ExifValue
, and then usingVector.mapM
.A slightly newer build of the aeson library (0.3.2.12) supports autogenerating JSON instances.
Produces:
I'm not native english speaker, so i may not understand you very well. I guess you want to know how to parse json into recursive data type like
ExifValue
you presented. So i made a simple example to show how to parse json into recursive data type.