json - 在 Swift 4 中使用可编码的数组中的嵌套字典键值
问题描述
我在下面的结构中有 json
{
"message": null,
"data": {
"admin": {
"UserId": 1,
"CUSTOMER_PROFILING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"RISK_ASSESSMENT": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"LINK_ANALYSIS": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"BENCH_MARKING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"SUSPICIOUS_TRANSACTION_REPORTING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"THRESHOLD_TRANSACTION_REPORTING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
}
},
"vinoth59": {
"UserId": 15,
"CUSTOMER_PROFILING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"RISK_ASSESSMENT": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"LINK_ANALYSIS": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"BENCH_MARKING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"SUSPICIOUS_TRANSACTION_REPORTING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"THRESHOLD_TRANSACTION_REPORTING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
}
},
"ba_user": {
"UserId": 16,
"CUSTOMER_PROFILING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"RISK_ASSESSMENT": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"LINK_ANALYSIS": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"BENCH_MARKING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"SUSPICIOUS_TRANSACTION_REPORTING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
},
"THRESHOLD_TRANSACTION_REPORTING": {
"id": 0,
"total": 0,
"high": 0,
"low": 0,
"medium": 0
}
}
},
"status": true
}
我的可编码课程如下所示
struct UserRiskReportBase : Codable {
let message : String?
let data : [String:UserRiskReport]?
let status : Bool?
enum CodingKeys: String, CodingKey {
case message = "message"
case data = "data"
case status = "status"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
message = try values.decodeIfPresent(String.self, forKey: .message)
data = try values.decodeIfPresent([String:[String:BenchMarking]].self, forKey: .data)
status = try values.decodeIfPresent(Bool.self, forKey: .status)
}
}
struct UserRiskReport: Codable {
let userID: Int
let customerProfiling, riskAssessment, linkAnalysis, benchMarking: BenchMarking
let suspiciousTransactionReporting, thresholdTransactionReporting: BenchMarking
enum CodingKeys: String, CodingKey {
case userID = "UserId"
case customerProfiling = "CUSTOMER_PROFILING"
case riskAssessment = "RISK_ASSESSMENT"
case linkAnalysis = "LINK_ANALYSIS"
case benchMarking = "BENCH_MARKING"
case suspiciousTransactionReporting = "SUSPICIOUS_TRANSACTION_REPORTING"
case thresholdTransactionReporting = "THRESHOLD_TRANSACTION_REPORTING"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
userID = try values.decodeIfPresent(Int.self, forKey: .userID)!
customerProfiling = try values.decodeIfPresent(BenchMarking.self, forKey: .customerProfiling)!
benchMarking = try values.decodeIfPresent(BenchMarking.self, forKey: .benchMarking)!
riskAssessment = try values.decodeIfPresent(BenchMarking.self, forKey: .riskAssessment)!
suspiciousTransactionReporting = try values.decodeIfPresent(BenchMarking.self, forKey: .suspiciousTransactionReporting)!
linkAnalysis = try values.decodeIfPresent(BenchMarking.self, forKey: .linkAnalysis)!
thresholdTransactionReporting = try values.decodeIfPresent(BenchMarking.self, forKey: .thresholdTransactionReporting)!
}
}
struct BenchMarking : Codable {
let id : Int?
let total : Int?
let high : Int?
let low : Int?
let medium : Int?
enum CodingKeys: String, CodingKey {
case id = "id"
case total = "total"
case high = "high"
case low = "low"
case medium = "medium"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(Int.self, forKey: .id)
total = try values.decodeIfPresent(Int.self, forKey: .total)
high = try values.decodeIfPresent(Int.self, forKey: .high)
low = try values.decodeIfPresent(Int.self, forKey: .low)
medium = try values.decodeIfPresent(Int.self, forKey: .medium)
}
}
我能拿到一级钥匙
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let alertList = try dec.decode(UserRiskReportBase.self, from:response.data!)
self.userRiskReportList = alertList.data!
self.headerArr = Array(alertList.data!.keys)
print(self.headerArr)
我得到了像 ["admin","vinoth59","ba_user"] 这样的第一级键。我需要获得二级密钥 ["CUSTOMER_PROFILING","RISK_ASSESSMENT",.....]。如何使用此可编码实现
解决方案
以下对我有用,请注意我已经做了一些简化并删除了不需要的代码init(from:)
,我还删除了许多属性的 Optional
struct UserRiskReportBase : Codable {
let message : String?
let data : [String:UserRiskReport]
let status : Bool?
}
struct UserRiskReport: Codable {
let userID: Int
let customerProfiling, riskAssessment, linkAnalysis, benchMarking: BenchMarking
let suspiciousTransactionReporting, thresholdTransactionReporting: BenchMarking
enum CodingKeys: String, CodingKey, CaseIterable {
case userID = "UserId"
case customerProfiling = "CUSTOMER_PROFILING"
case riskAssessment = "RISK_ASSESSMENT"
case linkAnalysis = "LINK_ANALYSIS"
case benchMarking = "BENCH_MARKING"
case suspiciousTransactionReporting = "SUSPICIOUS_TRANSACTION_REPORTING"
case thresholdTransactionReporting = "THRESHOLD_TRANSACTION_REPORTING"
}
var allKeys: [String] {
get {
CodingKeys.allCases.map {$0.rawValue}
}
}
}
struct BenchMarking : Codable {
let id : Int
let total : Int
let high : Int
let low : Int
let medium : Int
}
do {
let result = try JSONDecoder().decode(UserRiskReportBase.self, from: data)
for item in result.data.values {
print("Report for user: \(item.userID)")
print(item.customerProfiling)
print(item.benchMarking)
//print(...)
}
} catch {
print(error)
}
推荐阅读
- java - 创建新对象会覆盖与先前对象关联的 ObservableList
- spring-boot - rsyslog 是否与 Logback-SLF4J 兼容?
- swift - 删除tableview行和发布请求逻辑
- r - 如何在R中以字符形式构建条件滚动序列
- php - Laravel LdapRecord 数组
- java - 在 Spring Boot 中使用时 SonarQube API 日期+时区不起作用
- r - 多类中的可变重要性
- python - ProgrammingError: 1698 (28000): Access denied for user 'root'@'localhost when using mysql.connector in python
- sql - 处理 SSAS 多维数据集的速度比处理多维数据集的速度快
- cairo - 使用模式生成时访问 cairo_path_t