2016-02-15 20 views
5

Aşağıdaki JSON pasajı vardır: Ben ondan şu tip ayrıştırmak almak istiyorumBu JSON'u Aeson ile nasıl ayrıştırırım?

{ 
    "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 
} 

:

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

bunu yapmak için aşağıdaki kodu kullanmaya çalışıyorum ama hatalara koşmaya devam et. Sonunda bütün türlerin eşleşmesini sağladım, ama yanlış bir şekilde ayrıştırıyor ve nerede başarısız olduğunu gerçekten anlamıyor.

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

Sadece aşağıdaki çıktıyı alıyorum ki, nerede yanlış gittiğimi bilmeme yetmiyor.

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

Ben kodu ile sorunun ne bilmek istiyorum here

görüntülenebilir bir ve özü tüm şey koyduk ve bunu nasıl çözebileceğinizi. Bunu daha okunabilir bir şekilde nasıl yazacağınıza dair önerileriniz varsa bunu da bilmek isterim. Şu anda çoğunlukla iki ayrı fonksiyonla rahatsızım (lambda3 ve parseInner can sıkıcıdır)

+0

, bu yüzden 'lambda3 olmalıdır:

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

Bu çıkış var: Böyle bir şey çalışması gerekir = withObject "weatherMain" (.: "main") '. – zakyggaps

cevap

4

Bence bunu çok karmaşık hale getiriyorsunuz. Eğer bir nesnedir `weather` dizideki ilk elemanı var V.head`` By

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