如何从Haskell,Aeson的Value中取出HashMap(Object)?

How to get HashMap (Object) out of Value in Haskell, Aeson?

我正在尝试通过解决一些在线练习题来习惯一些 haskell 库。

我有一些输出这个的代码

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

也可能是

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

我需要提取的是"123"

使用具有类型 (.:) :: FromJSON a => Object -> Text -> Parser a.: 提取给定键的值会引发此错误

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

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

产生错误的代码:

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"

DataSet 的定义如下

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

如果我要替换

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

只有

print $ (Data.List.head l)

我明白了

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

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 字符串)。

Value 类型中获取东西的一种快速而肮脏的方法是

Value 编码为 ByteString

encode 的类型为 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 好好阅读。

这里有一些方法可以从 Value 数据类型中解包 Object 构造函数。

您可以创建一个函数来解包:

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

请注意此函数将 return 出错,因为有可能 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