【问题标题】:In Elm, how to decode a JSON object inside nested JSON在 Elm 中,如何解码嵌套 JSON 中的 JSON 对象
【发布时间】:2020-05-02 12:58:48
【问题描述】:

我将 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 的信息,但文档不够好,无法让我得到正确的代码。

【问题讨论】:

    标签: json pipeline elm hateoas decoder


    【解决方案1】:

    据我所知,问题在于:

    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)
    

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

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

    这有意义吗?

    【讨论】:

    • 非常好!!这意味着如果 _embedded 本身在 _noise 内部,而后者又在 _root 内部,我应该在 ["_root", "_noise", "_embedded", "aircrafts"] 使用(列出飞机解码器)?也就是说,我必须把从根到目标的整个路径?
    • 是的,你明白了!
    【解决方案2】:

    以下应该有效:

    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

    【讨论】:

    • 嗨,simplystuart,Json.Decode.map (Maybe.withDefault ""
    • 据我了解,他的解决方案是只允许您解码第一架飞机(List.head),这可能是您的情况; )
    • 在您的对象上面的“飞机”是一个数组,因此 Json.Decode.map 行将飞机名称列表转换为单个飞机名称。 @cuducos 是对的,我认为这是基于飞机类型的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 2017-01-12
    相关资源
    最近更新 更多