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

djh*_*rld 19 parsing json 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
    }
Run Code Online (Sandbox Code Playgroud)

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

decode tweet :: Result JSValue
Run Code Online (Sandbox Code Playgroud)

进入上面的数据类型.我明白我应该创建一个实例,instance JSON Tweet但我不知道从那里去哪里.

任何指针都将非常感谢,谢谢!

tib*_*bbe 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
Run Code Online (Sandbox Code Playgroud)

然后使用Data.Aeson.json获取将a转换为a 的attoparsec解析器.该呼叫在试图解析它变成你的记录.请注意,这两个步骤涉及两个不同的解析器,一个用于转换为通用JSON 的解析器,另一个用于将JSON值转换为记录的解析器.请注意,这两个步骤都可能失败ByteStringValuefromJSONValueData.Attoparsec.ParserByteStringValueData.Aeson.Types.Parser

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

aeson包更喜欢新的Unicode类型Text(在文本包中定义)到更旧的学校String类型.该Text类型具有更高的内存效率表示,String并且通常表现更好.我建议您更改Tweet要使用的类型Text而不是String.

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


Don*_*art 14

你需要写一个showJSONreadJSON方法,为你的类型,建立你的Haskell值了JSON格式.JSON包将负责将原始字符串解析为a JSValue.

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

  • 使用show看JSObject,看场的布局方式.
  • 您可以使用查找每个字段get_fieldJSObject.
  • 您可以使用fromJSString从中获取常规Haskell字符串JSString.

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

{-# 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'
Run Code Online (Sandbox Code Playgroud)

注意,我正在使用相当酷的通配符语言扩展.

如果没有JSON编码的示例,我可以提供更多建议.


有关

您可以通过实例找到JSON编码的示例实例

  • 在源代码中,对于简单类型.或者在依赖于json的其他包中.
  • AUR消息的实例在这里作为(低级)示例.

  • 非常好,感谢您提供的详细回复.有没有什么方法可以和软件包作者交谈,或者在文档中加上这样的例子(显然可以归功于你)? (3认同)

aug*_*tss 5

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