Отказоустойчивый анализ JSON
Я использую Data.Aeson для анализа некоторых JSON в тип записи. Время от времени данные добавляются в JSON, и это нарушает мой код, поскольку Эсон жалуется на что-то вроде:
ожидаемый объект с 21 парой имя / значение, но получил 23 имени / значения
Я действительно предпочел бы проанализировать JSON отказоустойчивым способом - мне все равно, будут ли добавлены дополнительные поля в JSON позднее, просто проанализируйте все, что можете! Есть ли способ добиться этой отказоустойчивости? Вот мой код:
myRecordFromJSONString :: BS.ByteString -> Maybe MyRecord
myRecordFromJSONString s = case Data.Attoparsec.parse json s of
Done _rest res -> Data.Aeson.Types.parseMaybe parseJSON res
_ -> Nothing
Я должен добавить, что я использую производное JSON из Data.Aeson.TH для генерации кода синтаксического анализа. Если я пишу код FromJSON вручную, он отказоустойчив, но я бы не хотел этого делать...
1 ответ
Если вы используете GHC 7.2 или 7.4, новая поддержка дженериков в aeson
не проверяет наличие дополнительных полей. Я не уверен, что это дизайн или нет, но мы используем его по той же причине.
{-# 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
Выполнение этого не удастся с производным от TH экземпляром из-за отсутствия 'field2' в записи. Generic
Экземпляр возвращает желаемый результат:
Just (MyRecord {field1 = 1})