我正在使用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
,这是一个部分功能。如何在不使用部分函数的情况下获得上述功能?
答案 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