在Jaskell中将JSON字符串解析为记录

时间:2011-05-22 20:31:18

标签: json parsing haskell

我很难理解这一点(我对Haskell仍然有点新意)但我发现Text.JSON包的文档有点令人困惑。基本上我有这种数据记录类型: -

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的实例,但我不知道从那里去哪里。

非常感谢任何指示,谢谢!

5 个答案:

答案 0 :(得分:25)

我建议您使用新的aeson软件包而不是json软件包,因为前者的性能要好得多。以下是使用aeson:

将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转换为ValuefromJSON上的Value调用尝试将其解析为您的记录。请注意,这两个步骤涉及两个不同的解析器,Data.Attoparsec.Parser解析器用于将ByteString转换为通用JSON Value,然后转换为Data.Aeson.Types.Parser解析器以转换JSON价值成记录。请注意,这两个步骤都可能失败:

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

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

如果您需要在StringText之间进行转换,请使用pack中定义的unpackData.Text函数。请注意,此类转换需要O(n)时间,因此请尽可能避免使用它们(即始终使用Text)。

答案 1 :(得分:14)

您需要为您的类型编写showJSONreadJSON方法,以JSON格式构建Haskell值。 JSON包将负责将原始字符串解析为JSValue

您的推文最多可能是包含字符串映射的JSObject

  • 使用show查看JSObject,了解字段的布局方式。
  • 您可以使用get_field上的JSObject查找每个字段。
  • 您可以使用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编码的例子,我可以提供更多建议。


相关

您可以通过实例

找到JSON编码的示例实例
  • in the source,for 简单的类型。或者在依赖于json的其他包中。
  • AUR消息is here的实例,作为(低级别)示例。

答案 2 :(得分:5)

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

答案 3 :(得分:1)

我支持@tibbe的回答。 但是,我想添加“如何检查”中放置一些默认值,以防万一参数在提供的JSON中丢失。

在tibbe的答案中,您可以执行以下操作:

Tweet <$> v .: "from_user"
      <*> v .:? "to_user_id"       .!= "some user here"
      <*> v .: "profile_image_url" .!= "url to image"
      <*> v .: "created_at"
      <*> v .: "id_str"             != 232131
      <*> v .: "source"

这将是在解析JSON时要使用的dafault参数。

答案 4 :(得分:0)

以下是Text.JSON.GenericdecodeJSONhttp://hpaste.org/41263/parsing_json_with_textjson

的示例