[英]Pattern Match Vector Value in Data.Aeson
我正在使用Data.Aeson將JSON解析為我的自定義類型。 我嘗試在我的FromJSON
實例中模式匹配Vector Value
( Array
),但不知道我該怎么做。 JSON value
鍵可以有一個值String
的列表, String
或列表的列表String
。
instance FromJSON Foo where
parseJSON (Object o) =
case lookup "value" o of
Just (String s) -> pure $ SimpleText s
Just foo@(Array (String s)) -> pure $ ListOfText $ V.toList <$> V.mapM (parseJSON :: Value -> Parser Text) foo
Just foo@(Array (Array (String s))) -> pure $ ListOfListOfText $ V.toList <$> V.mapM (parseJSON :: Value -> Parser Text) $ V.toList <$> V.mapM (parseJSON :: Value -> [Parser Value]) foo
同
data Foo = SimpleText Text
| ListOfText [Text]
| ListOfListOfText [[Text]]
deriving (Show, Eq, Ord)
我可以在Array上使用模式匹配來處理這種情況嗎? 或者我應該手動檢查每個Value
的類型? 怎么做?
不,你不能按照你在這里嘗試的方式進行模式匹配。 JSON數組可以包含不同類型的值,並且您不能對列表中的所有值進行模式匹配,就像它們中的值一樣。
有幾種方法可以解決您的實際問題。 有一種簡單的方法 ,有一種明確的方式可以為您提供更好的錯誤消息。
簡單的方法是使用已經存在Text
和[a]
FromJSON
實例的事實。 因此,您可以使用Alternative
運算符來編寫您的實例,如下所示:
instance FromJSON Foo where
parseJSON v = (SimpleText <$> parseJSON v)
<|> (ListOfText <$> parseJSON v)
<|> (ListOfListOfText <$> parseJSON v)
這里的訣竅是Aeson首先嘗試解析Text
值,然后如果失敗則會嘗試[Text]
,如果再次失敗則會嘗試[[Text]]
。
此解決方案的問題在於,如果您的JSON格式不正確,則錯誤消息可能沒有意義。 例如,如果你給它一個頂級Null值,你的錯誤將是它期望[[Text]]
,因為你總是得到鏈中最后一個值的錯誤。
要獲得更好的錯誤消息,您必須更加關注您期望的值。 如果結果是空數組,它應該是ListOfText
還是ListOfListOfText
? 由於我們無法直接在Vector
上進行模式匹配,因此我們可以將其轉換為列表和模式匹配:
instance FromJSON Foo where
parseJSON v = case v of
-- If its a string, we return the string as a SimpleText
(String s) -> return $ SimpleText s
-- If its an array, we turn the vector to a list so we can pattern match on it
(Array a) -> case V.toList a of
-- If its a empty list, we return a empty ListOfText
[] -> return $ ListOfText []
-- If the first value is a string, we put it as the first element of our ListOfTexts and try to parse the rest.
(String s: xs) -> ListOfText . (s:) <$> mapM parseJSON xs
-- If the first value is an array, we try to parse it as [Text], then parse the rest.
(Array a: xa) -> ListOfListOfText <$> ((:) <$> parseJSON (Array a) <*> mapM parseJSON xa)
-- If the first value is neither a string or array we return a error message.
_ -> fail "Expected an Array or an Array of Arrays."
-- If the top level value is not a string or array we return a error message.
_ -> fail "Expected a String or Array"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.