解析JSON值

时间:2015-10-27 18:11:34

标签: frege

假设我有以下结构:

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
        ] 

到目前为止,我可以将Lang实例转换为JSON:

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

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

但我无法弄清楚如何实施相反的操作:

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

我首先阅读了文档,但我担心在这种情况下仍然无法使用fromJSON并使用模式匹配:(

2 个答案:

答案 0 :(得分: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
    _                       -> "" 

2015年10月28日更新

就像评论中提到的Ingo一样。我应该添加fromJSON _ =...答案以完成这个答案,否则编译器会警告我的函数的可反复性。

答案 1 :(得分: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!!!"