2016-04-06 16 views
0

したがって、私はHaskell Aesonライブラリで次のJSONを解析することで何かのロードブロッキングを起こしました。Aesonでネストされた異種JSON配列を解析する

だから私は、次のしていると言う:

"packetX_Name": [ 
    "container", 
    [ 
    { 
     "field1": "value1", 
     "field2": "value2" 
    }, 
    { 
     "field1": "value3", 
     "field2": "value4" 
    }, 
    { 
     "field1": "value5", 
     "field2": "value6" 
    } 
    ] 
], 
"packetY_Name": [ 
    "container", 
    [ 
    { 
     "field1": "value7", 
     "field2": "value8" 
    }, 
    { 
     "field1": "value9", 
     "field2": "value10" 
    } 
    ] 
], 
etc... 

そして私は、理想的には、このように、この使用してデータ型解析したいと思います:

data ExtractedPacket = ExtractedPacket 
    { packetName :: String 
    , packetFields :: [ExtractedPacketField] 
    } deriving (Show,Eq) 

instance FromJSON ExtractedPacket where 
    parseJSON = blah 

data ExtractedPacketField = ExtractedPacketField 
    { field1 :: String 
    , field2 :: String 
    } deriving (Show,Eq) 

instance FromJSON ExtractedPacketField where 
    parseJSON = blah 

をそして、次のようなものを得る:

ExtractedPacket 
    "packetX_Name" 
    [ ExtractedPacketField "value1" "value2" 
    , ExtractedPacketField "value3" "value4" 
    , ExtractedPacketField "value5" "value6" 
    ] 

ExtractedPacket 
"packetY_Name" 
    [ ExtractedPacketField "value7" "value8" 
    , ExtractedPacketField "value10" "value10" 
    ] 

このJSONの例では、ネットワークパケットについて説明しています。各パケットの名前は異なります(「packetX _Name ")は、" field1 "または" field2 "と同じ方法で解析できません。毎回違うでしょう。 Aesonの例のほとんどは、このような状況になるとかなり役に立たない。異種の配列を解析している私はStringに一致するwithArrayと呼ばれるAPIドキュメント内の関数を気づいたが、私は(Array -> Parser a)

私は本当にに引っかかってる部分に使用すべきことの失うのだという文字列 "container"で始まり、その中にすべてのオブジェクトを持つ配列があります。これまでのところ、私はオブジェクトの配列に直接索引をつけていましたが、型システムは本当の迷路になり始めました。そして、私は醜くハックされない方法でこれにアプローチするのは本当に難しいと感じました。これに加えて、Aesonは非常に有用なエラーメッセージを生成しません。

これにアプローチする方法についてのご意見はありますか?これらのような、より複雑な例で

答えて

1

、それはアイソーンValueタイプの下に簡単なデータ構造であることを心に留めておくために良いことだ - アレイ用VectorとオブジェクトのためのHashMap。私たちが扱っているリストやマップよりも少しエキゾチックですが、依然としてFoldableTraversableのインスタンスを持つデータ構造です。このことを念頭に置いて、私たちは、これらのインスタンスを宣言することができます。

{-# LANGUAGE OverloadedStrings #-} 

import qualified Control.Lens as Lens 
import qualified Data.Foldable as Foldable 
import qualified Data.Text.Strict.Lens as Lens 
import   Data.Aeson 
import   Data.Aeson.Types 

newtype ExtractedPackets = 
    ExtractedPackets [ExtractedPacket] deriving (Show) 

instance FromJSON ExtractedPackets where 
    parseJSON (Object o) = do 
    let subparsers = 
      [ ExtractedPacket (Lens.view Lens.unpacked key) <$> parseJSON packets 
      | (key, Array values) <- Lens.itoList o 
      , [email protected](Array _) <- Foldable.toList values] 
    packets <- sequence subparsers 
    return (ExtractedPackets packets) 
    parseJSON invalid = 
    typeMismatch "ExtractedPackets" invalid 

instance FromJSON ExtractedPacketField where 
    parseJSON (Object o) = 
    ExtractedPacketField <$> o .: "field1" <*> o .: "field2" 
    parseJSON invalid = 
    typeMismatch "ExtractedPacketField" invalid 

を我々はすでにFromJSON a => FromJSON [a]ためFromJSONインスタンスがありますので、パケットのリストをNEWTYPEする必要があり、それは我々が(それをやりたいしない、具体的には、唯一であります同種のリストを扱うことができる)。

これで、オブジェクト内のハッシュマップを手に入れ、そのキーと値をタプルとしてトラバースすることができます。タプルをマッピングすると、[Parser ExpectedPacket]が生成され、sequenceParser [ExpectedPacket]に変換することができます。私はlensをここで自由に使用しています。パックされた文字列と解凍された文字列の間の変換や、ハッシュマップをキーと値の組に分解することなどです。 lensを引き込みたくない場合は、textunordered-containersパッケージを使用して同じ目標を達成できます。これは、提供された例で動作するようです

λ> eitherDecode bytes :: Either String ExtractedPackets 
Right (ExtractedPackets [ExtractedPacket {packetName = "packetX_Name", 
packetFields = [ExtractedPacketField {field1 = "value1", field2 = 
"value2"},ExtractedPacketField {field1 = "value3", field2 = 
"value4"},ExtractedPacketField {field1 = "value5", field2 = 
"value6"}]},ExtractedPacket {packetName = "packetY_Name", packetFields 
= [ExtractedPacketField {field1 = "value7", field2 = 
"value8"},ExtractedPacketField {field1 = "value9", field2 = 
"value10"}]}]) 

最後に、私はしばしばtypeMismatcheitherDecodeを使用してアイソーンインスタンスをデバッグするための途方もなく有用であることがことがわかります。

+0

ええ、これは私のためにも機能します。ありがとうございました!それは私がこれまで見てきたリスト内包表記のよりクールな使用の1つです。以前はVectorsやHashMapsを使っていましたが、デバッグが難しい方法でValueを推測することができました。 – carpemb

関連する問題