2017-10-17 13 views
1

j'ai les données malheureux de travailler avec:Aeson avec des tableaux de tableaux, dont quelques-uns sont vides

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

Les données entrées sont autorisées à être soit un tableau vide, ou un tableau de taille quatre.

que je veux analyser dans:

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

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

Voici cependant ne pas accepter les tableaux vides:

customOptions = defaultOptions { fieldLabelModifier = drop 2 } 

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

Le message d'erreur est:

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

J'ai aussi essayé de mettre un type supplémentaire autour de [Maybe ResultRow] et ont que convertir les sous-tableaux en listes et pat tern correspond à [], et envoie le cas non-vide à l'analyseur ResultRow mais je n'ai tout simplement pas pu le compiler et je me suis perdu dans les messages d'erreur.

Idéalement, je voudrais avoir un moyen de sauter les tableaux vides car ils ne sont que du bruit dans les données. Je n'ai aucun contrôle sur le producteur des données.

+2

Dans ce cas, je n'utiliserais pas l'analyseur json générique, mais je l'écrirais moi-même en utilisant les combinateurs d'Aeson! – epsilonhalbe

+0

Etes-vous en train de dire que c'est impossible/irréalisable avec l'analyseur json générique, ou vous ne savez pas comment le faire et donc recommander les combinateurs dans un commentaire plutôt que d'une réponse? Avez-vous du matériel de lecture à suggérer qui explore des données similaires à celles que j'ai, en utilisant les combinateurs que vous mentionnez? – dsvensson

+0

try Peut-être [ResultRow] au lieu de [Maybe ResultRow] – madnight

Répondre

2

Comme dsvensson, je suis perplexe que cela ne «marche tout simplement hors de la boîte, puisque les deux sont des cas FromJSON[a] et Maybe a quand a est. Puisque j'ai déjà passé beaucoup trop de temps sur ceci, je ne peux pas offrir une explication , mais je peux offrir une solution de contournement. Espérons que quelqu'un de mieux informé peut donner une meilleure réponse.

Au lieu de définir f_data comme [Maybe ResultRow], vous pouvez définir une newtype qui enveloppe Maybe ResultRow:

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

Vous pouvez donner ce comportement de type FromJSON spécial:

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

Ceci, évidemment, implique une changement de ResultSet:

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

Afin de tester, je définis ce document JSON:

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

Chargement tout en GHCi, on dirait qu'il travaille:

*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))]}) 

Ici, je me suis permis de formater la sortie de GHCi afin d'améliorer la lisibilité.

Je suis sûr que vous pouvez comprendre comment et déroulez filtrer la liste des valeurs MaybeResultRow ...

J'étole la solution d'utiliser fromJSON et correspondant sur Success de this answer.