2015-11-06 57 views
1

解碼/編碼:YAML庫不解碼什麼它編碼

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相同的代碼工作正常,那裏我只是不明白什麼是可能的錯誤?

+1

,也許這是一個這個愚蠢行結束事情 - YAML文件是怎麼樣的?你可以嘗試複製並粘貼到一個新的文件(在Linux上)並重試? – Carsten

+0

@Carsten複製和粘貼不起作用,即使我從Windows複製配置,但確定'[]'配置工作/ btw目前不確定,但看起來像Windows正在使用'LF'和linux在那裏使用'CRLF':S – Cynede

+0

' []'如同空文件一樣? ...真的很難說,如果你不給我們提供關於文件和你最終解碼到的類型的更多細節 – Carsten

回答

3

Nothing的情況下,最好通過使用decodeEither/decodeEither'來獲取更多信息。任一值的左側將包含一條錯誤消息,告訴您發生故障的位置。如果切換,則會看到由於error "Can't parse Repository from YAML"一行而導致解析失敗(請參閱下面的attempt1)。它除了一個對象外還遇到了一些東西!

最好再看看YAML包解碼到底是什麼,然後解碼到我們知道必須成功的類型 - Value。解碼,我們得到這個(見下文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)])])) 

看來根數據結構是一個數組,而不是一個對象。有很多方法可以解決這個問題,我選擇了一個黑客。

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) 
+0

我的實際錯誤有'未能解析字段啓用:期望布爾,遇到空' – Cynede

+0

,我仍然不確定它是什麼原因:/錯誤與maybies? – Cynede

+0

https://hackage.haskell.org/package/aeson-0.10.0.0/docs/src/Data-Aeson-Types-Instances.html - 應該是相關的,但現在不能挖掘到實際問題 – Cynede