2017-02-03 58 views
0

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类型,我需要/希望得到另一个ObjectMaybe Object在这一点上。

我在正确的道路上吗?

回答

0

我要从最后开始,然后回到你的问题。

解决与

通常你做一个Haskell数据类型为每个JSON类型和写入FromJSON类实现解析器。你不必这样做,但它确实减轻了你的心理负担,并符合你在其他项目中可能观察到的内容。为此,您为您的元素只是一对夫妇类型MyMys这些元素的列表:

{-# 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解析器得到公正的ab值:

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条目,我们可以将其解析为VectorMy值。

instance FromJSON My where 
    parseJSON (Object v) = My <$> v .: "a" <*> v .: "b" 
    parseJSON o = fail $ "Invalid type for My: " ++ show o 

而且My数据仅仅是一个ab领域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),最后为矢量的每个元素再次提取出一个对象,并在那里查找ab键。举个例子,我想写它,但如果你至少不允许自己使用monad,那就太难看了。

0

该教程可能会帮助你,因为它帮助了我。

接下来,我到了下面的代码。它扩展了sample以允许处理不同的样品(一些具有各种缺陷)进行检查。 main预计将被处理的样本的身份作为编译的可执行文件的第一个参数提供。

从JSON结构的底部开始,向上工作,函数parseMy :: Value -> Parser My使用'a''b'键处理对象以产生My(如果成功);中间帮助函数parseMyList'处理这样的对象的数组以产生列表My;并且parseMyList处理具有密钥'k1'的对象,从而产生具有密钥'k2'的对象,以产生My的列表。

main,parsedecode(如果成功的话)的结果适用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"