2011-05-22 83 views
18

我很努力地理解这一点(我对Haskell仍然有点新),但是我发现Text.JSON包的文档有点令人困惑。基本上我有这样的数据记录类型: -解析JSON字符串到Haskell的记录

data Tweet = Tweet 
    { 
     from_user :: String, 
     to_user_id :: String, 
     profile_image_url :: String, 
     created_at :: String, 
     id_str :: String, 
     source :: String, 
     to_user_id_str :: String, 
     from_user_id_str :: String, 
     from_user_id :: String, 
     text :: String, 
     metadata :: String 
    } 

和我有一些JSON格式的推文符合这种类型的结构。我正在努力的事情是如何映射上述从以下代码返回的内容

decode tweet :: Result JSValue 

转换成上述数据类型。我知道我应该创建一个instance JSON Tweet的实例,但我不知道该从哪里去。

任何指针将不胜感激,谢谢!

回答

14

您需要为您的类型编写一个showJSONreadJSON方法,该方法将您的Haskell值从JSON格式中构建出来。 JSON包将负责为您解析原始字符串到JSValue

您的推文将是一个JSObject包含最有可能的字符串的地图。

  • 使用show查看JSObject,看看这些字段是如何布置的。
  • 您可以在JSObject上使用get_field查找每个字段。
  • 您可以使用fromJSStringJSString获取常规Haskell字符串。

从广义上讲,你需要这样的东西,

{-# LANGUAGE RecordWildCards #-} 

import Text.JSON 
import Text.JSON.Types 

instance JSON Tweet where 

    readJSON (JSObject o) = return $ Tweet { .. } 
      where from_user   = grab o "from_user" 
        to_user_id  = grab o "to_user_id" 
        profile_image_url = grab o "proile_image_url" 
        created_at  = grab o "created_at" 
        id_str   = grab o "id_str" 
        source   = grab o "source" 
        to_user_id_str = grab o "to_user_id_str" 
        from_user_id_str = grab o "from_user_id_str" 
        from_user_id  = grab o "from_user_id" 
        text    = grab o "text" 
        metadata   = grab o "metadata" 


grab o s = case get_field o s of 
       Nothing   -> error "Invalid field " ++ show s 
       Just (JSString s') -> fromJSString s' 

注意,我使用的是相当清凉百搭牌语言的扩展。

没有JSON编码的例子,我没有更多的建议。


相关

您可以通过实例

  • in the source找到一个JSON编码的例子的情况下,对于 简单类型。或者在依赖于json的其他软件包中。
  • 作为(低级别)示例的AUR消息is here的实例。
+3

精湛,感谢您的工作一种享受了详细的答复。有没有什么办法可以与软件包作者交谈,以便或许在文档中加入这样的例子(很明显可以相信)? – djhworld 2011-05-23 07:50:57

5

导入Data.JSon.Generic和Data.Data,然后将派生(Data)添加到您的记录类型,然后尝试在推文上使用decodeJSON。

+0

我试图做到这一点,但无法找到'Data.JSon.Generic'。你能指出我吗? – 2012-01-04 15:34:26

+0

他可能是指Data.Aeson.Generic:http://hackage.haskell.org/packages/archive/aeson/0.6.0.2/doc/html/Data-Aeson-Generic.html – 2012-08-14 23:55:05

25

我建议您使用新的aeson包而不是json包,因为前者性能更好。这里是你怎么会一个JSON对象转换为Haskell的记录,使用埃宋:

{-# LANGUAGE OverloadedStrings #-} 
module Example where 

import Control.Applicative 
import Control.Monad 
import Data.Aeson 

data Tweet = Tweet { 
    from_user :: String, 
    to_user_id :: String, 
    profile_image_url :: String, 
    created_at :: String, 
    id_str :: String, 
    source :: String, 
    to_user_id_str :: String, 
    from_user_id_str :: String, 
    from_user_id :: String, 
    text :: String, 
    metadata :: String 
    } 

instance FromJSON Tweet where 
    parseJSON (Object v) = 
     Tweet <$> v .: "from_user" 
       <*> v .: "to_user_id" 
       <*> v .: "profile_image_url" 
       <*> v .: "created_at" 
       <*> v .: "id_str" 
       <*> v .: "source" 
       <*> v .: "to_user_id_str" 
       <*> v .: "from_user_id_str" 
       <*> v .: "from_user_id" 
       <*> v .: "text" 
       <*> v .: "metadata" 
    -- A non-Object value is of the wrong type, so use mzero to fail. 
    parseJSON _   = mzero 

然后使用Data.Aeson.json获得attoparsec解析器,一个ByteString转换为Value。请致电fromJSONValue尝试将其解析到您的记录中。请注意,在这两个步骤中涉及两个不同的解析器,Data.Attoparsec.Parser解析器,用于将ByteString转换为通用JSON Value,然后用于将JSON值转换为记录的解析器。请注意,这两个步骤可能会失败:

  • 如果ByteString不是有效的JSON值,则第一个解析器可能会失败。
  • 如果(有效)JSON值不包含您在fromJSON实现中提到的某个字段,那么第二个解析器可能会失败。

的埃宋包喜欢新的Unicode类型Text(在text包中定义)与更老学校String类型。 Text类型比String具有更高的内存有效表示,并且性能通常更好。我建议您将Tweet类型更改为使用Text而不是String

如果你需要StringText之间的转换,使用Data.Text定义的packunpack功能。请注意,此类转换需要O(n)个时间,因此尽可能避免这些转换(即始终使用Text)。