0

Ok, I am working off Implementing a custom Decoder in Swift 4 and it follows that the parser looks for these keys in the XML:

struct RSSChannel: Codable {
    var title: String
    var pubDate: Date
    var link: URL
    var description: String
    var items: [RSSItem]
    enum CodingKeys: String, CodingKey {
        case title, pubDate, link, description
        case items = "item"
    }
}'

(I did not write this, this is GitHub so Im struggling here)-

I need to know how to stop the parser erring out when a key doesnt exist in a feed, i.e pub date. In the XMLDecoder class, there are all these decoders:

 public func decode(_ type: UInt.Type) throws -> UInt {
        try expectNonNull(UInt.self)
        return try self.unbox(self.storage.topContainer, as: UInt.self)!
    }

    public func decode(_ type: UInt8.Type) throws -> UInt8 {
        try expectNonNull(UInt8.self)
        return try self.unbox(self.storage.topContainer, as: UInt8.self)!
    }

    public func decode(_ type: UInt16.Type) throws -> UInt16 {
        try expectNonNull(UInt16.self)
        return try self.unbox(self.storage.topContainer, as: UInt16.self)!
    }

    public func decode(_ type: UInt32.Type) throws -> UInt32 {
        try expectNonNull(UInt32.self)
        return try self.unbox(self.storage.topContainer, as: UInt32.self)!
    }

    public func decode(_ type: UInt64.Type) throws -> UInt64 {
        try expectNonNull(UInt64.self)
        return try self.unbox(self.storage.topContainer, as: UInt64.self)!
    }

    public func decode(_ type: Float.Type) throws -> Float {
        try expectNonNull(Float.self)
        return try self.unbox(self.storage.topContainer, as: Float.self)!
    }

    public func decode(_ type: Double.Type) throws -> Double {
        try expectNonNull(Double.self)

Which are actually:

  public func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
        guard let entry = self.container[key.stringValue] else {

            print("SKYaw")
            throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
        }

        self.decoder.codingPath.append(key)
        defer { self.decoder.codingPath.removeLast() }

        guard let value = try self.decoder.unbox(entry, as: type) else {
            throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
        }

        return value
    }

A bunch of these. Has anyone run into problems when it says "No key associated with Key"/ throws the error? How can I get around this with this library?

blue
  • 7,175
  • 16
  • 81
  • 179
  • Does declaring the property as an optional fix the issue? – Paulw11 Jun 06 '18 at 20:46
  • where/how would I do that? – blue Jun 06 '18 at 20:46
  • There may or may not be - but with optional I still get same keyNotFound(CodingKeys(stringValue: "pubDate", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "channel", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"pubDate\", intValue: nil) (\"pubDate\").", underlyingError: nil)) – blue Jun 06 '18 at 20:58
  • @Paulw11, this is wrong. Decodable handles optional values by the automatic us of the ```decodeIfPresent``` function on the container. – S.Moore Jun 06 '18 at 21:54

1 Answers1

1

In the XMLParsing library, you will need to make the property an optional if it might not exist in the data.

This is similar to the behavior you will find in Apple's JSONDecoder if the value doesn't exist in the JSON.


In your example, you mentioned pubDate might not exist in your XML, so the updated channel structure would appear as the following:

struct RSSChannel: Codable {
    var title: String
    var pubDate: Date?
    var link: URL
    var description: String
    var items: [RSSItem]

    enum CodingKeys: String, CodingKey {
        case title, pubDate, link, description
        case items = "item"
    }
}

So in the cases where pubDate does exist in your XML, there will be a date in that property. In the cases that the key does not exist in the XML, the value for pubDate will be nil.

You can make as many properties as you want in your structure optional and they will all follow this pattern.

S.Moore
  • 1,277
  • 17
  • 17
  • You're incredible - cant believe I missed that. Was putting the optional in another struct. thank you – blue Jun 06 '18 at 22:18
  • @skyguy FYI - This is what Paulw11 meant in his comment below your question. – rmaddy Jun 06 '18 at 23:07