2017-10-17 3 views
1

I die unglücklichen Daten zu arbeiten:Aeson mit Arrays von Arrays, von denen einige leer sind

{ "name": "foo" 
, "data": [ [] 
      , ["a", "b", "c", 1] 
      , ["d", "e", "f", 2] ] } 

Die Dateneingaben erlaubt sind entweder leer Array oder ein Array der Größe vier sein.

Dass ich in analysieren wollen:

data ResultRow = ResultRow Text Text Text Int deriving (Show, Generic) 

data ResultSet = 
    ResultSet { f_name :: Text 
      , f_data :: [Maybe ResultRow] } deriving (Show, Generic) 

Die folgenden jedoch nicht die leeren Felder akzeptiert:

customOptions = defaultOptions { fieldLabelModifier = drop 2 } 

instance FromJSON ResultRow where 
    parseJSON = genericParseJSON customOptions 
instance FromJSON ResultSet where 
    parseJSON = genericParseJSON customOptions 

Die Fehlermeldung lautet:

Left "Error in $[1].data[0]: When expecting a product of 4 values, encountered an Array of 0 elements instead" 

Ich habe auch versucht, einen zusätzlichen Typ um [Maybe ResultRow] und haben, dass die Sub-Arrays zu Listen und Pat konvertieren tern Match auf [], und senden Sie die nicht leere Fall an die ResultRow Parser, aber ich konnte einfach nicht zu kompilieren und ging verloren in den Fehlermeldungen.

Idealerweise hätte ich gerne eine Möglichkeit, die leeren Arrays zu überspringen, da sie nur Rauschen in den Daten sind. Ich habe keine Kontrolle über den Hersteller der Daten.

+2

in diesem Fall würde ich nicht den generischen JSON-Parser verwenden, stattdessen würde ich es selbst mit den Kombinatoren von AESON schreiben! – epsilonhalbe

+0

Willst du damit sagen, dass dies mit dem generischen JSON-Parser unmöglich/nicht durchführbar ist oder du einfach nicht weißt, wie man es macht und daher die Kombinatoren in einem Kommentar und nicht in einer Antwort empfehlen? Haben Sie Lesematerial, das nahe legt, dass Sie ähnliche In-Daten wie ich mit den von Ihnen erwähnten Kombinatoren untersuchen? – dsvensson

+0

versuche vielleicht [ResultRow] anstelle von [Maybe ResultRow] – madnight

Antwort

2

Wie dsvensson, ich bin verwirrt, dass diese ‚funktioniert nur‘ aus der Box nicht, da beide [a] und Maybe a sind FromJSON Fälle, in denen a ist. Da ich am Ende viel zu viel Zeit damit verbracht habe, kann ich keine Erklärung anbieten, aber ich kann einen Workaround anbieten. Hoffentlich kann jemand, der besser informiert ist, eine bessere Antwort geben.

Statt f_data als [Maybe ResultRow] definieren, können Sie eine newtype definieren, die Maybe ResultRow wickelt:

newtype MaybeResultRow = MaybeResultRow (Maybe ResultRow) deriving (Show, Generic) 

Sie diese Art besondere FromJSON Verhalten geben kann:

instance FromJSON MaybeResultRow where 
    parseJSON v = 
    case fromJSON v of 
     Success rr -> return $ MaybeResultRow $ Just rr 
     _   -> return $ MaybeResultRow Nothing 

Dies ist offensichtlich, impliziert ein Änderung von ResultSet:

data ResultSet = 
    ResultSet { f_name :: Text 
      , f_data :: [MaybeResultRow] } deriving (Show, Generic) 

Um zu testen, definiert ich dieses JSON-Dokument:

myJson :: ByteString 
myJson = 
    "{\ 
    \\"name\": \"foo\",\ 
    \\"data\": [\ 
     \[],\ 
     \[\"a\", \"b\", \"c\", 1],\ 
     \[\"d\", \"e\", \"f\", 2]\ 
    \]\ 
    \}" 

alles in GHCi Laden, es sieht aus wie es funktioniert:

*Lib Lib> decode myJson :: Maybe ResultSet 
Just (ResultSet { 
      f_name = "foo" 
     , f_data = [ 
        MaybeResultRow Nothing, 
        MaybeResultRow (Just (ResultRow "a" "b" "c" 1)), 
        MaybeResultRow (Just (ResultRow "d" "e" "f" 2))]}) 

Hier habe ich die Freiheit genommen habe zu formatieren die Ausgabe von GHCi, um die Lesbarkeit zu verbessern.

Ich vertraue darauf, dass Sie herausfinden können, wie die Liste der MaybeResultRow Werte auszupacken und filtern ...

stahl ich die Lösung von fromJSON und die Anpassung an Success von this answer verwenden.

Verwandte Themen