/XMLCoding

A clean and modular Swift implementation of the `Codable` protocol for XML.

Primary LanguageSwift

XMLCoding

A clean and modular implementation of the Codable protocol for XML, consisting of:

Single Value Container

☢️ Node-encodings are NOT applicable when coding with single value containers

struct SingleValueContainer: Codable {
    let value: Int

    init(value: Int) {
        self.value = value
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        self.value = try container.decode(Int.self)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.value)
    }
}
typealias Value = SingleValueContainer

let value = Value(value: 42)

let encoder = XMLEncoder()
encoder.outputFormatting = [.prettyPrinted]

let encoded = try! encoder.encode(value, rootKey: "root")
let string = String(data: encoded, encoding: .utf8)!

let decoder = XMLDecoder
let decoded = try! Value(from: decoder)
<root>42</root>

Keyed Container

struct KeyedContainer: Codable {
    enum CodingKeys: CodingKey {
        case values
    }
    
    let values: [String: Int]

    init(values: [String: Int]) {
        self.values = values
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.values = try container.decode([String: Int].self, forKey: .values)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.values)
    }
}

💡 Node-encodings are applicable when coding with keyed containers

typealias Value = KeyedContainer

let value = Value(values: ["foo": 1, "bar": 2])

let encoder = XMLEncoder()
encoder.outputFormatting = [.prettyPrinted]

let encoded = try! encoder.encode(value, rootKey: "root")
let string = String(data: encoded, encoding: .utf8)!

let decoder = XMLDecoder()
let decoded = try! Value(from: decoder)
<root>
    <foo>1</foo>
    <bar>2</bar>
</root>

Unkeyed Container

struct UnkeyedContainer: Codable {
    enum CodingKeys: CodingKey {
        case values
    }

    @XMLElement()
    let values: [Int]

    init(values: [Int]) {
        self.values = values
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.values = try container.decode([Int].self, forKey: .values)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.values)
    }
}

extension UnkeyedContainer: XMLCustomNodeEncodable {
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        switch
    }
}

☢️ Node-encodings are NOT applicable when coding with unkeyed containers

typealias Value = KeyedContainer

let value = Value(values: ["foo": 1, "bar": 2])

let encoder = XMLEncoder()
encoder.outputFormatting = [.prettyPrinted]

let encoded = try! encoder.encode(value, rootKey: "root")
let string = String(data: encoded, encoding: .utf8)!

let decoder = XMLDecoder()
let decoded = try! Value(from: decoder)
<root>
    <foo>1</foo>
    <bar>2</bar>
</root>

☢️ Node-encodings are not applicable within unkeyed containers