2011-08-03 29 views
13

Theo sau từ số previous post, tôi thấy mình hoàn toàn bị kẹt. Tôi đang cố gắng phân tích cú pháp một cấu trúc JSON thành kiểu của riêng tôi, và không chỉ tôi bị mắc kẹt về cách phân tích mảng, tôi thậm chí không chắc chắn liệu mình có đang sử dụng thư viện Aeson như dự định hay không. Mọi sự trợ giúp sẽ rất được trân trọng.Haskell, Aeson & phân tích cú pháp JSON thành loại tùy chỉnh

Mã:

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 

Các tập tin thử nghiệm:

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

Trả lời

10

Bạn cần phải làm theo các loại parseJSON một chút xuống một đường mòn thỏ, nhưng một khi bạn nhận ra những gì (Array a) đại diện, nó nên đơn giản.

parseJSON có loại Value -> Parser a, vì vậy (Array a) có loại Value. Một trong các biến thể trong loại ValueArray Array, do đó, a trong (Array a) phải thuộc loại Array, được định nghĩa là Vector Value. Các Value s bên trong đó Vector là những gì bạn muốn gọi parseJSON để trả lại danh sách của bạn, vì vậy hãy kiểm tra những gì bạn có thể làm với một Vector.

Cách tiếp cận dễ nhất có thể sẽ chuyển đổi a thành danh sách có Vector.toList và sau đó sử dụng mapM để phân tích cú pháp Values.

Cách khác, bạn có thể tránh Vector để liệt kê chuyển đổi bằng cách thay đổi ExifArray biến thể để giữ Vector ExifValue và sau đó sử dụng Vector.mapM.

5

Tôi không phải là người nói tiếng Anh bản địa, vì vậy tôi có thể không hiểu bạn rất rõ. Tôi đoán bạn muốn biết cách phân tích cú pháp json thành kiểu dữ liệu đệ quy như ExifValue mà bạn đã trình bày. Vì vậy, tôi đã thực hiện một ví dụ đơn giản để hiển thị cách phân tích cú pháp json thành kiểu dữ liệu đệ quy.

{-# 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

Một bản dựng mới hơn một chút của aeson library (0.3.2.12) hỗ trợ các cá thể JSON tự tạo.

{-# 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 

Tạo:

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 } } 
Các vấn đề liên quan