安全阅读Aeson parseJSON

时间:2013-10-30 01:46:54

标签: haskell applicative aeson

我正在使用Aeson解析来自Yahoo API的json引用数据。引用可能如下所示:

{
  "date": "2010-03-10",
  "Date": "2010-03-10",
  "Open": "0.37",
  "High": "0.37",
  "Low": "0.34",
  "Close": "0.35",
  "Volume": "443000",
  "Adj_Close": "0.35"
}

(那是使用this YQL查询)

如您所见,这些数字是引用的。我可以像这样写一个fromJSON实现:

instance FromJSON Quote where
  parseJSON (Object o) =
    Quote <$> o .: "Date"
          <*> o .: "Open"
          <*> o .: "High"
          <*> o .: "Low"
          <*> o .: "Close"
          <*> o .: "Volume"
  parseJSON _ = mzero

与派生的相同。不幸的是,只有当我想要Open,High,Low等作为Text类型时,这才有效。如果我尝试将这些字段中的任何字段设置为Double,那么解析就会失败,比如说。

我可以这样写:

<*> (fmap read $ o .: "Open")

将其作为我喜欢的任何内容,但这会使用read,这是一个部分功能。如何在不使用部分函数的情况下获得上述功能?

1 个答案:

答案 0 :(得分:1)

首先,找一个安全的读取功能。我必须hoogle it

其次,你必须使用的不仅仅是应用来获得选择。在下面,我使用readMay进行安全读取,并使用辅助函数在应用Read实例时提取字段。

{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-}
import Safe
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Text as T
import Data.Word
import Control.Applicative
import Control.Monad

data Quote = Quote Text Double Double Double Double Word64
instance FromJSON Quote where
  parseJSON (Object o) = do
    let readField :: (Read a) => T.Text -> Parser a
        readField f = do
            v <- o .: f
            case readMay (T.unpack v) of
                Nothing -> fail $ "Bad Field: " ++ T.unpack f
                Just r  -> return r
    Quote <$> o .: "Date"
          <*> readField "Open"
          <*> readField "Close"
          <*> readField "Low"
          <*> readField "High"
          <*> readField "Volume"
  parseJSON _ = mzero