isNothing 在解析 JSON 文件时抛出异常
isNothing throws an exception when parsing JSON file
我有以下函数可以使用 Data.Aeson
库解码 JSON 文件:
data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
还有这个函数:
getBook content = do
putStrLn (Data.ByteString.Lazy.Char8.unpack content)
let searchResult = decode content :: Maybe SearchResult
print (isNothing searchResult)
print searchResult
函数 getBook
适用于许多 JSON 文件。这是一个例子:
False
Just (SearchResult {items = [Item {volumeInfo = VolumeInfo {title = "A Memoir of Jane Austen", authors = ["James Edward Austen-Leigh","Jane Austen, James Austen-Leigh"], publisher = "Wordsworth Editions", publishedDate = "2007", industryIdentifiers = [IndustryIdentifier {identifierType = "ISBN_10", identifier = "1840225602"},IndustryIdentifier {identifierType = "ISBN_13", identifier = "9781840225600"}], pageCount = 256, categories = ["Novelists, English"]}}]})
JSON内容解码成功,因此第一行isNothing
returnsFalse
,后面是解码后的内容。如果我使用 this JSON file 作为 content
再次运行该函数,我会得到以下输出:
True
Nothing
无法解码文件(因为 JSON 文件中没有字段 categories
),因此 isNothing
returns True
, Nothing
打印在屏幕上。现在的问题是当我使用 this JSON file 作为 content
运行它时。我明白了:
*** Exception: Maybe.fromJust: Nothing
执行print (isNothing searchResult)
时抛出异常,不明白为什么没有像上一个例子那样返回True
(因为这里没有字段industryIdentifiers
,例如)。我错过了什么或做错了什么?
编辑:
我发现每次 JSON 文件不包含字段 industryIdentifiers
时都会出现问题。它在这一行中失败:
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
github包定义了一个方便的操作符来定义数组字段:
-- | A slightly more generic version of Aeson's @(.:?)@, using `mzero' instead
-- of `Nothing'.
(.:<) :: (FromJSON a) => Object -> T.Text -> Parser [a]
obj .:< key = case Map.lookup key obj of
Nothing -> pure mzero
Just v -> parseJSON v
(这里Map
是Data.HashMap.Lazy
的别名)
那么 VolumeInfo 的 FromJSON
实例将定义如下:
instance FromJSON VolumeInfo
v .: "title" <*>
...
v .:< "industryIdentifiers" <*>
...
我有以下函数可以使用 Data.Aeson
库解码 JSON 文件:
data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <data SearchResult = SearchResult {
items :: [Item]
} deriving (Show)
instance FromJSON SearchResult where
parseJSON :: Value -> Parser SearchResult
parseJSON (Object v) = SearchResult <$>
parseJSON (fromJust $ HM.lookup "items" v)
parseJSON _ = mzero
data Item = Item {
volumeInfo :: VolumeInfo
} deriving (Show)
instance FromJSON Item where
parseJSON :: Value -> Parser Item
parseJSON (Object v) = Item <$>
parseJSON (fromJust $ HM.lookup "volumeInfo" v)
parseJSON _ = mzero
data VolumeInfo = VolumeInfo {
title :: String,
authors :: [String],
publisher :: String,
publishedDate :: String,
industryIdentifiers :: [IndustryIdentifier],
pageCount :: Int,
categories :: [String]
} deriving (Show)
instance FromJSON VolumeInfo where
parseJSON :: Value -> Parser VolumeInfo
parseJSON (Object v) = VolumeInfo <$>
v .: "title" <*>
v .: "authors" <*>
v .: "publisher" <*>
v .: "publishedDate" <*>
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
v .: "pageCount" <*>
v .: "categories"
parseJSON _ = mzero
data IndustryIdentifier = IndustryIdentifier {
identifierType :: String,
identifier :: String
} deriving (Show)
instance FromJSON IndustryIdentifier where
parseJSON :: Value -> Parser IndustryIdentifier
parseJSON (Object v) = IndustryIdentifier <$>
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
gt;
v .: "type" <*>
v .: "identifier"
parseJSON _ = mzero
还有这个函数:
getBook content = do
putStrLn (Data.ByteString.Lazy.Char8.unpack content)
let searchResult = decode content :: Maybe SearchResult
print (isNothing searchResult)
print searchResult
函数 getBook
适用于许多 JSON 文件。这是一个例子:
False
Just (SearchResult {items = [Item {volumeInfo = VolumeInfo {title = "A Memoir of Jane Austen", authors = ["James Edward Austen-Leigh","Jane Austen, James Austen-Leigh"], publisher = "Wordsworth Editions", publishedDate = "2007", industryIdentifiers = [IndustryIdentifier {identifierType = "ISBN_10", identifier = "1840225602"},IndustryIdentifier {identifierType = "ISBN_13", identifier = "9781840225600"}], pageCount = 256, categories = ["Novelists, English"]}}]})
JSON内容解码成功,因此第一行isNothing
returnsFalse
,后面是解码后的内容。如果我使用 this JSON file 作为 content
再次运行该函数,我会得到以下输出:
True
Nothing
无法解码文件(因为 JSON 文件中没有字段 categories
),因此 isNothing
returns True
, Nothing
打印在屏幕上。现在的问题是当我使用 this JSON file 作为 content
运行它时。我明白了:
*** Exception: Maybe.fromJust: Nothing
执行print (isNothing searchResult)
时抛出异常,不明白为什么没有像上一个例子那样返回True
(因为这里没有字段industryIdentifiers
,例如)。我错过了什么或做错了什么?
编辑:
我发现每次 JSON 文件不包含字段 industryIdentifiers
时都会出现问题。它在这一行中失败:
parseJSON (fromJust $ HM.lookup "industryIdentifiers" v) <*>
github包定义了一个方便的操作符来定义数组字段:
-- | A slightly more generic version of Aeson's @(.:?)@, using `mzero' instead
-- of `Nothing'.
(.:<) :: (FromJSON a) => Object -> T.Text -> Parser [a]
obj .:< key = case Map.lookup key obj of
Nothing -> pure mzero
Just v -> parseJSON v
(这里Map
是Data.HashMap.Lazy
的别名)
那么 VolumeInfo 的 FromJSON
实例将定义如下:
instance FromJSON VolumeInfo
v .: "title" <*>
...
v .:< "industryIdentifiers" <*>
...