我正在尝试解析一个看起来像这样的嵌套JSON文件
{
"Meta Data": {
"1: Symbol": "MSFT",
"2: Indicator": "Relative Strength Index (RSI)",
"3: Last Refreshed": "2018-10-17 10:31:05",
"4: Interval": "weekly",
"5: Time Period": 10,
"6: Series Type": "open",
"7: Time Zone": "US/Eastern Time"
},
"Technical Analysis: RSI": {
"2018-10-17 10:31:05": {
"RSI": "54.5653"
},
"2018-10-12": {
"RSI": "63.0279"
},
"2018-10-05": {
"RSI": "74.7519"
},
"2018-09-28": {
"RSI": "72.1573"
},
"2018-09-21": {
"RSI": "74.8123"
},
"2018-09-14": {
"RSI": "66.7116"
},
"2018-09-07": {
"RSI": "75.8051"
...
...
... and so on
我的目标是获得最新/最高的“ RSI”值。由于键(日期)是可变的,因此我试图在不匹配键的情况下获取它。
这是我到目前为止所得到的
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Tesst where
import Data.Aeson
import qualified Data.ByteString.Lazy as B
import Data.HashMap.Strict as S
import Data.Text
import Data.Time
import GHC.Exts
import GHC.Generics
import Network.HTTP.Conduit (simpleHttp)
newtype TechnicalAnalysis = TechnicalAnalysis {
rsiQuote :: Object
} deriving (Show, Generic)
instance FromJSON TechnicalAnalysis where
parseJSON = withObject "RSI Quote" $
\o -> do
rsiQuote <- o .: "Technical Analysis: RSI"
return TechnicalAnalysis {..}
main :: IO ()
main = do
putStrLn "Which ticker? "
symbolToQuote <- getLine
d <- (eitherDecode <$> simpleHttp ("https://www.alphavantage.co/query?function=RSI&interval=weekly&time_period=10&series_type=open&apikey=FI2KMDSAE&symbol=" ++ symbolToQuote)) :: IO (Either String TechnicalAnalysis)
case d of
Left e -> print e
Right qt -> print $ Prelude.map (\(a, b) -> (read (unpack a) :: Day, b)) (S.toList (rsiQuote qt))
我要运行的代码是这样的:
[(2005-09-02,Object (fromList [("RSI",String "60.8860")])),(2017-12-29,Object (fromList [("RSI",String "71.1921")])),(2011-09-16,Object (fromList [("RSI",String "50.3489")])),(2000-05-12,Object (fromList [("RSI",String "33.6402")]))...
如您所见,所有值都是乱序的。
我的问题是:
答案 0 :(得分:0)
我能够按照威廉姆斯的指示(在评论中)解决问题。
angular
这是关键
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Tesst where
import Data.Aeson
import qualified Data.ByteString.Lazy as B
import Data.HashMap.Strict as S
import Data.List
import Data.Text
import Data.Time
import GHC.Exts
import GHC.Generics
import Network.HTTP.Conduit (simpleHttp)
newtype TechnicalAnalysis = TechnicalAnalysis {
rsiQuote :: Object
} deriving (Show, Generic)
instance FromJSON TechnicalAnalysis where
parseJSON = withObject "RSI Quote" $
\o -> do
rsiQuote <- o .: "Technical Analysis: RSI"
return TechnicalAnalysis {..}
main :: IO ()
main = do
putStrLn "Which ticker? "
symbolToQuote <- getLine
d <- (eitherDecode <$> simpleHttp ("https://www.alphavantage.co/query?function=RSI&interval=weekly&time_period=10&series_type=open&apikey=FI2KMC2DSAE&symbol=" ++ symbolToQuote)) :: IO (Either String TechnicalAnalysis)
case d of
Left e -> print e
Right qt -> do
let l = S.toList (rsiQuote qt)
print $ maximumBy (\(a, _) (b, _) -> compare a b) l
答案 1 :(得分:0)
您已选择本质上为动态类型的Object
作为语义对象。选择更好的东西; Map Day Double
,例如,或者ArgMax Day Double
,如果您真的只想要最新的RSI值,而不会查看其他任何内容。
例如:
import Control.Monad
import Data.Aeson
import Data.Aeson.Types
import Data.HashMap.Strict as S
import Data.List.NonEmpty
import Data.Semigroup
import Data.Text
import Data.Time
-- can't use readMaybe, 2018-10-17 10:31:05 has extra non-Day gunk at the end
jsonReadText :: Read a => String -> Text -> Parser a
jsonReadText err t = case reads (unpack t) of
(v,_):_ -> return v
_ -> fail $ "could not parse " ++ unpack t ++ " as " ++ err
newtype RSI = RSI Double deriving Show
instance FromJSON RSI where
parseJSON = withObject "object with RSI key" $ \o -> do
t <- o .: pack "RSI"
RSI <$> jsonReadText "Double" t
newtype LatestRSI = LatestRSI (ArgMax Day RSI) deriving Show
instance FromJSON LatestRSI where
parseJSON = withObject "RSI Quote" $ \o -> do
quoteMap <- o .: pack "Technical Analysis: RSI"
quotes <- forM (S.toList quoteMap) $ \(dayText, rsiValue) -> do
day <- jsonReadText "Day" dayText
rsi <- parseJSON rsiValue
return (Max (Arg day rsi))
case quotes of
[] -> fail "expected non-empty collection of RSI quotes"
q:qs -> return . LatestRSI . sconcat $ q :| qs
ghci中的用法示例:
> bs <- Data.ByteString.Lazy.readFile "test.json"
> eitherDecode bs :: Either String LatestRSI
Right (LatestRSI (Max {getMax = Arg 2018-10-17 (RSI 54.5653)}))