2011-05-22 35 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)。