Haskell爱生JSON,过滤掉非法字符
Haskell Aeson JSON, filter out illegal characters
将 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
中定义了两种可能性。我尝试用更通用的方式来做到这一点,但是 'illegal' 字符 #
在 data
部分中是不允许的。
所以在这种情况下,我只有两个烦人的字段。但是如果我想扩展它并获得多个烦人的字符(#、@、- 等),我是否必须定义每个字段?还是有更聪明、更快捷的方法来实现同样的目标?
您可以使用 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 选项!
将 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
中定义了两种可能性。我尝试用更通用的方式来做到这一点,但是 'illegal' 字符 #
在 data
部分中是不允许的。
所以在这种情况下,我只有两个烦人的字段。但是如果我想扩展它并获得多个烦人的字符(#、@、- 等),我是否必须定义每个字段?还是有更聪明、更快捷的方法来实现同样的目标?
您可以使用 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 选项!