如何在Aeson Haskell中使HashMap(对象)失去价值?

时间:2018-10-17 18:46:25

标签: parsing haskell aeson

我正试图通过解决一些在线练习问题来适应一些haskell库。

我有一些输出此代码的代码

Object (fromList [("ABC", String "123")])

也可能是

Object (fromList [("123", String "ABC")])
Object (fromList [(String "123", String "ABC")])
Object (fromList [("123", "ABC")])

我需要提取的是"123"

使用类型为.:的{​​{1}}提取给定键的值会引发此错误

(.:) :: FromJSON a => Object -> Text -> Parser a

我最好的猜测是,我将不得不编写一个解析器,但我不知道该如何去做或寻找什么。

产生错误的代码:

• Couldn't match type ‘Value’ with ‘HashMap Text Value’                                                         
  Expected type: Object
    Actual type: Value

像这样定义DataSet的地方

x <- (eitherDecode <$> simpleHttp url) :: IO (Either String DataSet)
  case x of
    Left er   -> print er
    Right an -> do
      let l = S.toList (data1 an)
      print $ l .: "ABC"

如果我要更换

newtype DataSet = DataSet {
                   data1  :: Object
                   } deriving (Show, Generic)

print $ (Data.List.head l) .: "ABC"

我知道

print $ (Data.List.head l)

3 个答案:

答案 0 :(得分:2)

ObjectValue type

的几个构造函数之一
Haskell Constructor | JSON Syntax
Object              | {"key": "value"}
String              | "hello"
Number              | 123
Array               | [1, 2, 3]

请注意,在这种情况下,构造函数Object不是Object类型的构造函数。 [结尾请注意。]

该错误是由于将Value传递给某个期望Object的函数而引起的。您将需要定义程序在遇到任何其他情况时应采取的措施。

或者由于您拥有data1 an :: Object,因此可以在其中查找所需的密钥。我不确定S.toList的类型是什么,但是您似乎正在将Object转换为Value,然后将其传递给需要对象的.:

最后的注释:Object (fromList [("ABC", String "123")])是具有单个键值对的单个对象的单个值。 fromList是一种从对象的各个部分创建对象的方法(而不是通过解析JSON字符串)。

答案 1 :(得分:0)

一种使事情脱离Value类型的快速而肮脏的方法是

Value编码为ByteString

编码的类型为encode :: ToJSON a => a -> ByteString

所以在您的代码中

...
  case x of
    Left er   -> print er
    Right an -> do
      let l = S.toList (data1 an)
          x = (encode . snd) l  -- you can replace snd with fst if you want "ABC" instead of "123"
          y = decode x :: Maybe (HashMap String String)
          case y of
              Nothing -> print "got nothing"
              Just a -> print $ Data.HashMap.Strict.toList a

哪个会输出如下列表:

[("123")]

现在您可以使用简单的函数提取值。

希望有帮助。

要了解有关如何更好地解析JSON文件的更多信息,建议您阅读https://artyom.me/aeson

答案 2 :(得分:0)

您可以通过以下几种方法从Object数据类型中解开Value构造函数。

您可以创建一个函数来展开:

unwrapValue :: Value -> Object
unwrapValue (Object x) = x
unwrapValue _ = error "No Object available"

请注意,此功能将返回错误,因为在某些情况下Value不会是Object

此外,不要因为Object既是Value的构造函数又是aeson中的类型而感到困惑!

您也可以解开内联,但是它也不安全,这可能会导致运行时错误。例如:

getNum :: Array -> Either String Scientific
getNum someArray = flip parseEither someArray $ \arr -> do
  let Just (Object obj) = arr !? 1 -- Unsafe unwrap Object constructor from Value (also unwraps Just constructor from Maybe)
  (Number num) <- obj .: "myNumber" -- Unsafe unwrap Number constructor from Value

  return num