2

大きくブラウジングするにはどうすればよいAeson Valuesですか? 興味のある文字列が構造体のどこかにネストされている必要があることはわかっています。どうすれば見つけられますか?

これまでのところ、コンストラクターを照会する方法しか知らず、それが配列であることがわかりました。どうすればそれ以上深く掘り下げることができますか?

> take 20 $ show bt
"Array (fromList [Obj"
4

1 に答える 1

4

このlensパッケージには、 JSON のようなツリー状の構造を検査するための便利な機能がありますValuelens-aeson追加の JSON 固有の機能を備えたパッケージもあります。

import Data.Text
import Data.Aeson
import Data.Aeson.Lens (_Value,_String) -- this is from lens-aeson
import Data.Foldable (toList)

import Control.Lens (Fold,folding,universeOf,toListOf,paraOf,preview)

指定された JSONFoldの直接の子を抽出するレンズを定義することから始めることができます。ValuesValue

vchildren :: Fold Value Value
vchildren = folding $ \v -> case v of
    Object o -> toList o
    Array a -> toList a
    _ -> []

foldingリストを返す関数を作成する関数ですlensFoldこの場合、のリストValue

関数 fromと組み合わせvchildrenて、それ自体を含むa のすべての推移的な子孫を抽出する関数を取得できます。universeOfControl.Lens.PlatedValue

allValues :: Value -> [Value]
allValues = universeOf vchildren

そして、この関数は、に含まれるすべてのテキストを抽出しますValue_Stringプリズムを使用しますData.Aeson.Lens(aPrismは、渡すことができる「具体化された」パターンに少し似ています):

allTexts :: Value -> [Text]
allTexts = toListOf (folding allValues . _String)

Control.Lens.PlatedparaOfには、「パラモルフィム」を構築できる のような興味深い機能もあります。パラモーフィズムは、葉から始まり、結果を上方向に構築する木のような構造の「制御された破壊」です。たとえば、この関数

vpara :: (Value -> [r] -> r) -> Value -> r
vpara = paraOf vchildren

最初のパラメータとして、「現在のノード」と下のノードの中間結果を受け取る別の関数を取り、現在のノードの中間結果を構築します。

vparaリーフから JSON 値の消費を開始し (これらのノードの中間結果リストは単純です[])、上に進みます。

の使用例の 1 つvparaは、次のように、ある条件に一致するテキストで終わる JSON 内のパスのリストを取得することです。

type Path = [Value]

pathsThatEndInText :: (Text -> Bool) -> Value -> [Path]
pathsThatEndInText pred = vpara func
  where
    func :: Value -> [[Path]] -> [Path]
    func v@(String txt) _ | pred txt = [[v]]
    func v l@(_:_) = Prelude.map (v:) (Prelude.concat l)
    func _ _ = []

によって返されたパスの 1 つのある程度読みやすい説明を取得するには、次のようにしpathsThatEndInTextます。

import qualified Data.HashMap.Strict as HM
import qualified Data.Vector as V

describePath :: Path -> [String]
describePath (v:vs) = Prelude.zipWith step (v:vs) vs
  where
    step (Object o) next = (unpack . Prelude.head . HM.keys . HM.filter (==next)) o
    step (Array a) next = (show . maybe (error "not found") id) (V.elemIndex next a)
    step _ _ = error "should not happen"

最後に、ghci で上記の関数をテストするための JSON 値の例を次に示します。

exampleJSON :: Value
exampleJSON = maybe Null id (preview _Value str)
  where
    str = "[{ \"k1\" : \"aaa\" },{ \"k2\" : \"ccc\" }, { \"k3\" : \"ddd\" }]"

要点は次のとおりです。

于 2015-02-20T21:24:10.340 に答える