如何在Swift中基于条件解析JSON的嵌套部分

gudnpqoy  于 2022-11-19  发布在  Swift
关注(0)|答案(1)|浏览(143)

其他建议的解决方案处理结构的类型,他们是一部分,虽然我不能弄清楚如何解析嵌套的部分,相同的结构的基础上,在外部结构的值。
我有一个JSON响应,它的结构根据JSON外部的某个值而改变。
例如:

{
  "reports": [
    {
      "reportType": "advance",
      "reportData": {
        "value1": "true"
      }
    },
    {
      "reportType": "simple",
      "reportData": {
        "value3": "false",
        "value": "sample"
      }
    }
  ]
}

将Codable与字符串一起用作'report'关键字的类型时无法解析此json。我希望稍后解析此报告值并按原样存储它,或者至少根据reportType值解析它,因为reportType的每个值都有不同的结构。
我已经根据建议的解决方案编写了代码。

enum ReportTypes: String {
    case simple, advance
}

struct Reports: Codable {
    let reportArray = [Report]
}

struct Report: Decodable {
    let reportType: String
    let reportData: ReportTypes
    enum CodingKeys: String, CodingKey {
        case reportType, reportData
    }
    init(from decoder: Decoder) {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.reportType = try container.decode(String.self, forKey: .reportType)

        switch ReportTypes(rawValue: self.reportType) {
            case .simple:
            ???
            case .advance:
            ???
        }
    }
    
}

请看开关的情况下,我不知道该怎么做。我需要一个类似的解决方案来做这件事。
解决方法:解决方法是在report {}结构中对reportType进行建模,然后按照How can i parse an Json array of a list of different object using Codable?这个问题
新建结构

{
  "reports": [
    {
      "reportType": "advance",
      "reportData": {
        "reportType": "advance",
        "value1": "true"
      }
    },
    {
      "reportType": "simple",
      "reportData": {
        "reportType": "simple",
        "value3": "false",
        "value": "sample"
      }
    }
  ]
}

所以我就这样解决了。
但是,如果改变结构不是你所能负担得起的,那么这将是行不通的。
其他可能的解决方案是将reportType存储在init(from decoder: Decoder)变量currentReportType中,然后为struct reportData编写另一个解码器,该解码器将基于存储在var currentReportType中的值处理解码。

monwx1rj

monwx1rj1#

解码此JSON的合理方法是使用具有关联值的枚举,因为类型是已知的。
为表示reportData中数据的对象创建两个结构

struct AdvancedReport: Decodable {
    let value1: String
}

struct SimpleReport: Decodable {
    let value3, value: String
}

并且在ReportType中采用Decodable

enum ReportType: String, Decodable {
    case simple, advance
}

两个主要的结构体是根对象结构体Response(我重命名了它,因为术语 Report 出现太多次)和上面提到的带有关联值的枚举。子字典中的键reportType没有被解码,因为它是冗余的。

struct Response: Decodable {
    let reports : [Report]
}

enum Report: Decodable {
    
    case simple(SimpleReport)
    case advance(AdvancedReport)
    
    private enum CodingKeys: String, CodingKey {
        case reportType, reportData
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let reportType = try container.decode(ReportType.self, forKey: .reportType)

        switch reportType {
            case .simple: self = .simple(try container.decode(SimpleReport.self, forKey: .reportData))
            case .advance: self = .advance(try container.decode(AdvancedReport.self, forKey: .reportData))
        }
    }
}

解码JSON后,您可以打开reports

for report in response.reports {
    switch report {
        case .simple(let simpleReport): print(simpleReport)
        case .advance(let advancedReport): print(advancedReport)

    }
}

相关问题