Swift json json 的动态密钥解析

Swift json dynamic key parsing for json

我有 json 响应,其中只有一个键名更改其余部分是相同的,并且想在不重复相同结构的情况下进行解析。

"attributes": {
  "symbol":"EUR",
  "name":"Euro",
  "precision":2,             
}
    
"attributes":{
  "symbol":"EUR",
  "name":"Euro",
  "precision_for_fiat_price":2,  
}

如何在json解析

中动态处理这个精度键

您可以使用自定义 keyDecodingStrategy

本质上,您编写了一些逻辑来检查当前编码键路径是否符合某些条件,如果符合,则将该键映射到 precision 键。

例如:

struct Root : Codable {
    let attributes: Attributes
}

struct Attributes : Codable {
    let symbol: String
    let name: String
    let precision: Int
    
    enum CodingKeys: CodingKey {
        case symbol
        case name
        case precision
    }
}

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .custom({
    keys in

    // This will decode every precision_for_fiat_price key in the json as "precision".
    // You might not want this. 
    // Make this criteria stricter if you need to. An example is shown below
    if keys.last?.stringValue == "precision_for_fiat_price" {
        return Attributes.CodingKeys.precision
    }

    // this will only decode those precision_for_fiat_price that have "attribute" as their parent as "precision"
//    if stringPath.suffix(2) == ["attributes", "precision_for_fiat_price"] {
//        return Attributes.CodingKeys.precision
//    }
    return keys.last!
})
let json = """
{
    "attributes":{
                  "symbol":"EUR",
                  "name":"Euro",
                  "precision_for_fiat_price":2
                  
     }
}
""".data(using: .utf8)!
let decoded = try decoder.decode(Root.self, from: json)

如果你只想像这样解码 json 模型:

let json = """
{
  "attributes": {
     "symbol":"EUR",
     "name":"Euro",
     "precision_for_fiat_price":2 // or "precision": 2
  }
}
"""

您可以创建 Decodable 结构:

struct WrapperModel: Decodable { // any model
    var attributes: Attributes
}

struct Attributes : Decodable {
    let symbol: String
    let name: String
    var precision: Int = 0
    
    enum CodingKeys: String, CodingKey, CaseIterable {
        case symbol
        case name
        case precision
        case precisionAnother = "precision_for_fiat_price"
        // you can write any types of key here
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        symbol = try container.decode(String.self, forKey: .symbol)
        name = try container.decode(String.self, forKey: .name)
        if let precisionValue = try container.decodeIfPresent(Int.self, forKey: .precision) {
            precision = precisionValue
        }
        if let precisionValue = try container.decodeIfPresent(Int.self, forKey: .precisionAnother) {
            precision = precisionValue
        }
    }
}

您可以使用以下方法进行测试:

let jsonData = Data(json.utf8)

let decoder = JSONDecoder()

do {
    let attributes = try decoder.decode(WrapperModel.self, from: jsonData)
    print(attributes)
} catch {
    print(error.localizedDescription)
}