在 Elm 中,如何解码嵌套 JSON 中的 JSON 对象

In Elm, how to decode a JSON object inside nested JSON

我使用 Elm 0.19.1 和 NoRedInk/elm-json-decode-pipeline/1.0.0

我的飞机类型是

type alias Aircraft = {name:String}

为此,我有以下解码器:

aircraftDecoder : Json.Decode.Decoder Aircraft        
aircraftDecoder =            
    Json.Decode.succeed Aircraft            
    |> Json.Decode.Pipeline.required "name" Json.Decode.string

不幸的是,解码器抱怨我说:"BadBody "给定值有问题:(...)" 这是因为实际上我感兴趣的区域周围充满噪音(来自 HATEOAS api),如下所示:

{
  "_embedded" : {
    "aircrafts" : [ {
      "name" : "AC01",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/aircrafts/1"
        },
        "aircraft" : {
          "href" : "http://localhost:8080/aircrafts/1"
        }
      }
    }, {
      "name" : "AC01",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/aircrafts/2"
        },
        "aircraft" : {
          "href" : "http://localhost:8080/aircrafts/2"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/aircrafts{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/aircrafts"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 4,
    "totalPages" : 1,
    "number" : 0
  }
}

我怎样才能更改代码,并继续使用管道,这样解码器就不会被这些噪音弄丢了?

我听说过一些关于使用 Json.Decode.at 的信息,但文档不够好,无法让我获得正确的代码。

以下应该有效:

aircraftNameDecoder : Json.Decode.Decoder String
aircraftNameDecoder =
    Json.Decode.map (Maybe.withDefault "" << List.head) <|
        Json.Decode.at [ "_embedded", "aircrafts" ] <|
            Json.Decode.list (Json.Decode.field "name" Json.Decode.string)


aircraftDecoder : Json.Decode.Decoder Aircraft
aircraftDecoder =
    Json.Decode.succeed Aircraft
        |> Json.Decode.Pipeline.custom aircraftNameDecoder

有关 Json.Decode.at 的更多文档,请参阅 elm/json

据我所知,问题在于:

  1. 此刻,您的解码器可能非常适合解码单个 Aircraft
  2. 但是,您的 JSON 有一个列表 Aircrafts
  3. 另外,你的解码器不知道在哪里,在JSON中,它可能会找到Aircrafts

而且你知道,对于 Elm AircraftList Aircraft 是完全不同的节拍(它们应该是)。无论如何,解决方案分为两步:

  1. 告诉解码器 JSON 结构中的 Aircrafts
  2. 解析 List Aircraft 而不是单个 Aircraft

按照您的代码并从 Json.Decode 导入 atlist,代码可能如下所示:

listAircraftDecoder : Json.Decode.Decoder List Aircraft 
listAircraftDecoder =
    at ["_embedded", "aircrafts"] (list aircraftDecoder)

这意味着我们现在的目标是 Aircraft 的列表,并且该列表是 JSON 中的一个数组。从 JSON 根开始,获取 属性 "_embedded" 以及其中的 属性 "aircrafts"。这是一个数组,Elm的list知道如何处理它

最后,我们只需要告诉 Elm 的 list 将 JSON 数组的每个元素传递给特定的解码器——在我们的例子中是您的 aircraftDecoder

这有意义吗?