Aeson 解析器为数组字段返回 'Nothing'

Aeson Parser Returning 'Nothing' for Array field

我正在尝试从以下 JSON 输入中提取 'path' 键的第三个元素:

{
  "certname": "some.server.name",
  "path": [
    "networking",
    "interfaces",
    "eth0",
    "bindings",
    0,
    "address"
  ],
  "name": "networking",
  "value": "192.168.1.1",
  "environment": "develop"
}

但我得到的只是 'Nothing' 当 运行 这个程序:

{-# LANGUAGE OverloadedStrings #-}

import           Control.Monad        (mzero)
import           Data.Aeson
import           Data.ByteString.Lazy (ByteString)
import           Data.Text
import qualified Data.Vector          as V

data HostNicIp =
  HostNicIp { hniHost :: !Text
            , hniNic  :: !Text
            , hniIp   :: !Text
            } deriving Show

instance FromJSON HostNicIp where
  parseJSON (Object o) =
    HostNicIp
      <$> (o .: "certname")
      <*> fmap (V.! 2) (o .: "path")
      <*> (o .: "value" )
  parseJSON _  = mzero

main :: IO ()
main = print ( decode demo :: Maybe HostNicIp )

demo :: ByteString
demo = "{\"certname\":\"some.server.name\",\"path\":[\"networking\",\"interfaces\",\"eth0\",\"bindings\",0,\"address\"],\"name\":\"networking\",\"value\":\"192.168.1.1\",\"environment\":\"develop\"}"

注释 hniNic 及其相关逻辑使程序解析其他所有内容

编辑:

运行 这与 eitherDecode 使它抱怨遇到 Number 而不是 Text

*Main> eitherDecode demo :: Either String HostNicIp 
Left "Error in $.path[4]: expected Text, encountered Number"

而原始 Object 似乎解析正常

*Main> eitherDecode demo :: Either String Object
Right (fromList [("certname",String "some.server.name"),("path",Array [String "networking",String "interfaces",String "eth0",String "bindings",Number 0.0,String "address"]),("environment",String "develop"),("value",String "192.168.1.1"),("name",String "networking")])

异构列表可以用Aeson吗?我该如何处理?

fmap (V.! 2) (o .: "path")

o .: "path" 这里必须有类型 Parser (Vector Text) 但你给的数组包含一个数字。

相反,不要解码数组,即在类型 Parser Value 处使用 o .: "path",然后通过模式匹配或使用 withArray 显式破坏值。然后给定一个 Array(即 Vector Value,它是异构的)你可以得到第二个元素 (V.! 2) 并将其转换为 Text(通过模式匹配,用 withText, 或者 parseJSON).

(o .: "path") >>= withArray "Path info" (parseJSON . (V.! 2))