我有以下json-data
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
在密钥不存在的情况下,我对Prism和Traversals的了解仍然处于开发阶段,所以我唯一能做的就是:
#!/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 :(得分:1)
按照Benjamin Hodgson关于路径的单独数据类型的想法,这是一个使用 lens-aeson 和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
是一种从群落中“摧毁”Value
开始形式的共生。处理每个节点时,我们可以访问为其子节点获得的结果。
Maybe
的{{3}}会从左侧返回第一个Just
。
asum
生成地图的键列表,或矢量的整数索引列表。它们与当前节点的子节点的结果一一匹配。