我正在尝试解析一些书目数据,更具体地说,为每个项目提取“主题”字段。数据是json,看起来像这样:
{"rows": [
{"doc":{"sourceResource": {"subject": ["fiction", "horror"]}}},
{"doc":{"sourceResource": {"subject": "fantasy"}}}
]}
如果每个条目都是Text或[Text],我可以拉出'subject',但我很难理解如何同时容纳这两个条目。这是我目前状态下的程序:
{-# LANGUAGE OverloadedStrings#-}
import Debug.Trace
import Data.Typeable
import Data.Aeson
import Data.Text
import Control.Applicative
import Control.Monad
import qualified Data.ByteString.Lazy as B
import Network.HTTP.Conduit (simpleHttp)
import qualified Data.HashMap.Strict as HM
import qualified Data.Map as Map
jsonFile :: FilePath
jsonFile = "bib.json"
getJSON :: IO B.ByteString
getJSON = B.readFile jsonFile
data Document = Document { rows :: [Row]}
deriving (Eq, Show)
data Row = SubjectList [Text]
| SubjectText Text
deriving (Eq, Show)
instance FromJSON Document where
parseJSON (Object o) = do
rows <- parseJSON =<< (o .: "rows")
return $ Document rows
parseJSON _ = mzero
instance FromJSON Row where
parseJSON (Object o) = do
item <- parseJSON =<< ((o .: "doc") >>=
(.: "sourceResource") >>=
(.: "subject"))
-- return $ SubjectText item
return $ SubjectList item
parseJSON _ = mzero
main :: IO ()
main = do
d <- (decode <$> getJSON) :: IO (Maybe Document)
print d
任何帮助都将不胜感激。
编辑:
工作FromJSON Row实例:
instance FromJSON Row where
parseJSON (Object o) =
(SubjectList <$> (parseJSON =<< val)) <|>
(SubjectText <$> (parseJSON =<< val))
where
val = ((o .: "doc") >>=
(.: "sourceResource") >>=
(.: "subject"))
parseJSON _ = mzero
答案 0 :(得分:2)
首先,看看
的类型((o .: "doc") >>=
(.: "sourceResource") >>=
(.: "subject")) :: FromJSON b => Parser b
我们可以摆脱任何FromJSON
的实例。现在,显然,这可以单独用于Text
或[Text]
,但问题是您要获得Text
或 [Text]
。幸运的是,处理这个问题应该相当容易。而不是让它进一步解码它,只需从中获取Value
。获得Value
后,您可以将其解码为Text
并将其放入SubjectText
:
SubjectText <$> parseJSON val :: Parser Row
或[Text]
并将其放入SubjectList
:
SubjectList <$> parseJSON val :: Parser Row
但是等等,其中任何一个都可以,并且它们具有相同的输出类型。请注意,Parser
是Alternative
的一个实例,它可以让我们准确地说(“任何一个会做”)。因此,
(SubjectList <$> parseJSON val) <|> (SubjectText <$> parseJSON val) :: Parser Row
钽哒! (实际上,没有必要将它作为Value
拉出来;我们可以将长((o .: "doc") >>= (.: "sourceResource") >>= (.: "subject"))
链嵌入到每个子表达式中。但这很难看。)子>