Swift解码JSON中的唯一密钥或忽略某些密钥



我正在练习Swift技巧,这次我试图制作一个新冠肺炎跟踪器,为此我找到了这个API,问题是/cases检索到的格式是这样的(更改密钥使其更具可读性(

{
"Country1": {
"All": {
"property1": 0,
"property2": "foo"
}
}, {
"All": {
"property1": "0",
"property2": "bar",
},
"State1": {
"property1": 0,
"property3": "foobar"
}
}
}

我制作了以下结构来解码它:

国家

struct Country: Codable {
let All: [String: All]

private enum CodingKeys: String, CodingKey {
case All
}
}

全部

struct All: Codable {
let confirmed: Int?
let recovered: Int?
let deaths: Int?
let country: String?
let population: Int?
let squareKmArea: Int?
let lifeExpectancy: String?
var elevationInMeters: String?
let continent: String?
let location: String?
let iso: String?
let capitalCity: String?
let lat: String?
let long: String?
let updated: String?

private enum CodingKeys: String, CodingKey {
case confirmed
case recovered
case deaths
case country
case population
case squareKmArea = "sq_km_area"
case lifeExpectancy = "life_expectancy"
case elevationInMeters = "elevation_in_meters"
case continent
case location
case iso
case capitalCity = "capital_city"
case lat
case long
case updated
}

init(confirmed: Int?, recovered: Int?, deaths: Int?, country: String?, population: Int?,
squareKmArea: Int?, lifeExpectancy: String?, elevationInMeters: String?,
continent: String?, location: String?, iso: String?, capitalCity: String?,
lat: String?, long: String?, updated: String?) {
self.confirmed = confirmed
self.recovered = recovered
self.deaths = deaths
self.country = country
self.population = population
self.squareKmArea = squareKmArea
self.lifeExpectancy = lifeExpectancy
self.elevationInMeters = elevationInMeters
self.continent = continent
self.location = location
self.iso = iso
self.capitalCity = capitalCity
self.lat = lat
self.long = long
self.updated = updated
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.confirmed = try container.decodeIfPresent(Int.self, forKey: .confirmed)
self.recovered = try container.decodeIfPresent(Int.self, forKey: .recovered)
self.deaths = try container.decodeIfPresent(Int.self, forKey: .deaths)
self.country = try container.decodeIfPresent(String.self, forKey: .country)
self.population = try container.decodeIfPresent(Int.self, forKey: .population)
self.squareKmArea = try container.decodeIfPresent(Int.self, forKey: .squareKmArea)
self.lifeExpectancy = try container.decodeIfPresent(String.self, forKey: .lifeExpectancy)
self.elevationInMeters = try container.decodeIfPresent(String.self, forKey: .elevationInMeters)
self.continent = try container.decodeIfPresent(String.self, forKey: .continent)
self.location = try container.decodeIfPresent(String.self, forKey: .location)
self.iso = try container.decodeIfPresent(String.self, forKey: .iso)
self.capitalCity = try container.decodeIfPresent(String.self, forKey: .capitalCity)
self.lat = try container.decodeIfPresent(String.self, forKey: .lat)
self.long = try container.decodeIfPresent(String.self, forKey: .long)
self.updated = try container.decodeIfPresent(String.self, forKey: .updated)

do {
self.elevationInMeters = try String(container.decodeIfPresent(Int.self, forKey: .elevationInMeters) ?? 0)
} catch DecodingError.typeMismatch {
print("Not a number")
self.elevationInMeters = try container.decodeIfPresent(String.self, forKey: .elevationInMeters) ?? ""
}
}
}

以米为单位的高程可以是字符串或Int值(4位以上的数字长>字符串(加逗号(,否则为Int((想法取自

我试着用这种方式解码

if let decodedData = self.jsonUtilities.decode(json: safeData, as: [String : Country].self) {
print(decodedData)
}

我上面的decode方法如下:

func decode<T: Decodable>(json: Data, as clazz: T.Type) -> T? {
do {
let decoder = JSONDecoder()
let data = try decoder.decode(T.self, from: json)

return data
} catch {
print(error)
print("An error occurred while parsing JSON")
}

return nil
}

我在他们建议添加所有编码密钥的地方找到了这个答案,但这些都是一大堆。

我还没有添加所有的密钥,因为它是一个8k多行的JSON,所以我想知道是否有更简单的方法来解码它,因为我想不出用唯一密钥解码这个JSON的更好方法了。

或者,如果我可以忽略所有不是"All"的密钥,也可能有效,因为我只是想得到每个国家的总数和它们的位置,将它们放在地图中。

到目前为止,我得到了这个错误:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Diamond Princess", intValue: nil), CodingKeys(stringValue: "All", intValue: nil), _JSONKey(stringValue: "recovered", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found a number instead.", underlyingError: nil))
An error occurred while parsing JSON

也许是因为它找不到钥匙;钻石公主;这是加拿大的一个州(或者我相信是这样((根据我的JSON(,因为出于上述原因我没有添加它。

当您有动态密钥时,您可以将其解码为[String: ...]字典。

JSON的结构如下:

{
"Canada": {
"All": { ... },
"Ontario": { ... },
...
},
"Mexico": { ... },
...
}

所有的国家统计数据都有关键的"All",如果这就是你所需要的,那么你可以创建以下结构:

struct Country: Decodable {
var all: CountryAll
enum CodingKeys: String, CodingKey {
case all = "All"
}
}
struct CountryAll: Decodable {
var confirmed: Int
var recovered: Int
//.. etc
}

并解码为:

let countries = try JSONDecoder().decode([String: Country].self, from: json)

最新更新