2016-02-15 16 views
5

Ho il seguente frammento di codice JSON:Come analizzare questo JSON con Aeson?

{ 
    "weather": [ 
    { 
     "id": 803, 
     "main": "Clouds", 
     "description": "broken clouds", 
     "icon": "04n" 
    } 
    ], 
    "main": { 
    "temp": 271.979, 
    "pressure": 1024.8, 
    "humidity": 100, 
    "temp_min": 271.979, 
    "temp_max": 271.979, 
    "sea_level": 1028.51, 
    "grnd_level": 1024.8 
    }, 
    "id": 6332485, 
    "name": "Queensbridge Houses", 
    "cod": 200 
} 

voglio ottenere analizzare il seguente tipo da esso:

data WeatherResponse = WeatherResponse 
    { temp :: Double 
    , humidity :: Double 
    , weatherMain :: T.Text 
    } deriving Show 

Ho cercato di utilizzare il seguente codice per farlo, ma io continua a incorrere in errori. Ho finalmente ottenuto tutti i tipi per abbinare, ma analizza in modo errato e non capisco davvero dove sta fallendo.

{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE RecordWildCards #-} 
{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Aeson 
import Data.Aeson.Types (Parser, Array) 
import Data.Time (defaultTimeLocale, formatTime, getZonedTime) 

import qualified Data.ByteString.Lazy as BL 
import qualified Data.Vector as V 
import qualified Data.Text as T 

data WeatherResponse = WeatherResponse 
    { temp :: Double 
    , humidity :: Double 
    , weatherMain :: T.Text 
    } deriving Show 

lambda3 :: Value -> Parser T.Text 
lambda3 o = do 
    withText "main" (\t -> do 
         return t 
       ) o 

parseInner :: Value -> Parser T.Text 
parseInner a = withArray "Inner Array" (lambda3 . (V.head)) a 

instance FromJSON WeatherResponse where 
    parseJSON = 
    withObject "Root Object" $ \o -> do 
    mainO <- o .: "main" 
    temp <- mainO .: "temp" 
    humidity <- mainO .: "humidity" 
    weatherO <- o .: "weather" 
    weatherMain <- parseInner weatherO 
    return $ WeatherResponse temp humidity weatherMain 

getSampleData = BL.readFile "/home/vmadiath/.xmonad/weather.json" 

main = do 
    text <- getSampleData 
    let (result :: Either String WeatherResponse) = eitherDecode text 
    putStrLn . show $ result 

Ho semplicemente ottenuto il seguente output che non mi dà abbastanza sapere dove ho sbagliato.

$ runhaskell lib/code.hs 
Left "Error in $: expected main, encountered Object" 

ho messo l'intera cosa in una sostanza visibile here

Mi piacerebbe sapere che cosa c'è di sbagliato con il codice, e come posso risolvere il problema. Se hai suggerimenti su come scriverlo in un modo più leggibile, mi piacerebbe saperlo anche io. Attualmente sono per lo più infastidito dalle due funzioni separate lambda3 e parseInner è fastidioso)

+0

da 'V.head' hai avuto il primo elemento della matrice' weather' che è un oggetto, quindi dovrebbe essere 'Lambda3 = withObject "weatherMain" (.: "main") '. – zakyggaps

risposta

4

A mio parere, lo stai rendendo troppo complicato. Qualcosa del genere dovrebbe funzionare:

instance FromJSON WeatherResponse where 
    parseJSON (Object v) = do 
     weatherValue <- head <$> v .: "weather" 
     WeatherResponse <$> ((v .: "main") >>= (.: "temp")) 
          <*> ((v .: "main") >>= (.: "humidity")) 
          <*> weatherValue .: "main" 

E 'uscita:

[nix-shell:~/haskell-sample]$ ./weather 
Right (WeatherResponse {temp = 271.979, humidity = 100.0, weatherMain = "Clouds"})