我需要能够将一个巨大的嵌套JSON结构解析成更具延展性的东西,最好是从字符串到字符串的映射。
我正在谈论的各种结构的例子:
{“foo”:“baz”,“bar”:{“qux”:“quux”,“baz”:{“abracadabra”:“alakazam”,“abc”:“xyz”}}}
我想将上述内容解析为:
fromList [(“foo”,“baz”),(“bar / qux”,“quux”),(“bar / baz / abracadabra”,“alakazam”),(“bar / baz / abc”, “XYZ”)]
是否可以使用Aeson的相对库存解析器?我是否应该对Aeson解析的JSON AST进行一些修改,直到它起作用?
答案 0 :(得分:4)
我在这里无法自拔,我 滥用lens
......
在下面的示例中,Primitive
只是叶子JSON值的数据类型。
import Data.Aeson
import Control.Lens
import Data.Aeson.Lens
flatten :: Value -> [(String, Primitive)]
flatten (Object obj) = do
(k, v) <- obj^@..ifolded
flatten v <&> _1 <>~ (k^..each ++ "/")
flatten (Array arr) = arr^..each >>= flatten
flatten prim = [("", prim^?! _Primitive)]
input = "{ \"foo\" : \"baz\", \"bar\" : {\"qux\" : \"quux\", \"baz\" : {\"abracadabra\" : \"alakazam\", \"abc\" : \"xyz\" } } }"
main = do
print $ input^? _Value . to flatten
-- Just [("foo/",StringPrim "baz"),("abc/baz/bar/",StringPrim "xyz"),("abracadabra/baz/bar/",StringPrim "alakazam"),("qux/bar/",StringPrim "quux")]
答案 1 :(得分:2)
module AesonFun(collapse) where
import qualified Data.Map as M (empty, Map, insert, lookup)
import qualified Data.HashMap.Strict as HM (toList)
import qualified Data.List as L (foldl')
import qualified Data.Aeson as Ae (decode, )
import qualified Data.Text as T (unpack, Text)
import Data.Aeson.Types as AT
import qualified Data.ByteString.Lazy.Char8 as BS ( pack )
collapse :: String -> StringMap
collapse s = maybe M.empty (collapser0 M.empty) $ toValue s
toValue :: String -> Maybe Value
toValue = Ae.decode . BS.pack
type StringMap = M.Map String String
delim = "/"
type Collapser = StringMap -> Value -> StringMap
collapser0 = collapser Nothing
collapser :: (Maybe String) -> Collapser
collapser s m v = case v of
AT.Object ob -> L.foldl' (\m' (c,v') -> c m' v') m pairs where
pairs :: [(Collapser, Value)]
pairs = map toPair $ HM.toList ob
toPair :: (T.Text, Value) -> (Collapser, Value)
toPair (t, v') = (collapser s', v') where
s' = case s of
Just p -> Just $ p ++ delim ++ (T.unpack t)
Nothing -> Just $ (T.unpack t)
AT.String t -> maybe m (\str -> M.insert str (T.unpack t) m) s
otherwise -> m
AesonFun> collapse "{ \"foo\" : \"baz\", \"bar\" : {\"qux\" : \"quux\", \"baz\" : {\"abracadabra\" : \"alakazam\", \"abc\" : \"xyz\" } } }"
fromList [("bar/baz/abc","xyz"),("bar/baz/abracadabra","alakazam"),("bar/qux","quux"),("foo","baz")]