CoreOffice / XMLCoder

Easy XML parsing using Codable protocols in Swift
https://coreoffice.github.io/XMLCoder/
MIT License
800 stars 112 forks source link

Mixed choice/non-choice decoding #155

Closed bwetherfield closed 4 years ago

bwetherfield commented 4 years ago

Mirrors #154

Fixes bugs 1) Decoding multiple choice elements in the same Keyed Container. 2) Decoding choice elements after decoding regular keyed elements in the same container.

Case 1 refers to decoding implementations of the form:

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        otherValue = try container.decode(String.self, forKey: .otherValue)
        intOrString = try IntOrString(from: decoder)
    }

where IntOrString is a choice coding element

(IntOrString defined as follows)

```swift enum IntOrString { case int(Int) case string(String) } extension IntOrString: Decodable { enum CodingKeys: String, CodingKey { case int case string } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.contains(.int) { self = .int(try container.decode(Int.self, forKey: .int)) } else { self = .string(try container.decode(String.self, forKey: .string)) } } } extension IntOrString.CodingKeys: XMLChoiceCodingKey {} // signifies that `IntOrString` is a choice element ```

Case 2 refers to decoding implementations of the following form:

    init(from decoder: Decoder) throws {
        self.first = try IntOrString(from: decoder)
        self.second = try AlternateIntOrString(from: decoder)
    }

Where both first: IntOrString and second: AlternateIntOrString are choice elements.

(AlternateIntOrString defined as follows)

```swift private enum AlternateIntOrString { case alternateInt(Int) case alternateString(String) } extension AlternateIntOrString: Decodable { enum CodingKeys: String, CodingKey { case alternateInt = "alternate-int" case alternateString = "alternate-string" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.contains(.alternateInt) { self = .alternateInt(try container.decode(Int.self, forKey: .alternateInt)) } else { self = .alternateString(try container.decode(String.self, forKey: .alternateString)) } } } extension AlternateIntOrString.CodingKeys: XMLChoiceCodingKey {} // signifies that `AlternateIntOrString` is a choice element ```