Haskell Aeson JSON,过滤掉非法字符

时间:2017-10-30 11:38:35

标签: json parsing haskell instance aeson

将Haskell与Aeson JSON Hackage一起使用,并给出以下JSON:

{
    "base": "GBP",
    "date": "2017-10-27",
    "rates": {
        "#USD": 1.3093,
        "#EUR": 1.1282
    }
}

实施FromJson实例的最佳方式是什么?

目前我有这个:

{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

import GHC.Generics
import Data.Aeson

data Conversion = Conversion {
  base :: String,
  rates  :: Rates }
  deriving (Show, Generic)

data Rates = Rates {
  eur :: Float,
  usd :: Float }
  deriving (Show, Generic)

instance FromJSON Conversion
instance FromJSON Rates where
  parseJSON (Object o) = trace ( show(o)) Rates <$> o .: "#USD" <*> o .: "#EUR"

我在instance FromJSON Rates中定义了两种可能性。我尝试用更通用的方式来做,但是非法的&#39; #部分中不允许使用字符data

所以在这种情况下我只有两个烦人的领域。但是如果我想扩展它并获得多个讨厌的字符(#,@, - 等),我是否必须定义每个字段?或者有更智能,更快捷的方法来实现同样的目标吗?

1 个答案:

答案 0 :(得分:1)

您可以使用fieldLabelModifier并使用您自己的字段替换有问题的字段来处理此问题。这使您可以选择修改哪些名称,如果您的大型记录只有几个奇怪命名的字段,而这些字段无法直接放入您的类型中,那么这些名称非常有用。

{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where

import           Data.Aeson
import           Data.Aeson.Types
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Map.Strict as M
import           GHC.Generics
import           System.Environment (getArgs)

data Conversion = Conversion
  { base :: String
  , rates  :: Rates
  } deriving (Show, Generic)

newtype USD = USD Float
newtype EUR = EUR Float

data Rates = Rates
  { eur :: Float
  , usd :: Float
  }
  deriving (Show, Generic)

instance FromJSON Conversion

instance FromJSON Rates where
  parseJSON = genericParseJSON opts
    where
      fields = M.fromList
        [("usd", "#USD"), ("eur", "#EUR")]
      opts = defaultOptions
        { fieldLabelModifier = \s -> M.findWithDefault s s fields }

main :: IO ()
main = do
  [file] <- getArgs
  decode <$> BSL.readFile file >>= \case
    Nothing -> putStrLn "Parse failed!"
    Just conversion -> print (conversion :: Conversion)

有了这个我们得到

[nix-shell:/tmp]$ ./T /tmp/rates.json
Conversion {base = "GBP", rates = Rates {eur = 1.1282, usd = 1.3093}}

[nix-shell:/tmp]$ cat /tmp/rates.json
{
  "base": "GBP",
  "date": "2017-10-27",
  "rates": {
    "#USD": 1.3093,
    "#EUR": 1.1282
  }
}

如果您为类型定义ToJSON个实例,请记住使用相同的Aeson选项!