2012-05-15 71 views
11

Tôi đang sử dụng Data.Aeson để phân tích cú pháp một số JSON thành một loại Bản ghi. Bất cứ lúc nào dữ liệu được thêm vào JSON và điều này phá vỡ mã của tôi như Aeson phàn nàn cái gì đó để tác động của:Phân tích cú pháp JSON dung sai lỗi

dự kiến ​​đối tượng với 21 cặp tên/giá trị nhưng có 23 tên/giá trị

Tôi thực sự muốn phân tích cú pháp JSON theo cách chịu lỗi - Tôi không quan tâm nếu có thêm nhiều trường vào JSON vào một ngày sau đó, chỉ cần phân tích cú pháp bất cứ điều gì bạn có thể! Có cách nào để đạt được khả năng chịu lỗi này không? Đây là mã của tôi:

myRecordFromJSONString :: BS.ByteString -> Maybe MyRecord 
myRecordFromJSONString s = case Data.Attoparsec.parse json s of 
    Done _rest res -> Data.Aeson.Types.parseMaybe parseJSON res 
    _    -> Nothing 

Tôi nên thêm rằng tôi đang sử dụng deriveJSON từ Data.Aeson.TH để tạo mã phân tích cú pháp. Nếu tôi viết mã FromJSON theo cách thủ công thì nó có khả năng chịu lỗi nhưng tôi không muốn làm điều đó ...

Trả lời

6

Nếu bạn đang sử dụng GHC 7.2 hoặc 7.4, hỗ trợ generics mới trong aeson không kiểm tra các trường bổ sung . Tôi không chắc chắn nếu điều này là do thiết kế hay không nhưng chúng tôi sử dụng nó cho cùng một lý do.

{-# LANGUAGE DeriveGeneriC#-} 
{-# LANGUAGE OverloadedStrings #-} 

import Data.Aeson 
import qualified Data.Aeson.Types 
import Data.Attoparsec 
import qualified Data.ByteString as BS 
import Data.ByteString.Char8() 
import GHC.Generics 

data MyRecord = MyRecord 
    { field1 :: Int 
    } deriving (Generic, Show) 

instance FromJSON MyRecord 

myRecordFromJSONString :: BS.ByteString -> Maybe MyRecord 
myRecordFromJSONString s = case Data.Attoparsec.parse json s of 
    Done _rest res -> Data.Aeson.Types.parseMaybe parseJSON res 
    _    -> Nothing 

main :: IO() 
main = do 
    let parsed = myRecordFromJSONString "{ \"field1\": 1, \"field2\": 2 }" 
    print parsed 

Chạy điều này sẽ không thành công với trường hợp TH có nguồn gốc do 'field2' không tồn tại trong bản ghi. Ví dụ Generic trả lại kết quả mong muốn:

Just (MyRecord {field1 = 1}) 
Các vấn đề liên quan