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
parseJSONa little bit down a rabbit trail, but once you recognize what(Array a)represents, it should be straightforward.parseJSONhas typeValue -> Parser a, so(Array a)has typeValue. One of the variants in theValuetype isArray Array, so theain(Array a)must be of the typeArray, which is defined asVector Value. TheValues inside thatVectorare what you want to callparseJSONon to return your list, so check out what you can do with aVector.The easiest approach would probably to convert
ato a list withVector.toList, and then usemapMto parse theValues.Alternately, you could avoid the
Vectorto list conversion by changing yourExifArrayvariant to holdVector ExifValue, and then usingVector.mapM.