2015-10-27 88 views
2

可以說我有以下結構:解析JSON值

import Data.JSON 
import Data.List 

data Lang = Lang { name :: String, 
        desc :: String } 

derive Show Lang 

instance ToJSON Lang where 
    toJSON Lang{name, desc} = 
     Struct [ 
      assoc "name" name, 
      assoc "desc" desc 
     ] 

到目前爲止,我可以把郎實例JSON:

langEn = Lang { name = "en", 
       desc = "english" } 

langEnJSON = toJSON langEn --- produces {"name" : "en", "desc" : "english"} 

但我無法弄清楚如何實施相反操作:

instance FromJSON Lang where 
    fromJSON (Struct fields) = --- 

我第一次讀文檔,但恐怕我還沒有得到如何使用fromJSON並使用拍拍在這種情況下:(燕鷗匹配

回答

1

最後,我想出了這個解決方案:

instance FromJSON Lang where 
fromJSON (Struct fields) 
    | Just name <- lookup "name" fields 
    = case lookup "desc" fields of 
      Just pdesc -> do 
       fname <- fromJSON name 
       fdesc <- fromJSON pdesc 
       return Lang { name = fname, desc = fdesc } 
      Nothing -> do 
       return Lang { name = "", desc = "" } 
    | otherwise = fail "error" 

fromJSON _ = fail "error" --- Updated 28/10/2015 

現在我可以解析輸入字符串,如:

--- returns "english" 
case (parseJSON "{\"name\":\"en\",\"desc\":\"english\"}") of 
    Just Lang {name,desc} -> name 
    _      -> "" 

已更新28/10/2015

像英諾在評論中提到的。我應該添加fromJSON _ =...答案才能完成此答案,否則編譯器會警告我的函數的可糾正性。

+0

看,你有它比我快!請注意編譯器警告:提供一個公式,該公式對於不是Struct的所有內容都是失敗的。否則,你的程序會因輸入錯誤而中止。 (嘗試「[]」) – Ingo

+0

當然,您的答案是我正在尋找的解決方案:-)我仔細看看您的評論和答案,然後編輯我的答案以添加您的建議。謝謝Ingo。 –

+0

你的問題變成了一個重要的點rgd。文檔 - 它沒有提到例子中的「fields」函數,但它應該。我首先寫了文檔(經常推薦),後來在我看來,「field」(這只是Data.List.lookup的一個小泛化,加上來自應用於找到的值的JSON)可能非常有用。所以我也會將它包含在文檔中。 – Ingo

1

下面應該工作:

instance FromJSON Lang where 
    fromJSON v = case v of 
    Struct s → do 
      name ← field "name" s 
      desc ← field "desc" s 
      return Lang{name, desc} 
    _ → fail ("expected {\"name\" : ..., \"desc\" : ...}, found " ++ show v) 

注意,這樣使得一些輸入,如:

{"name" : "pl", "desc" : "polskij", "script" : "latin"} 

如果你想成爲迂腐,你還可滿足下面的Struct關聯列表更明確地說:

fromJSON (Struct s) = case sort s of 
    [("desc", desc), ("name", name)] -> do 
     sname <- fromJSON name 
     sdesc <- fromJSON desc 
     return Lang{name=sname, desc=sdesc} 
    _ -> fail "extra or missing fields" 
fromJSON _ = fail "I want a struct!!!"