Как извлечь информацию из файла Json. Структура Json должна быть отображена через тип и использовать AESON - PullRequest
0 голосов
/ 10 июня 2018
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

module Main where

import           Data.Aeson
import           Data.Aeson.Encode.Pretty
import           Data.Aeson.Types
import           Data.ByteString as B
import qualified Data.ByteString.Lazy.Char8 as LC
import           GHC.Generics
import           Data.Text

data MainWeatherInfo = MainWeatherInfo
    { mainInfo :: Main
    } deriving (Show,Generic)

data Main = Main
    { temp :: Double
    , pressure :: Int
    , humidity :: Int
    , temp_min :: Double
    , temp_max :: Double
    } deriving (Show,Generic)

instance FromJSON MainWeatherInfo
instance FromJSON Main

main :: IO ()
main = do
  jsonString <- B.readFile "/home/ashot/test.json"
  let result = decodeStrict $ jsonString :: Maybe MainWeatherInfo
  case result of
    Nothing      -> print "error"
    Just result  -> print result

И JSON-файл:

{
    "coord": {
        "lon": 44.51,
        "lat": 40.18
    },
    "weather": [{
        "id": 500,
        "main": "Rain",
        "description": "light rain",
        "icon": "10d"
    }],
    "base": "stations",
    "main": {
        "temp": 299.15,
        "pressure": 1008,
        "humidity": 34,
        "temp_min": 299.15,
        "temp_max": 299.15
    },
    "visibility": 10000,
        "wind": {
        "speed": 1.5,
        "deg": 190
    },
    "rain": {
        "3h": 0.195
    },
    "clouds": {
        "all": 8
    },
    "dt": 1528615800,
    "sys": {
        "type": 1,
        "message": 0.0036,
        "country": "AM",
        "sunrise": 1528594331,
        "sunset": 1528648255
    },
    "id": 616052,
    "name": "Yerevan",
    "cod": 200
}

Мне нужно извлечь "основную" информацию. И у меня есть тип MainWeatherInfo. Этот код скомпилирован. Но во время запуска я получаю эту "ошибку".Как я могу это исправить и получить нормальную информацию?

1 Ответ

0 голосов
/ 10 июня 2018

Проблема в том, что aeson ищет в файле поле с именем mainInfo , но такого поля не существует.

Сначала я думал, что мы могли быустранить проблему, изменив mainInfo в определении типа для MainWeatherInfo на main .Это не сработает, потому что функция с таким именем уже существует!

aeson предоставляет выход из этого, и вы можете найти описание в этот полезный урок в разделе Generics: настройка имен полей .

Просто чтобы быть более конкретным, если вы используете метод turorial, вы получите Main.hs , который выглядит следующим образом:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

module Main where

import GHC.Generics
import Data.Aeson
import Data.Aeson.Types
import qualified Data.ByteString as L

data MainWeatherInfo = MainWeatherInfo
  { mainInfo :: Main
  } deriving ( Show
             , Generic
             )

instance ToJSON MainWeatherInfo where
  toJSON = genericToJSON defaultOptions { fieldLabelModifier = take 4 }

instance FromJSON MainWeatherInfo where
  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = take 4 }

data Main = Main
  { temp :: Double
  , pressure :: Int
  , humidity :: Int
  , temp_min :: Double
  , temp_max :: Double
  } deriving ( Show
             , Generic
             , ToJSON
             , FromJSON
             )

main :: IO ()
main = do
  contents <- L.readFile "notes/test.json"
  let result = (decodeStrict contents) :: Maybe MainWeatherInfo
  case result of
    Nothing -> putStrLn "error"
    Just v  -> putStrLn $ show v 

Я попробовал его на своем компьютере, и он работал нормально.

ОБНОВЛЕНИЕ: Я был очень глупыми предположил, что решение должно быть ограничено только одним модулем.Вероятно, было бы намного лучше иметь Main.hs , который выглядит как:

module Main where

import Data.Aeson
import qualified Data.ByteString as L
import qualified Weather as W

main :: IO ()
main = do
  contents <- L.readFile "notes/test.json"
  let result = (decodeStrict contents) :: Maybe W.MainWeatherInfo
  case result of
    Nothing -> putStrLn "error"
    Just v  -> putStrLn $ show v 

, а также другой модуль Weather.hs то есть:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

module Weather where

import GHC.Generics
import Data.Aeson
import Data.Aeson.Types

data MainWeatherInfo = MainWeatherInfo
  { main :: Main
  } deriving ( Show
             , Generic
             , ToJSON
             , FromJSON
             )

data Main = Main
  { temp :: Double
  , pressure :: Int
  , humidity :: Int
  , temp_min :: Double
  , temp_max :: Double
  } deriving ( Show
             , Generic
             , ToJSON
             , FromJSON
             )

Я проверил это, просто чтобы убедиться, и оно работает.

...