解码/编码:
yDecode :: FromJSON iFromJSONable ⇒ FilePath → IO iFromJSONable
yDecode fnm = do
ymlData ← BS.readFile fnm
return $ fromMaybe (error "Can't parse from YAML") (decode ymlData)
yEncode :: ToJSON iToJSONable ⇒ FilePath → iToJSONable → IO()
yEncode fnm dat = BS.writeFile fnm $ encode dat
我用这个编码创建配置并且它创建得很好但是当我正在阅读它时 - 我收到此错误:Can't parse from YAML
- 在Windows上相同的代码工作正常并且在那里我只是无法理解是什么可能是错的?
答案 0 :(得分:3)
如果是Nothing
,最好使用decodeEither
/ decodeEither'
获取更多信息。任一值的左侧都将包含一条错误消息,告诉您发生故障的位置。如果您切换,您会看到解析因error "Can't parse Repository from YAML"
行而失败(请参阅下面的attempt1
)。它遇到的东西除了一个对象!
然后最好通过解码到我们知道必须成功的类型 - 值来看看YAML包解码到底是什么。解码,我们得到这个(见下面的attempt2
):
Right (Array (fromList [Object (fromList [("group",Null),("branches",Array (fromList [String "master"])),("hash",Null),("clean",Null),("location",String "/home/gentoo-haskell"),("enabled",Null),("root",Null),("postRebuild",Null),("upstream",String "upstream master"),("task",String "rebase"),("positive",Null)])]))
根数据结构似乎是一个数组,而不是一个对象。有很多方法可以解决这个问题,我选择了一个hacky。
parseJSON (Array array) = parseJSON (array ! 0)
这使程序工作!我粘贴了下面的代码。 (使用镜头的道歉;我用它来在字符串和字节串之间进行转换,以获得像这样的快速脚本。如果没有它,你的程序当然可以正常工作。)
{-# LANGUAGE OverloadedStrings #-}
module Lib where
import Control.Lens
import Data.ByteString
import Data.ByteString.Lens
import Data.Vector
import Data.Yaml
data Repository = Repository
{ location :: String
, task :: String
, branches :: [String]
, upstream :: String
, enabled :: Maybe Bool
, root :: Maybe Bool
, positive :: Maybe Bool
, clean :: Maybe Bool
, postRebuild :: Maybe [String]
, syncGroup :: Maybe String
, hash :: Maybe String
} deriving (Show, Eq)
instance FromJSON Repository where
parseJSON (Object v) = Repository <$>
v .: "location" <*>
v .: "task" <*>
v .: "branches" <*>
v .: "upstream" <*>
v .:? "enabled" <*>
v .:? "root" <*>
v .:? "positive" <*>
v .:? "clean" <*>
v .:? "postRebuild" <*>
v .:? "group" <*>
v .:? "hash"
parseJSON (Array array) = parseJSON (array ! 0)
raw :: String
raw = unlines [
"- group: null",
" branches:",
" - master",
" hash: null",
" clean: null",
" location: /home/gentoo-haskell",
" enabled: null",
" root: null",
" postRebuild: null",
" upstream: upstream master",
" task: rebase",
" positive: null"]
attempt1 :: Either ParseException Repository
attempt1 = decodeEither' (raw ^. packedChars)
attempt2 :: Either ParseException Value
attempt2 = decodeEither' (raw ^. packedChars)