I've been following the examples at SWXMLHash to deserialize an XML file. It is working quite well, but I am not sure how to handle cases when the XML input is incomplete:
For example, suppose the XML input is this:
<shippingInfo>
<shippingServiceCost currencyId="USD">0.0</shippingServiceCost>
<shippingType>Free</shippingType>
<shipToLocations>US</shipToLocations>
<expeditedShipping>true</expeditedShipping>
<oneDayShippingAvailable>false</oneDayShippingAvailable>
<handlingTime>1</handlingTime>
</shippingInfo>
To deserialize this XML, I create the following struct that is an XMLIndexerDeserializable
import SWXMLHash
struct ShippingInfo: XMLIndexerDeserializable
{
let currencyId: String
let shippingServiceCost: Double
let shippingType: String
let shipToLocations: String
let expeditedShipping: Bool
let oneDayShippingAvailable: Bool
let handlingTime: Int
static func deserialize(_ node: XMLIndexer) throws -> ShippingInfo
{
return try ShippingInfo(
currencyId: node["shippingServiceCost"].value(ofAttribute: "currencyId"),
shippingServiceCost: node["shippingServiceCost"].value(),
shippingType: node["shippingType"].value(),
shipToLocations: node["shipToLocations"].value(),
expeditedShipping: node["expeditedShipping"].value(),
oneDayShippingAvailable: node["oneDayShippingAvailable"].value(),
handlingTime: node["handlingTime"].value()
)
}
}
The code above works, until the shippingInfo XML misses an element, like so:
<shippingInfo>
<shippingServiceCost currencyId="USD">0.0</shippingServiceCost>
<shippingType>Free</shippingType>
<shipToLocations>Worldwide</shipToLocations>
<expeditedShipping>false</expeditedShipping>
<oneDayShippingAvailable>false</oneDayShippingAvailable>
</shippingInfo>
The 2nd XML above is missing the property "handlingTime". Running the deserialization code above would throw an exception at node["handlingTime"].value()
One approach to fix this problem is to try to catch the exception whenever we access the XMLIndexer's key, and pass in a default value to the property if the exception is thrown which means the key isn't there. I don't think this is best approach though.
What is the best approach to deserialize XML when the XML is missing properties?
Change the declaration of your handlingTime
property from Int
to Int?
, like so:
let handlingTime: Int?
It needs to be nullable so that the deserialization can support a value that doesn't exist.
Hope this helps!