2016-02-15 10 views
5

Ich habe folgenden JSON-Schnipsel:Wie analysiere ich diesen JSON mit 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 
} 

Ich mag von ihm die folgenden Art erhalten analysieren:

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

ich den folgenden Code zu verwenden, habe versucht, es zu tun, aber ich laufe immer wieder in Fehler. Ich habe endlich alle Typen gefunden, aber es analysiert falsch und versteht nicht wirklich, wo es scheitert.

{-# 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 

Ich bekomme einfach die folgende Ausgabe, die mir nicht genug gibt, um zu wissen, wo ich falsch gelaufen bin.

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

Ich habe die ganze Sache in einem Kern sichtbar here

setze Ich mag würde wissen, was mit dem Code falsch ist, und wie ich es beheben kann. Wenn Sie Vorschläge haben, wie Sie dies lesbarer schreiben können, würde ich das auch gerne wissen. Momentan bin ich meistens genervt mit den beiden separaten Funktionen lambda3 und parseInner nervt)

+0

von 'V.head' Sie das erste Element in der' weather' Array bekam, die ein Objekt ist, so soll es sein 'Lambda3 = withObject "weatherMain" (.: "main") '. – zakyggaps

Antwort

4

Meiner Meinung nach machen Sie das zu kompliziert. So etwas sollte funktionieren:

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

Es ist Ausgabe:

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