我很难理解这一点(我对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
的实例,但我不知道从那里去哪里。
非常感谢任何指示,谢谢!
答案 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
转换为Value
。 fromJSON
上的Value
调用尝试将其解析为您的记录。请注意,这两个步骤涉及两个不同的解析器,Data.Attoparsec.Parser
解析器用于将ByteString
转换为通用JSON Value
,然后转换为Data.Aeson.Types.Parser
解析器以转换JSON价值成记录。请注意,这两个步骤都可能失败:
ByteString
不是有效的JSON值,则第一个解析器可能会失败。fromJSON
实现中提到的某个字段,则第二个解析器可能会失败。 aeson包将新的Unicode类型Text
(在text包中定义)更喜欢更旧的学校String
类型。 Text
类型具有比String
更高的内存效率,并且通常表现更好。我建议您将Tweet
类型更改为使用Text
而不是String
。
如果您需要在String
和Text
之间进行转换,请使用pack
中定义的unpack
和Data.Text
函数。请注意,此类转换需要O(n)时间,因此请尽可能避免使用它们(即始终使用Text
)。
答案 1 :(得分:14)
您需要为您的类型编写showJSON
和readJSON
方法,以JSON格式构建Haskell值。 JSON包将负责将原始字符串解析为JSValue
。
您的推文最多可能是包含字符串映射的JSObject
。
show
查看JSObject,了解字段的布局方式。get_field
上的JSObject
查找每个字段。 fromJSString
从JSString
获取常规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编码的示例实例答案 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.Generic
和decodeJSON
:http://hpaste.org/41263/parsing_json_with_textjson