我的JSON
答复如下:
{
"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"
}
}
从以上响应中,我想获取未知键及其值。未知密钥的值是一种自定义类型,称为Record
,符合Codable
协议。
我已经创建了用于解析数据的结构
struct RecordSuper: Codable
{
var data: [[String: Record]]
}
因此,我想过滤响应中得到的所有其他键,例如event, created, user
等,并仅保存未知键和值。
请建议如何使用可编码来解析此内容。
我已经仔细阅读了该答案以及答案第三条注释中建议的变体形式。 https://stackoverflow.com/a/46369152/8330469
此答案显示了如何过滤Array中的错误数据,以便不会丢失正确的数据。我正在尝试做类似的事情。
例如,我想丢弃event
键,因为它的类型为String
,而不是类型为Record
。
以上答案将丢弃整个词典,因为所有词典的数据都不正确,例如event
。最后,我得到一个空数组。
谢谢。
答案 0 :(得分:1)
这是一个广泛基于intriguing answer的Rob Napier的解决方案。
TitleKey
和两个Decoder
扩展的目标是将具有任意键的字典映射到将键作为title
属性添加的数组。
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)
}
}
}
我修改了decodeTitledElements
函数,使其仅解码其值表示过滤其他键的RecordSuper
结构的那些字典。
这是结构。
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
}
现在假设jsonData
是JSON,Data
解码JSON
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let result = try decoder.decode(Root.self, from: jsonData
print(result.data)