2017-10-30 10 views
0

를 필터링, 다음과 같은 JSON 제공 :하스켈 아이손 JSON은 아이손 JSON Hackage와 하스켈을 사용하여 잘못된 문자

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

FromJson 인스턴스를 구현하는 beste 방법은 무엇입니까? 나는 instance FromJSON Rates 모두 가능성을 정의

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

:

현재 나는이 있습니다. 좀 더 일반적인 방법으로 시도했지만 data 부분에 '불법'문자 인 #을 사용할 수 없습니다.

그래서이 경우에는 두 개의 성가신 필드 만 있습니다. 그러나 이것을 확장하고 성가신 여러 문자 (#, @, - 등)를 얻으려면 모든 필드를 정의해야합니까? 또는 똑같은 목표를 달성하기위한 더 똑똑하고 빠른 방법이 있습니까?

+0

나는 ghci (+ overloadedstrings)에서'let x :: Maybe Conversion = decode "{\"base \ "base \", rate \ ": {\"# USD \ ": 1, \"# EUR \ ": 2}}" "귀하의 인스턴스와 함께. – epsilonhalbe

+1

표준이 아닌 json을 사용한다면 - 직접'parseJSON' 인스턴스 선언을 작성해야합니다. json을 직접 정의하는 경우 # @ 등과 같이 "이상한"필드 접근자를 추가하지 않고 대시 구문을 사용하여 일반적인 소문자를 사용합니다. – epsilonhalbe

+0

@epsilonhalbe 절대적으로 사실입니다. 불행히도 네덜란드 날씨 예보 사이트는 "이상한"필드 접근을 사용하고 있습니다. ** Mateusz Kowalczyk ** 님이 제공 한 답변을 사용하면 내 문제를 해결할 수 있습니다. 감사합니다. :) – Viletung

답변

0

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) 

우리는 그냥 당신이 이제까지 당신의 유형 ToJSON 인스턴스를 정의하면 같은 아이손 옵션을 사용하는 것을 기억

[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 
    } 
} 

를 얻을!