如何从Json file.Json结构中提取信息必须通过类型映射并使用AESON

时间:2018-06-10 08:49:19

标签: json haskell aeson

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

我需要Extract“main”信息。我有类型MainWeatherInfo。这个代码是编译的。但是在启动过程中我收到了这个“错误”。如何解决此问题并获取正常信息?

1 个答案:

答案 0 :(得分:0)

问题是 aeson 正在文件中寻找名为 mainInfo 的字段,但这样的字段不存在。

最初我认为我们可以通过将 MainWeatherInfo 的类型定义中的 mainInfo 更改为 main 来解决问题。这不起作用,因为已存在具有相同名称的函数!

aeson 提供了一种解决方法,您可以在泛型:自定义字段名称部分的this helpful tutorial中找到说明。

更具体地说,如果你使用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
             )

我测试它只是为了确定,并且它有效。