首页 > 解决方案 > 使用 Decodable 解码嵌套的 JSON 子对象

问题描述

我有一些 JSON(来自 last.fm),看起来像这样:

{
    "results": {
        "opensearch:Query": {
            "#text": "",
            "role": "request",
            "searchTerms": "believe",
            "startPage": "1"
        },
        "opensearch:totalResults": "119100",
        "opensearch:startIndex": "0",
        "opensearch:itemsPerPage": "50",
        "albummatches": {
            // It's this array that I actually want:
            "album": [
                {
                    "name": "Believe",
                    "artist": "Disturbed",
                    "url": "https://www.last.fm/music/Disturbed/Believe",
                    "image": [
                        {
                            "#text": "https://lastfm-img2.akamaized.net/i/u/34s/bca3b80481394e25b03f4fc77c338897.png",
                            "size": "small"
                        },
                        // There are more here.
                        …
                    ]
                },
                // There are more here.
                …
            }
        }
    }
}

我想解码嵌套数组album,它是三层深。我可以愉快地为此实现一个Decodable结构,这将是这样的(未经测试,但可以构建):

struct Album: Decodable {
  let name: String
  let artist: String
  let url: URL
  let image: [Image]

  struct Image: Decodable {
    let url: URL
    let size: String

    enum CodingKeys: String, CodingKey {
      case url = "#text"
      case size
    }
  }
}

但是,有没有一种很好的方法可以访问 JSON 并开始解析album数组?

我可以实现ResponseContainer,ResultsAlbumMatches这样的结构来实现这一点:

struct ResponseContainer: Decodable {
   let results: Results
}

struct Results: Decodable {
    let albummatches: AlbumMatches
}

struct AlbumMatches: Decodable {
    let album: [Album]
}

…但是当我真正想做的是这样的事情时,这似乎不是一个好方法:

let decoder = JSONDecoder()
let albums = try! decoder.decode(
  [Album].self, 
  for: jsonData, 
  // Made up path parameter to let me jump to a child.
  at: "results.albummatches.album"
)

我还想避免使用 反序列化 JSON JSONSerialization.jsonObject(with: …, options: …),取出特定部分并重新序列化它,然后使用JSONDecoder,因为这似乎非常浪费,尽管它肯定会起作用。

标签: jsonswiftdecodable

解决方案


推荐阅读