问题
My JSON
response is the following:
{
"data": [
{
"unknown-key-c3e7f0": {
"date_time": 1546944854000,
"medication": "f4f25ea4-0607-4aac-b85a-edf40cc7d5b6",
"record": {
"status": "never"
}
},
"unknown-key-619d40": {
"date_time": 1546944854000,
"medication": "deef2278-f176-418f-ac34-c65fa54e712c",
"record": {
"status": "always"
}
},
"event": "06b445b9-dae0-48a1-85e4-b9f48c9a2349",
"created": 1546949155020,
"user": "8fb3fcd1-ffe6-4fd9-89b8-d22b1653cb6a",
"id": "1546944855000",
"type": "compliance"
},
{
"unknown-key-619d40": {
"date_time": 1546944975000,
"medication": "deef2278-f176-418f-ac34-c65fa54e712c",
"record": {
"status": "sometimes"
}
},
"event": "7309d8e9-b71c-4068-b278-0ae6d91a57a6",
"created": 1546946798407,
"user": "8fb3fcd1-ffe6-4fd9-89b8-d22b1653cb6a",
"id": "1546944975000",
"type": "compliance"
}
}
From the above response, I want to get the unknown keys and their values. The values of the unknown keys are of a custom type called Record
which conforms to the Codable
protocol.
I have created this struct for the parsing the data
struct RecordSuper: Codable
{
var data: [[String: Record]]
}
So, I want to filter all other keys like event, created, user
, etc which I am getting in the response and save only the unknown keys and the values.
Please suggest how to parse this using codable.
I have gone through this answer as well as the variation suggested in the third comment of the answer. https://stackoverflow.com/a/46369152/8330469
This answer shows how to filter the incorrect data in an Array so that the correct data is not lost. I am trying to do something similar.
For example, I want to discard the event
key because it is of type String
and not of type Record
.
The above answer will discard the whole dictionary because all the dictionaries are have incorrect data like event
. And in the end, I get an empty array.
Thanks in advance.
回答1:
This is a solution widely based on this intriguing answer of Rob Napier.
The goal of TitleKey
and the two Decoder
extensions is to map dictionaries with arbitrary keys to arrays adding the key as title
property.
struct TitleKey: CodingKey {
let stringValue: String
init?(stringValue: String) { self.stringValue = stringValue }
var intValue: Int? { return nil }
init?(intValue: Int) { return nil }
}
extension Decoder {
func currentTitle() throws -> String {
guard let titleKey = codingPath.last as? TitleKey else {
throw DecodingError.dataCorrupted(.init(codingPath: codingPath,
debugDescription: "Not in titled container"))
}
return titleKey.stringValue
}
}
extension Decoder {
func decodeTitledElements<Element: Decodable>(_ type: Element.Type) throws -> [Element] {
let titles = try container(keyedBy: TitleKey.self)
return titles.allKeys.compactMap { title in
return try? titles.decode(Element.self, forKey: title)
}
}
}
I modified the decodeTitledElements
function to decode only those dictionaries whose value represents the RecordSuper
struct filtering the other keys.
Here are the structs.
struct Root : Decodable {
let data : [Containers]
}
struct Containers: Decodable {
let containers: [RecordSuper]
init(from decoder: Decoder) throws {
self.containers = try decoder.decodeTitledElements(RecordSuper.self)
}
}
struct RecordSuper : Decodable {
let title : String
let dateTime : Date
let medication : String
let record : Record
enum CodingKeys: String, CodingKey {
case dateTime = "date_time", medication, record
}
init(from decoder: Decoder) throws {
self.title = try decoder.currentTitle()
let container = try decoder.container(keyedBy: CodingKeys.self)
self.dateTime = try container.decode(Date.self, forKey: .dateTime)
self.medication = try container.decode(String.self, forKey: .medication)
self.record = try container.decode(Record.self, forKey: .record)
}
}
struct Record : Decodable {
let status : String
}
Now decode the JSON assuming jsonData
is the JSON as Data
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let result = try decoder.decode(Root.self, from: jsonData
print(result.data)
来源:https://stackoverflow.com/questions/54160875/implement-codable-for-an-array-of-dictionary-with-failable-responses