【问题标题】:Haskell, Aeson & JSON parsing into custom typeHaskell、Aeson 和 JSON 解析成自定义类型
【发布时间】:2012-11-05 02:09:03
【问题描述】:

previous post 开始,我发现我完全陷入了困境。我正在尝试将 JSON 结构解析为我自己的类型,不仅我坚持如何解析数组,我什至不确定我是否按预期使用 Aeson 库。任何帮助将不胜感激。

代码:

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

测试文件:

[{
  "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"]
}]

【问题讨论】:

    标签: json haskell aeson


    【解决方案1】:

    您必须遵循parseJSON 的类型,稍微走下兔子路线,但是一旦您认识到(Array a) 代表什么,它应该很简单。

    parseJSON 的类型为 Value -&gt; Parser a,因此 (Array a) 的类型为 ValueValue 类型中的变体之一是Array Array,因此(Array a) 中的a 必须是Array 类型,即定义为Vector ValueValues 里面的 Vector 是你想要调用 parseJSON 来返回你的列表,所以看看你可以用 Vector 做什么。

    最简单的方法可能是将a 转换为带有Vector.toList 的列表,然后使用mapM 解析Values

    或者,您可以通过将ExifArray 变体更改为保留Vector ExifValue,然后使用Vector.mapM 来避免Vector 到列表转换。

    【讨论】:

      【解决方案2】:

      我的母语不是英语,所以我可能不太了解你。我想您想知道如何将 json 解析为递归数据类型,例如您提供的 ExifValue。 所以我做了一个简单的例子来展示如何将json解析为递归数据类型。

      {-# LANGUAGE OverloadedStrings #-}
      import qualified Data.ByteString as B
      import Data.Maybe
      import Control.Monad
      import Control.Applicative
      import Data.Attoparsec
      import Data.Attoparsec.Number
      import Data.Aeson
      import qualified Data.Vector as V
      
      data Data = D1 Int | D2 [Data]
          deriving (Show)
      
      instance FromJSON Data where
          parseJSON (Number (I n)) = return $ D1 $ fromInteger n
          parseJSON (Array a)    = D2 <$> mapM parseJSON (V.toList a)
      
      main = do
          let v = fromJust $ maybeResult $ parse json "[1,2,3,[5,3,[6,3,5]]]"
          let v1 :: Data
              v1 = case fromJSON v of
                       Success a -> a
                       Error s   -> error s
          print v1
      

      【讨论】:

        【解决方案3】:

        aeson library (0.3.2.12) 的稍新版本支持自动生成 JSON 实例。

        {-# LANGUAGE TemplateHaskell #-}
        
        import Data.Aeson
        import Data.Aeson.TH (deriveJSON)
        import Data.Attoparsec
        import qualified Data.ByteString as B
        import qualified Data.Text as T
        
        data Exif = Exif [(T.Text, ExifValue)] deriving (Show)
        data ExifValue = 
            ExifText T.Text | 
            ExifInt Integer | 
            ExifDouble Double | 
            ExifBool Bool | 
            ExifArray [ExifValue] 
            deriving (Show)
        
        deriveJSON id ''Exif
        deriveJSON id ''ExifValue
        
        parseExifFile = fmap parseExifData . B.readFile
        
        parseExifData :: B.ByteString -> Data.Attoparsec.Result (Data.Aeson.Result [Exif])
        parseExifData content = parse (fmap fromJSON json) content
        

        生产:

        instance ToJSON Exif where
          { toJSON
              = \ value_a1Va
                  -> case value_a1Va of { Exif arg1_a1Vb -> toJSON arg1_a1Vb } }
        instance FromJSON Exif where
          { parseJSON
              = \ value_a1Vc
                  -> case value_a1Vc of {
                       arg_a1Vd -> (Exif Data.Functor.<$> parseJSON arg_a1Vd) } }
        
        instance ToJSON ExifValue where
          { toJSON
              = \ value_a1Wd
                  -> case value_a1Wd of {
                       ExifText arg1_a1We
                         -> object [(T.pack "ExifText" .= toJSON arg1_a1We)]
                       ExifInt arg1_a1Wf
                         -> object [(T.pack "ExifInt" .= toJSON arg1_a1Wf)]
                       ExifDouble arg1_a1Wg
                         -> object [(T.pack "ExifDouble" .= toJSON arg1_a1Wg)]
                       ExifBool arg1_a1Wh
                         -> object [(T.pack "ExifBool" .= toJSON arg1_a1Wh)]
                       ExifArray arg1_a1Wi
                         -> object [(T.pack "ExifArray" .= toJSON arg1_a1Wi)] } }
        instance FromJSON ExifValue where
          { parseJSON
              = \ value_a1Wj
                  -> case value_a1Wj of {
                       Object obj_a1Wk
                         -> case Data.Map.toList obj_a1Wk of {
                              [(conKey_a1Wl, conVal_a1Wm)]
                                -> case conKey_a1Wl of {
                                     _ | (conKey_a1Wl == T.pack "ExifText")
                                       -> case conVal_a1Wm of {
                                            arg_a1Wn
                                              -> (ExifText Data.Functor.<$> parseJSON arg_a1Wn) }
                                       | (conKey_a1Wl == T.pack "ExifInt")
                                       -> case conVal_a1Wm of {
                                            arg_a1Wo
                                              -> (ExifInt Data.Functor.<$> parseJSON arg_a1Wo) }
                                       | (conKey_a1Wl == T.pack "ExifDouble")
                                       -> case conVal_a1Wm of {
                                            arg_a1Wp
                                              -> (ExifDouble Data.Functor.<$> parseJSON arg_a1Wp) }
                                       | (conKey_a1Wl == T.pack "ExifBool")
                                       -> case conVal_a1Wm of {
                                            arg_a1Wq
                                              -> (ExifBool Data.Functor.<$> parseJSON arg_a1Wq) }
                                       | (conKey_a1Wl == T.pack "ExifArray")
                                       -> case conVal_a1Wm of {
                                            arg_a1Wr
                                              -> (ExifArray Data.Functor.<$> parseJSON arg_a1Wr) }
                                       | otherwise -> Control.Monad.mzero }
                              _ -> Control.Monad.mzero }
                       _ -> Control.Monad.mzero } }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多