解析JSON与埃宋
Cosider以下JSON结构:解析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]
,而两个int应该分别从JSON阵列的“a”和“b”键中取出:
[My 3 4, My 1 2]
无可否认我很好ady面临着最简单的部分麻烦。
这是我如何开始使用埃宋:
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
在这一点上。
我在正确的道路上吗?
我要从最后开始,然后回到你的问题。
解决与类
通常你做一个Haskell数据类型为每个JSON类型和写入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)
OK,没问题。现在,我们可以从记录提取ABC对象的列表以及对这些对象运行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
我们需要一个对象,该对象必须具有另一个对象的条目。必须有一个k2
条目,我们可以将其解析为Vector
的My
值。
instance FromJSON My where
parseJSON (Object v) = My <$> v .: "a" <*> v .: "b"
parseJSON o = fail $ "Invalid type for My: " ++ show o
而且My
数据仅仅是一个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,那么只需忘记组合器并直接使用数据类型即可。也就是很多case
销毁的Value
类型。首先是k1这是一个Object
(只是一个HashMap
),然后提取k2值这是一个Array
(一Vector
),最后为矢量的每个元素再次提取出一个对象,并在那里查找a
和b
键。举个例子,我想写它,但如果你至少不允许自己使用monad,那就太难看了。
该教程可能会帮助你,因为它帮助了我。
接下来,我到了下面的代码。它扩展了sample
以允许处理不同的样品(一些具有各种缺陷)进行检查。 main
预计将被处理的样本的身份作为编译的可执行文件的第一个参数提供。
从JSON结构的底部开始,向上工作,函数parseMy :: Value -> Parser My
使用'a''b'键处理对象以产生My
(如果成功);中间帮助函数parseMyList'
处理这样的对象的数组以产生列表My
;并且parseMyList
处理具有密钥'k1'的对象,从而产生具有密钥'k2'的对象,以产生My
的列表。
在main
,parse
对decode
(如果成功的话)的结果适用parseMyList :: Value -> Parser [My]
。
{-# 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"