代码之家  ›  专栏  ›  技术社区  ›  Isuru PapaSmurf

解码没有字段名的JSON数组

  •  0
  • Isuru PapaSmurf  · 技术社区  · 7 年前

    我有一个这样简单的JSON文件。

    {
        "january": [
            {
                "name": "New Year's Day",
                "date": "2019-01-01T00:00:00-0500",
                "isNationalHoliday": true,
                "isRegionalHoliday": true,
                "isPublicHoliday": true,
                "isGovernmentHoliday": true
            },
            {
                "name": "Martin Luther King Day",
                "date": "2019-01-21T00:00:00-0500",
                "isNationalHoliday": true,
                "isRegionalHoliday": true,
                "isPublicHoliday": true,
                "isGovernmentHoliday": true
            }
        ],
        "february": [
            {
                "name": "Presidents' Day",
                "date": "2019-02-18T00:00:00-0500",
                "isNationalHoliday": false,
                "isRegionalHoliday": true,
                "isPublicHoliday": false,
                "isGovernmentHoliday": false
            }
        ],
        "march": null
    }
    

    我想用斯威夫特的 JSONDecoder 把它们解码成物体。为此,我创建了一个 Month 和一个 Holiday 对象。

    public struct Month {
        public let name: String
        public let holidays: [Holiday]?
    }
    
    extension Month: Decodable { }
    
    public struct Holiday {
        public let name: String
        public let date: Date
        public let isNationalHoliday: Bool
        public let isRegionalHoliday: Bool
        public let isPublicHoliday: Bool
        public let isGovernmentHoliday: Bool
    }
    
    extension Holiday: Decodable { }
    

    和一个单独的 HolidayData 模型来保存所有这些数据。

    public struct HolidayData {
        public let months: [Month]
    }
    
    extension HolidayData: Decodable { }
    

    这就是我解码的地方。

    guard let url = Bundle.main.url(forResource: "holidays", withExtension: "json") else { return }
    do {
        let data = try Data(contentsOf: url)
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        let jsonData = try decoder.decode(Month.self, from: data)
        print(jsonData)
    } catch let error {
        print("Error occurred loading file: \(error.localizedDescription)")
        return
    }
    

    但它总是失败,错误如下。

    无法读取数据,因为数据的格式不正确。

    我猜是失败了,因为没有一个场叫 holidays 在JSON文件中,即使在 月份 结构。

    如何将假日数组添加到 假期 字段而不在JSON中?

    0 回复  |  直到 7 年前
        1
  •  1
  •   fphilipe    7 年前

    public struct Holiday: Decodable {
        public let name: String
        public let date: Date
        public let isBankHoliday: Bool?
        public let isPublicHoliday: Bool
        public let isMercantileHoliday: Bool?
    }
    
    try decoder.decode([String: [Holiday]?].self, from: data)
    

    isBankHoliday isMercantileHoliday Optional


    public struct Month {
        public let name: String
        public let holidays: [Holiday]?
    }
    
    extension Month: Decodable { }
    
    public struct Holiday {
        public let name: String
        public let date: Date
        public let isBankHoliday: Bool
        public let isPublicHoliday: Bool
        public let isMercantileHoliday: Bool
    
        enum CodingKeys: String, CodingKey {
            case name
            case date
            case isBankHoliday
            case isPublicHoliday
            case isMercantileHoliday
        }
    }
    
    extension Holiday: Decodable {
        public init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            name = try container.decode(String.self, forKey: .name)
            date = try container.decode(Date.self, forKey: .date)
            isBankHoliday = try container.decodeIfPresent(Bool.self, forKey: .isBankHoliday) ?? false
            isPublicHoliday = try container.decodeIfPresent(Bool.self, forKey: .isPublicHoliday) ?? false
            isMercantileHoliday = try container.decodeIfPresent(Bool.self, forKey: .isMercantileHoliday) ?? false
        }
    }
    
    public struct HolidayData {
        public let months: [Month]
    }
    
    extension HolidayData: Decodable {
        public init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            let values = try container.decode([String: [Holiday]?].self)
    
            months = values.map { (name, holidays) in
                Month(name: name, holidays: holidays)
            }
        }
    }
    
    decoder.decode(HolidayData.self, from: data)
    
        2
  •  1
  •   Sweeper    7 年前

    CodingKey

    enum Months : CodingKey, CaseIterable {
        case january
        case feburary
        case march
        // ...
    }
    

    init(decoder:) HolidayData

    extension HolidayData : Decodable {
        public init(from decoder: Decoder) throws {
            var months = [Month]()
            let container = try decoder.container(keyedBy: Months.self)
            for month in Months.allCases {
                let holidays = try container.decodeIfPresent([Holiday].self, forKey: month)
                months.append(Month(name: month.stringValue, holidays: holidays))
            }
            self.months = months
        }
    }
    

        3
  •  0
  •   Mojtaba Hosseini    7 年前

    public struct Year {
         public let January: [Holyday]?
         public let February: [Holyday]?
         public let March: [Holyday]?
         public let April: [Holyday]?
         public let May: [Holyday]?
         public let June: [Holyday]?
         public let July: [Holyday]?
         public let August: [Holyday]?
         public let September: [Holyday]?
         public let October: [Holyday]?
         public let November: [Holyday]?
         public let December: [Holyday]?
    }
    
    extension Year: Decodable { }
    

    {[
        "name":"january",
        "holidays": [
            {
                "name": "New Year's Day",
                "date": "2019-01-01T00:00:00-0500",
                "isNationalHoliday": true,
                "isRegionalHoliday": true,
                "isPublicHoliday": true,
                "isGovernmentHoliday": true
            },
            {
                "name": "Martin Luther King Day",
                "date": "2019-01-21T00:00:00-0500",
                "isNationalHoliday": true,
                "isRegionalHoliday": true,
                "isPublicHoliday": true,
                "isGovernmentHoliday": true
            }
        ]],[
        "name":"february",
        "holidays": [
            {
                "name": "Presidents' Day",
                "date": "2019-02-18T00:00:00-0500",
                "isNationalHoliday": false,
                "isRegionalHoliday": true,
                "isPublicHoliday": false,
                "isGovernmentHoliday": false
            }
        ]],[
        "name":"march",
        "holidays": null
        ]
    }