考虑以下JSON结构:
{"k1":
{"k2":
[{"a": 3, "b": 4, "c": 2},
{"a": 1, "b": 2, "c": 9}]},
"irrelevant": "x"}和Haskell数据类型:
data My = My Int Int上面的JSON应该解析成My:[My]的列表,而两个Int应该分别取自JSON数组的"a“和"b”键:
[My 3 4, My 1 2]诚然,我已经在它最简单的部分遇到了麻烦。
下面是我开始使用Aeson的方法:
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as L8
sample :: L8.ByteString
sample = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "在repl上:
decode sample :: Maybe Object
Just (Object (fromList [("irreleva...这就像预期的那样工作,JSON被解析。然而,下一步,获取关键字"k1“处的对象不起作用:
:t (fromJust $ (decode sample :: Maybe Object)) .: "k1"
...
:: FromJSON a => aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser a我在这里接收到一个Parser a类型,此时我需要/期望获得另一个Object或Maybe Object。
我走的路对吗?
发布于 2017-02-04 14:32:14
我将从头开始,然后回到你们的问题上。
用类求解
通常,您为每个JSON类型创建一个Haskell数据类型,并编写实现解析器的FromJSON类。你不必这样做,但它确实减轻了你的精神负担,并与你在其他项目中可能观察到的东西保持一致。为此,让我们为您的元素创建几个类型My,并为这些元素的列表创建Mys:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.Vector as V
sample :: L8.ByteString
sample = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
newtype Mys = Mys [My]
deriving (Eq,Ord,Show)
data My = My Int Int
deriving (Eq,Ord,Show)好的,没问题。现在,我们可以从您的k1记录中提取a-b-c对象的列表,并对这些对象运行My解析器,以仅获取a和b值:
instance FromJSON Mys where
parseJSON (Object v) = do
do k1Val <- v .: "k1"
case k1Val of
Object k1 ->
do k2Val <- k1 .: "k2"
Mys . V.toList <$> mapM parseJSON k2Val
_ -> fail "k1 was not an Object"
parseJSON o = fail $ "Invalid type for Mys: " ++ show o也就是说,要解析我们需要一个对象的Mys,该对象必须有一个k1条目,该条目是另一个对象。k1必须有一个k2条目,我们可以将其解析为My值的Vector。
instance FromJSON My where
parseJSON (Object v) = My <$> v .: "a" <*> v .: "b"
parseJSON o = fail $ "Invalid type for My: " ++ show oMy数据只是将a和b字段解析为Int。看吧:
> decode sample :: Maybe Mys
Just (Mys [My 3 4,My 1 2])不带类的
您询问了:t (fromJust $ (decode sample :: Maybe Object)) .: "k1",这只是询问.:类型的一种奇特方式
> :t (.:)
(.:) :: FromJSON a => Object -> Text -> Parser a因此,正如您所说的,您提供了一个对象和文本来获取Parser。我不建议再次使用Parser monad --您只是在decode中有效地使用了它。简而言之,我会说不,你没有走在通往幸福的道路上。
如果您不打算按照设计使用API,那么就忘记组合符,直接使用数据类型。也就是说,大量的Value类型的case破坏。首先是k1,它是一个Object (只是一个HashMap),然后提取k2的值,它是一个Array ( Vector),最后对于Vector的每个元素,再次提取一个对象并在那里查找a和b键。举个例子,我打算把它写出来,但是如果你不至少允许你自己有一个Maybe monad,那么它是非常丑陋的。
发布于 2017-02-04 20:46:28
教程'Aeson: the tutorial' by Artyom可能会对您有帮助,就像它对我有帮助一样。
按照它,我得到了以下代码。它扩展了sample,允许对不同样本(一些具有各种缺陷)的处理进行检查。main期望要处理的示例的标识作为第一个参数提供给已编译的可执行文件。
从JSON结构的底部开始,向上递增,函数parseMy :: Value -> Parser My处理具有'a‘'b’键的对象以生成My (如果成功);中间辅助函数parseMyList'处理此类对象的数组以生成My列表;parseMyList处理具有键'k1‘的对象,依次生成具有键'k2’的对象,以生成My列表。
在main中,parse将parseMyList :: Value -> Parser [My]应用于decode的结果(如果成功)。
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Data.Aeson ((.:), decode, Value)
import Data.Aeson.Types (parse, Parser, withArray, withObject)
import qualified Data.ByteString.Lazy.Char8 as L8 (ByteString)
import qualified Data.Vector as V (toList)
import System.Environment (getArgs)
data My = My Int Int deriving (Show)
sample :: String -> L8.ByteString
sample "1" = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
sample "2" = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"c\": 9}]}, \"irrelevant\": \"x\"} "
sample "3" = "{\"k1\":{\"k3\":[{\"a\": 3, \"b\": 4, \"c\": 2}, {\"a\": 1, \"b\": 2, \"c\": 9}]}, \"irrelevant\": \"x\"} "
sample "4" = "{\"k1\":{\"k2\":[{\"a\": 3, \"b\": 4, \"c\": 2}]}, \"irrelevant\": \"x\"} "
sample _ = "Error"
parseMy :: Value -> Parser My
parseMy = withObject "object" $ \o -> do
a <- o .: "a"
b <- o .: "b"
return $ My a b
parseMyList' :: Value -> Parser [My]
parseMyList' = withArray "array" $ \arr ->
mapM parseMy (V.toList arr)
parseMyList :: Value -> Parser [My]
parseMyList = withObject "object" $ \o -> do
k1 <- o .: "k1"
k2 <- k1 .: "k2"
parseMyList' k2
main :: IO ()
main = do
args <- getArgs
case args of
[] -> fail "expected sample identity as the first argument"
n:_ -> do
putStrLn $ "Processing sample " ++ n
case decode (sample n) of
Just result -> print $ parse parseMyList result
Nothing -> fail "decoding failed"https://stackoverflow.com/questions/42031937
复制相似问题