2017-10-20 48 views
0

,我有以下的JSON數據導線/重寫JSON價值

value :: Maybe Value 
value = decode 
    "{ \"import\" : { \"starttime\": \"2017-02-20T18:45:456.45645\" \ 
        \ , \"endtime\" : \"2017-02-20T18:45:456.45645\" \ 
        \ } \ 
    \ , \"export\" : { \"starttime\": \"2017-02-20T18:45:456.45645\" \ 
        \ , \"endtime\" : \"2017-02-20T18:45:456.45645\" \ 
        \ } \ 
    \ , \"cleanup\" : { \"starttime\": \"2017-02-20T18:45:456.45645\" \ 
        \ , \"endtime\" : \"2017-02-20T18:45:456.45645\" \ 
        \ , \"errormsg\" : \"It is dead Jim!\" \ 
        \ } \ 
    \ }" 

,我的目標是改寫這個對象,它只包含了「直接路徑」,以給定的鍵 - 例如如果我搜索「ERRORMSG」只應

Just "{\"cleanup\":\"It is dead Jim!\"}" 

Just "{\"cleanup\": {\"errormsg\":\"It is dead Jim!\"}}" 

,並在關鍵的是不存在的情況下Nothing,我對棱鏡和遍歷知識仍處於階段發展,使我能夠做到的唯一事情是:

#!/usr/bin/env stack 
-- stack runhaskell --package=lens --package=aeson --package=lens-aeson-lens --package=bytestring 
{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Control.Lens 
import Data.Aeson 
import Data.Foldable 
import Data.Aeson.Lens 
import Data.Maybe 
import qualified Data.ByteString.Lazy.Char8 as B 

value :: Maybe Value 
value = decode 
    "{ \"import\" : { \"starttime\": \"2017-02-20T18:45:456.45645\" \ 
        \ , \"endtime\" : \"2017-02-20T18:45:456.45645\" \ 
        \ } \ 
    \ , \"export\" : { \"starttime\": \"2017-02-20T18:45:456.45645\" \ 
        \ , \"endtime\" : \"2017-02-20T18:45:456.45645\" \ 
        \ } \ 
    \ , \"cleanup\" : { \"starttime\": \"2017-02-20T18:45:456.45645\" \ 
        \ , \"endtime\" : \"2017-02-20T18:45:456.45645\" \ 
        \ , \"errormsg\" : \"It is dead Jim!\" \ 
        \ } \ 
    \ }" 

main :: IO() 
main = do 
    traverse_ (traverse (B.putStrLn . encode)) 
      [ value & _Just . members %~ fromMaybe Null . preview (key "errormsg") 
      , value & _Just . members %~ fromMaybe Null . preview (key "not here") 
      ] 

這將產生

{"export":null,"cleanup":"It is dead Jim!","import":null} 
{"export":null,"cleanup":null,"import":null} 
+0

您可能會發現通過調整問題可以更輕鬆一些。不要返回已經過濾的整個JSON blob,而是嘗試返回兩個部分:'data Result = Result {path :: [String],piece :: Value}'。然後你可以直接重建一個完整的JSON值。 –

回答

1

繼具有用於路徑的單獨的數據類型的本傑明霍奇森的想法,下面是其使用透鏡埃宋Control.Lens.Plated一個可能的解決方案:

import Control.Lens 
import Control.Lens.Plated (para) 
import Data.Foldable (asum) 
import Data.Aeson 
import qualified Data.Aeson.Lens 
import Data.Text (Text) 

data JsonPathPiece = Key Text | Index Int deriving Show 

data JsonPath = JsonPath [JsonPathPiece] Value deriving Show 

path :: Text -> Value -> Maybe JsonPath 
path key = para go 
    where 
    go :: Value -> [Maybe JsonPath] -> Maybe JsonPath 
    go v previous = case v of 
     Object o -> asum $ keyFound o : zipIntoMaybes Key o previous 
     Array as -> asum $ zipIntoMaybes Index as previous 
     _   -> Nothing 
    keyFound = preview (ix key.to (JsonPath [Key key])) 
    zipIntoMaybes makePiece as mbs = 
     zipWith fmap (toListOf (ifolded.asIndex.to makePiece.to addPiece) as) mbs 
    addPiece piece (JsonPath pieces v) = JsonPath (piece:pieces) v 

para是paramorphism即「破壞」一個Value起始形式葉子。在處理每個節點時,我們可以訪問爲其子節點獲得的結果。

asum對於Maybe從左側返回第一個Just

ifolded.asIndex產生一個映射關鍵字列表,或一個向量的整數索引列表。它們與當前節點的孩子的結果一一對應。