2017-02-03 95 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"