'Is there a way to deal with optionals of simple types that require a custom deserializer?
I have a struct which has its own deserialize method and optional DateComponents, which in turn, require their own deserialize method.
The struct currently looks like this:
public struct RepetitionPattern: XMLIndexerDeserializable {
let duration: DateComponents?
let interval: DateComponents?
let stopAtDurationEnd: Bool?
public init(duration: DateComponents? = nil, interval: DateComponents? = nil, stopAtDurationEnd: Bool? = nil) {
self.duration = duration
self.interval = interval
self.stopAtDurationEnd = stopAtDurationEnd
}
public static func deserialize(_ element: XMLIndexer) throws -> Self {
let duration: DateComponents = try element["Duration"].value()
let interval: DateComponents = try element["Interval"].value()
return try RepetitionPattern(
duration: duration.isValidDate ? duration : nil,
interval: interval.isValidDate ? interval : nil,
stopAtDurationEnd: element["StopAtDurationEnd"].value()
)
}
}
And the deserialize method for the DateComponents type looks like:
extension DateComponents: XMLElementDeserializable {
public static func deserialize(_ element: SWXMLHash.XMLElement) throws -> Self {
guard !element.text.isEmpty else {
return DateComponents()
}
// Use durationFrom8601String from Swift_ISO8601_DurationParser to parse
// the ISO 8601 string.
guard let validDateComponents = DateComponents.durationFrom8601String(element.text) else {
throw XMLDeserializationError.typeConversionFailed(type: "DateComponent", element: element)
}
return validDateComponents
}
public func validate() throws {
// Empty validate. Only necessary for custom validation logic after parsing.
}
}
Is there a way to return an optional from the deserialize method? Or is there a better mechanism than the following in the struct's deserialize method for dealing with optionals?
public static func deserialize(_ element: XMLIndexer) throws -> Self {
let duration: DateComponents = try element["Duration"].value()
let interval: DateComponents = try element["Interval"].value()
return try RepetitionPattern(
duration: duration.isValidDate ? duration : nil,
interval: interval.isValidDate ? interval : nil,
stopAtDurationEnd: element["StopAtDurationEnd"].value()
)
}
Ideally, I'd be able to do something like the following in deserialize for DateComponents, but deserialize doesn't appear to support an optional return type:
public static func deserialize(_ element: SWXMLHash.XMLElement) throws -> DateComponents? {
guard !element.text.isEmpty else {
return nil
}
// Use durationFrom8601String from Swift_ISO8601_DurationParser to parse
// the ISO 8601 string.
guard let validDateComponents = DateComponents.durationFrom8601String(element.text) else {
throw XMLDeserializationError.typeConversionFailed(type: "DateComponent", element: element)
}
return validDateComponents
}
The Duration and Internal tags are not missing in the XML that I receive. Instead, they look like:
<d1p7:Repetition>
<d1p7:Duration i:nil="true" />
<d1p7:Interval i:nil="true" />
<d1p7:StopAtDurationEnd>false</d1p7:StopAtDurationEnd>
</d1p7:Repetition>
Given the above, I also looked at doing the following for RepetitionPattern's deserialize method, but it sure is ugly:
public static func deserialize(_ element: XMLIndexer) throws -> Self {
let hasDuration: Bool? = element["Duration"].value(ofAttribute: "i:nil")
let hasInterval: Bool? = element["Interval"].value(ofAttribute: "i:nil")
let hasStopAtDurationEnd: Bool? = element["StopAtDurationEnd"].value(ofAttribute: "i:nil")
return RepetitionPattern(
duration: hasDuration != nil ? nil : try element["Duration"].value(),
interval: hasInterval != nil ? nil : try element["Interval"].value(),
stopAtDurationEnd: hasStopAtDurationEnd != nil ? nil : try element["StopAtDurationEnd"].value()
)
}
Thoughts?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
