json – Haskell Aeson:如何将Value转换为自定义类型?

找不到一个好例子.感谢任何帮助. JSON如下:
[{
  "EXIF:Make": "Canon","EXIF:Model": "Canon PowerShot S95","EXIF:Orientation": "Horizontal (normal)","EXIF:XResolution": 180,"EXIF:YResolution": 180,"EXIF:ResolutionUnit": "inches"
}]

我使用的代码如下:

import Data.Aeson
import Data.Attoparsec
import Data.ByteString
x <- fmap (parse json) (Data.ByteString.readFile "json.txt")

我该如何定义&使用FromJSON类型从x转换为:

data Exif = Exif [[(String,String)]]

或类似的数据结构?注意[[]] – 我希望JSON有多个顶级条目.

解决方法

这是一个惯用的解决方案:
{-# LANGUAGE OverloadedStrings #-}

module Main
       where

import Control.applicative
import Control.Monad
import Data.Aeson
import Data.Attoparsec

import qualified Data.ByteString as B
import qualified Data.Text as T

data ExifEntry = ExifEntry { exifMake :: T.Text,exifModel :: T.Text,exifOrientation :: T.Text,exifXResolution :: Int,exifYResolution :: Int,exifResolutionUnit :: T.Text
                           } deriving (Eq,Show)


instance FromJSON ExifEntry
  where
    parseJSON (Object v) = ExifEntry <$> 
                           v .: "EXIF:Make" <*>
                           v .: "EXIF:Model" <*>
                           v .: "EXIF:Orientation" <*>
                           v .: "EXIF:XResolution" <*>
                           v .: "EXIF:YResolution" <*>
                           v .: "EXIF:ResolutionUnit"
    parseJSON _          = mzero


parseAll :: B.ByteString -> [ExifEntry]
parseAll s = case (parse (fromJSON <$> json) s) of
  Done _ (Error err)  -> error err
  Done ss (Success e) -> e:(parseAll ss)
  _                   -> []

main :: IO ()
main = do s <- B.readFile "json.txt"
          let p = parseAll s
          print p

测试:

$cat json.txt 
{
  "EXIF:Make": "Canon","EXIF:ResolutionUnit": "inches"
}

{
  "EXIF:Make": "Canon","EXIF:Model": "Canon PowerShot S995","EXIF:ResolutionUnit": "inches"
}
$./dist/build/test/test
[ExifEntry {exifMake = "Canon",exifModel = "Canon PowerShot S95",exifOrientation = "Horizontal (normal)",exifXResolution = 180,exifYResolution = 180,exifResolutionUnit = "inches"},ExifEntry {exifMake = "Canon",exifModel = "Canon PowerShot S995",exifResolutionUnit = "inches"}]

或者,这是一个slightly more ugly solution,它为您提供所请求的数据类型([[(Text,Text)]]).

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...