I have a simple JSON file like this.
{
"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
}
I'm trying to use Swift's JSONDecoder
to decode these into objects. For that, I have created a Month
and a Holiday
object.
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 { }
And a separate HolidayData
model to hold all those data.
public struct HolidayData {
public let months: [Month]
}
extension HolidayData: Decodable { }
This is where I'm doing the decoding.
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
}
But it keeps failing with the following error.
The data couldn’t be read because it isn’t in the correct format.
I'm guessing it's failing because there is no field called holidays
in the JSON file even though there is one in the Month
struct.
How do I add the holidays array into the holidays
field without having it in the JSON?
Month structure does not match with the json.
Change month structure to something else like this:
Note that it is not a best practice of how you can achieve what you want.
Another way is to change the json (if you have access) to match you structures:
If you want to parse the JSON without writing custom decoding logic, you can do it as follows:
For that I had to make
isBankHoliday
andisMercantileHoliday
Optional
as they don't always appear in the JSON.Now, if you want to decode it into the stucture that you introduced above, you'll have to write custom decoding logic:
Your JSON structure is quite awkward to be decoded, but it can be done.
The key thing here is that you need a
CodingKey
enum like this (pun intended):And you can provide a custom implementation of
init(decoder:)
in yourHolidayData
struct:Also note that your structs' property names have different names from the key names in your JSON. Typo?