From 2538057e865797e92f2f3a68ae8d70fe76544bd3 Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 15:54:37 +0100 Subject: [PATCH 01/10] Respect .sortedKeys option --- Sources/XMLCoder/Decoder/XMLDecoder.swift | 2 +- Sources/XMLCoder/Encoder/XMLEncoder.swift | 2 +- Sources/XMLCoder/XMLStackParser.swift | 71 ++++++++++++--- .../NodeEncodingStrategyTests.swift | 90 +++++++++++++++++++ 4 files changed, 149 insertions(+), 16 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 460d572e..c146542a 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -123,7 +123,7 @@ open class XMLDecoder { /// Convert from "CodingKey" to "codingKey" case convertFromCapitalized - /// Provide a custom conversion from the key in the encoded JSON to the keys specified by the decoded types. + /// Provide a custom conversion from the key in the encoded XML to the keys specified by the decoded types. /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. case custom((_ codingPath: [CodingKey]) -> CodingKey) diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index acfc15e4..a6d5b883 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -382,7 +382,7 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont private let encoder: _XMLEncoder /// A reference to the container we're writing to. - private let container: NSMutableDictionary + private let container: NSMutableDictionary /// The path of coding keys taken to get to this point in encoding. private(set) public var codingPath: [CodingKey] diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index cb282b32..a02a2033 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -196,16 +196,65 @@ internal class _XMLElement { } } - fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { + fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + for childElement in children { + for child in childElement.value { + string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) + string += prettyPrinted ? "\n" : "" + } + } + } + + fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + for childElement in children.sorted(by: { $0.key < $1.key }) { + for child in childElement.value { + string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) + string += prettyPrinted ? "\n" : "" + } + } + } + + fileprivate func formatSortedXMLAttributes(_ string: inout String) { + for (key, value) in attributes.sorted(by: { $0.key < $1.key }) { + string += " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + } + } + + fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { + for (key, value) in attributes { + string += " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + } + } + + fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLAttributes(&string) + } + } + formatUnsortedXMLAttributes(&string) + } + + fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + } else { + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + } + return + } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + } + + fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { let prettyPrinted = formatting.contains(.prettyPrinted) let indentation = String(repeating: " ", count: (prettyPrinted ? level : 0) * 4) var string = indentation string += "<\(key)" - - for (key, value) in attributes { - string += " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" - } - + + formatXMLAttributes(formatting, &string) + if let value = value { string += ">" if !ignoreEscaping { @@ -216,14 +265,8 @@ internal class _XMLElement { string += "" } else if !children.isEmpty { string += prettyPrinted ? ">\n" : ">" - - for childElement in children { - for child in childElement.value { - string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) - string += prettyPrinted ? "\n" : "" - } - } - + formatXMLElements(formatting, &string, level, cdata, prettyPrinted) + string += indentation string += "" } else { diff --git a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift index a4b5e73d..d8f6f7e1 100644 --- a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift +++ b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift @@ -37,6 +37,32 @@ class NodeEncodingStrategyTests: XCTestCase { return .attribute } } + + fileprivate struct ComplexUnkeyedContainer: Encodable { + let elements: [ComplexElement] + + enum CodingKeys: String, CodingKey { + case elements = "element" + } + } + + fileprivate struct ComplexElement: Encodable { + struct Key: Encodable { + let a: String + let b: String + let c: String + } + + var key: Key = Key(a: "C", b: "B", c: "A") + + enum CodingKeys: CodingKey { + case key + } + + static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { + return .attribute + } + } func testSingleContainer() { let encoder = XMLEncoder() @@ -189,4 +215,68 @@ class NodeEncodingStrategyTests: XCTestCase { ("testKeyedContainer", testKeyedContainer), ("testUnkeyedContainer", testUnkeyedContainer), ] + + func testItSortsKeysWhenEncodingAsElements() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + C + B + A + + + +""" + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } + + func testItSortsKeysWhenEncodingAsAttributes() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + encoder.nodeEncodingStrategy = .custom { key, encoder in + if key == ComplexElement.Key.self { + return { _ in .attribute } + } + return { _ in .element } + } + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + + +""" + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } } From 877258a4db3ed51fa55028247f1d04fedf32adce Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 17:00:49 +0100 Subject: [PATCH 02/10] DRY up the code --- Sources/XMLCoder/XMLStackParser.swift | 53 +++++++++++++++++---------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index a02a2033..9bbf7b61 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -191,46 +191,59 @@ internal class _XMLElement { func toXMLString(with header: XMLHeader? = nil, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { if let header = header, let headerXML = header.toXML() { return headerXML + _toXMLString(withCDATA: cdata, formatting: formatting) - } else { - return _toXMLString(withCDATA: cdata, formatting: formatting) } + return _toXMLString(withCDATA: cdata, formatting: formatting) } fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - for childElement in children { - for child in childElement.value { - string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) - string += prettyPrinted ? "\n" : "" - } + formatXMLElements(from: children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { + var string = "" + for child in childElement.value { + string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) + string += prettyPrinted ? "\n" : "" } + return string } fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - for childElement in children.sorted(by: { $0.key < $1.key }) { - for child in childElement.value { - string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) - string += prettyPrinted ? "\n" : "" - } + formatXMLElements(from: children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func attributeString(key: String, value: String) -> String { + return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + } + + fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { + for (key, value) in keyValuePairs { + string += attributeString(key: key, value: value) } } - fileprivate func formatSortedXMLAttributes(_ string: inout String) { - for (key, value) in attributes.sorted(by: { $0.key < $1.key }) { - string += " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { + for childElement in children { + string += elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) } } + fileprivate func formatSortedXMLAttributes(_ string: inout String) { + formatXMLAttributes(from: attributes.sorted(by: { $0.key < $1.key }), into: &string) + } + fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { - for (key, value) in attributes { - string += " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" - } + formatXMLAttributes(from: attributes.map { (key: $0, value: $1) }, into: &string) } fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { if #available(OSX 10.13, iOS 11.0, *) { if formatting.contains(.sortedKeys) { formatSortedXMLAttributes(&string) + return } + formatUnsortedXMLAttributes(&string) + return } formatUnsortedXMLAttributes(&string) } @@ -239,9 +252,9 @@ internal class _XMLElement { if #available(OSX 10.13, iOS 11.0, *) { if formatting.contains(.sortedKeys) { formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - } else { - formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) return } formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) From 7f710951177a9f49c11c9a93ee7c1cc4b96f6651 Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 17:06:54 +0100 Subject: [PATCH 03/10] Add SwiftFormat configuration with inferred rules --- .swiftformat | 29 ++ Package.swift | 9 +- Sample XML/RJI/RJI.swift | 2 +- .../Decoder/DecodingErrorExtension.swift | 6 +- Sources/XMLCoder/Decoder/XMLDecoder.swift | 94 +++--- .../XMLCoder/Decoder/XMLDecodingStorage.swift | 19 +- .../Decoder/XMLKeyedDecodingContainer.swift | 56 ++-- .../Decoder/XMLUnkeyedDecodingContainer.swift | 12 +- .../Encoder/EncodingErrorExtension.swift | 2 +- Sources/XMLCoder/Encoder/XMLEncoder.swift | 172 +++++------ .../XMLCoder/Encoder/XMLEncodingStorage.swift | 2 +- .../Encoder/XMLReferencingEncoder.swift | 2 +- Sources/XMLCoder/ISO8601DateFormatter.swift | 2 - Sources/XMLCoder/XMLKey.swift | 12 +- Sources/XMLCoder/XMLStackParser.swift | 193 ++++++------ .../NodeEncodingStrategyTests.swift | 282 +++++++++--------- Tests/XMLCoderTests/XMLCoderTests.swift | 15 +- 17 files changed, 467 insertions(+), 442 deletions(-) create mode 100644 .swiftformat diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 00000000..d624b85c --- /dev/null +++ b/.swiftformat @@ -0,0 +1,29 @@ +--allman false +--binarygrouping none +--closingparen balanced +--commas always +--comments indent +--decimalgrouping none +--elseposition same-line +--empty void +--exponentcase lowercase +--exponentgrouping disabled +--fractiongrouping disabled +--header ignore +--hexgrouping none +--hexliteralcase uppercase +--ifdef indent +--importgrouping alphabetized +--indent 4 +--indentcase false +--linebreaks lf +--octalgrouping none +--operatorfunc spaced +--patternlet inline +--ranges nospace +--self insert +--semicolons inline +--stripunusedargs closure-only +--trimwhitespace nonblank-lines +--wraparguments preserve +--wrapcollections beforefirst diff --git a/Package.swift b/Package.swift index cb6843e7..103b8c53 100644 --- a/Package.swift +++ b/Package.swift @@ -9,7 +9,8 @@ let package = Package( // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( name: "XMLCoder", - targets: ["XMLCoder"]), + targets: ["XMLCoder"] + ), ], dependencies: [ // Dependencies declare other packages that this package depends on. @@ -20,9 +21,11 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "XMLCoder", - dependencies: []), + dependencies: [] + ), .testTarget( name: "XMLCoderTests", - dependencies: ["XMLCoder"]), + dependencies: ["XMLCoder"] + ), ] ) diff --git a/Sample XML/RJI/RJI.swift b/Sample XML/RJI/RJI.swift index f303e378..7ac9c1cd 100644 --- a/Sample XML/RJI/RJI.swift +++ b/Sample XML/RJI/RJI.swift @@ -17,7 +17,7 @@ struct RSS: Decodable { var channel: Channel enum CodingKeys: String, CodingKey { - case channel = "channel" + case channel case dc = "xmlns:dc" case sy = "xmlns:sy" diff --git a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift index d60a2c31..810654bb 100644 --- a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift +++ b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift @@ -23,7 +23,7 @@ internal extension DecodingError { let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead." return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description)) } - + /// Returns a description of the type of `value` appropriate for an error message. /// /// - parameter value: The value whose type to describe. @@ -38,12 +38,10 @@ internal extension DecodingError { return "a string/data" } else if value is [Any] { return "an array" - } else if value is [String : Any] { + } else if value is [String: Any] { return "a dictionary" } else { return "\(type(of: value))" } } } - - diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index c146542a..62f7e092 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -15,6 +15,7 @@ import Foundation /// `XMLDecoder` facilitates the decoding of XML into semantic `Decodable` types. open class XMLDecoder { // MARK: Options + /// The strategy to use for decoding `Date` values. public enum DateDecodingStrategy { /// Defer to `Date` for decoding. This is the default strategy. @@ -45,7 +46,7 @@ open class XMLDecoder { guard let container = try? decoder.singleValueContainer(), let text = try? container.decode(String.self) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) } guard let dateFormatter = try formatterForKey(codingKey) else { @@ -81,7 +82,7 @@ open class XMLDecoder { guard let container = try? decoder.singleValueContainer(), let text = try? container.decode(String.self) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) } guard let data = try formatterForKey(codingKey) else { @@ -119,15 +120,15 @@ open class XMLDecoder { /// /// - Note: Using a key decoding strategy has a nominal performance cost, as each string key has to be inspected for the `_` character. case convertFromSnakeCase - + /// Convert from "CodingKey" to "codingKey" case convertFromCapitalized - + /// Provide a custom conversion from the key in the encoded XML to the keys specified by the decoded types. /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. case custom((_ codingPath: [CodingKey]) -> CodingKey) - + static func _convertFromCapitalized(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } var result = stringKey @@ -156,7 +157,7 @@ open class XMLDecoder { let trailingUnderscoreRange = stringKey.index(after: lastNonUnderscore)..(_ type: T.Type, from data: Data) throws -> T { + open func decode(_ type: T.Type, from data: Data) throws -> T { let topLevel: [String: Any] do { topLevel = try _XMLStackParser.parse(with: data) @@ -247,7 +250,7 @@ open class XMLDecoder { // MARK: - _XMLDecoder -internal class _XMLDecoder : Decoder { +internal class _XMLDecoder: Decoder { // MARK: Properties /// The decoder's storage. @@ -257,10 +260,10 @@ internal class _XMLDecoder : Decoder { internal let options: XMLDecoder._Options /// The path to the current point in encoding. - internal(set) public var codingPath: [CodingKey] + public internal(set) var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { + public var userInfo: [CodingUserInfoKey: Any] { return self.options.userInfo } @@ -283,8 +286,8 @@ internal class _XMLDecoder : Decoder { debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } - guard let topContainer = self.storage.topContainer as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: self.storage.topContainer) + guard let topContainer = self.storage.topContainer as? [String: Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String: Any].self, reality: self.storage.topContainer) } let container = _XMLKeyedDecodingContainer(referencing: self, wrapping: topContainer) @@ -302,7 +305,7 @@ internal class _XMLDecoder : Decoder { if let container = self.storage.topContainer as? [Any] { topContainer = container - } else if let container = self.storage.topContainer as? [AnyHashable: Any] { + } else if let container = self.storage.topContainer as? [AnyHashable: Any] { topContainer = [container] } else { throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: self.storage.topContainer) @@ -316,8 +319,7 @@ internal class _XMLDecoder : Decoder { } } - -extension _XMLDecoder : SingleValueDecodingContainer { +extension _XMLDecoder: SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods private func expectNonNull(_ type: T.Type) throws { @@ -331,77 +333,77 @@ extension _XMLDecoder : SingleValueDecodingContainer { } public func decode(_ type: Bool.Type) throws -> Bool { - try expectNonNull(Bool.self) + try self.expectNonNull(Bool.self) return try self.unbox(self.storage.topContainer, as: Bool.self)! } public func decode(_ type: Int.Type) throws -> Int { - try expectNonNull(Int.self) + try self.expectNonNull(Int.self) return try self.unbox(self.storage.topContainer, as: Int.self)! } public func decode(_ type: Int8.Type) throws -> Int8 { - try expectNonNull(Int8.self) + try self.expectNonNull(Int8.self) return try self.unbox(self.storage.topContainer, as: Int8.self)! } public func decode(_ type: Int16.Type) throws -> Int16 { - try expectNonNull(Int16.self) + try self.expectNonNull(Int16.self) return try self.unbox(self.storage.topContainer, as: Int16.self)! } public func decode(_ type: Int32.Type) throws -> Int32 { - try expectNonNull(Int32.self) + try self.expectNonNull(Int32.self) return try self.unbox(self.storage.topContainer, as: Int32.self)! } public func decode(_ type: Int64.Type) throws -> Int64 { - try expectNonNull(Int64.self) + try self.expectNonNull(Int64.self) return try self.unbox(self.storage.topContainer, as: Int64.self)! } public func decode(_ type: UInt.Type) throws -> UInt { - try expectNonNull(UInt.self) + try self.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) + try self.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) + try self.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) + try self.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) + try self.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) + try self.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) + try self.expectNonNull(Double.self) return try self.unbox(self.storage.topContainer, as: Double.self)! } public func decode(_ type: String.Type) throws -> String { - try expectNonNull(String.self) + try self.expectNonNull(String.self) return try self.unbox(self.storage.topContainer, as: String.self)! } - public func decode(_ type: T.Type) throws -> T { - try expectNonNull(type) + public func decode(_ type: T.Type) throws -> T { + try self.expectNonNull(type) return try self.unbox(self.storage.topContainer, as: type)! } } @@ -672,7 +674,7 @@ extension _XMLDecoder { } return Float(double) - } else if case let .convertFromString(posInfString, negInfString, nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { if string == posInfString { return Float.infinity } else if string == negInfString { @@ -691,13 +693,12 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } if let number = Decimal(string: string) as NSDecimalNumber? { - guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) } return number.doubleValue - } else if case let .convertFromString(posInfString, negInfString, nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { if string == posInfString { return Double.infinity } else if string == negInfString { @@ -799,7 +800,7 @@ extension _XMLDecoder { return Decimal(doubleValue) } - internal func unbox(_ value: Any, as type: T.Type) throws -> T? { + internal func unbox(_ value: Any, as type: T.Type) throws -> T? { let decoded: T if type == Date.self || type == NSDate.self { guard let date = try self.unbox(value, as: Date.self) else { return nil } @@ -830,4 +831,3 @@ extension _XMLDecoder { return decoded } } - diff --git a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift index 41d19b50..cf27e453 100644 --- a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift +++ b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift @@ -12,34 +12,33 @@ import Foundation internal struct _XMLDecodingStorage { // MARK: Properties - + /// The container stack. /// Elements may be any one of the XML types (String, [String : Any]). - private(set) internal var containers: [Any] = [] - + internal private(set) var containers: [Any] = [] + // MARK: - Initialization - + /// Initializes `self` with no containers. internal init() {} - + // MARK: - Modifying the Stack - + internal var count: Int { return self.containers.count } - + internal var topContainer: Any { precondition(!self.containers.isEmpty, "Empty container stack.") return self.containers.last! } - + internal mutating func push(container: Any) { self.containers.append(container) } - + internal mutating func popContainer() { precondition(!self.containers.isEmpty, "Empty container stack.") self.containers.removeLast() } } - diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index d2fa3e44..dbe0d6eb 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -10,7 +10,7 @@ import Foundation // MARK: Decoding Containers -internal struct _XMLKeyedDecodingContainer : KeyedDecodingContainerProtocol { +internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainerProtocol { typealias Key = K // MARK: Properties @@ -19,15 +19,15 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain private let decoder: _XMLDecoder /// A reference to the container we're reading from. - private let container: [String : Any] + private let container: [String: Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - internal init(referencing decoder: _XMLDecoder, wrapping container: [String : Any]) { + internal init(referencing decoder: _XMLDecoder, wrapping container: [String: Any]) { self.decoder = decoder switch decoder.options.keyDecodingStrategy { case .useDefaultKeys: @@ -37,15 +37,15 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with dictionaries. self.container = Dictionary(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) - }, uniquingKeysWith: { (first, _) in first }) + }, uniquingKeysWith: { first, _ in first }) case .convertFromCapitalized: self.container = Dictionary(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromCapitalized(key), value) - }, uniquingKeysWith: { (first, _) in first }) + }, uniquingKeysWith: { first, _ in first }) case .custom(let converter): self.container = Dictionary(container.map { key, value in (converter(decoder.codingPath + [_XMLKey(stringValue: key, intValue: nil)]).stringValue, value) - }, uniquingKeysWith: { (first, _) in first }) + }, uniquingKeysWith: { first, _ in first }) } self.codingPath = decoder.codingPath } @@ -61,7 +61,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain } private func _errorDescription(of key: CodingKey) -> String { - switch decoder.options.keyDecodingStrategy { + switch self.decoder.options.keyDecodingStrategy { case .convertFromSnakeCase: // In this case we can attempt to recover the original value by reversing the transform let original = key.stringValue @@ -87,7 +87,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -102,7 +102,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -117,7 +117,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -132,7 +132,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -147,7 +147,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -162,7 +162,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -177,7 +177,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -192,7 +192,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -207,7 +207,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -222,7 +222,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -237,7 +237,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -252,7 +252,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -267,7 +267,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -282,7 +282,7 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: String.Type, forKey key: Key) throws -> String { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -295,9 +295,9 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain return value } - public func decode(_ type: T.Type, forKey key: Key) throws -> T { + public func decode(_ type: T.Type, forKey key: Key) throws -> T { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -320,8 +320,8 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"")) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String: Any].self, reality: value) } let container = _XMLKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) @@ -354,10 +354,10 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain } public func superDecoder() throws -> Decoder { - return try _superDecoder(forKey: _XMLKey.super) + return try self._superDecoder(forKey: _XMLKey.super) } public func superDecoder(forKey key: Key) throws -> Decoder { - return try _superDecoder(forKey: key) + return try self._superDecoder(forKey: key) } } diff --git a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift index 87e3f417..cc669251 100644 --- a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift @@ -8,7 +8,7 @@ import Foundation -internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { +internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { // MARK: Properties /// A reference to the decoder we're reading from. @@ -18,10 +18,10 @@ internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { private let container: [Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The index of the element we're about to decode. - private(set) public var currentIndex: Int + public private(set) var currentIndex: Int // MARK: - Initialization @@ -280,7 +280,7 @@ internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { return decoded } - public mutating func decode(_ type: T.Type) throws -> T { + public mutating func decode(_ type: T.Type) throws -> T { guard !self.isAtEnd else { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } @@ -313,8 +313,8 @@ internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String: Any].self, reality: value) } self.currentIndex += 1 diff --git a/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift b/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift index acc4f405..f2e83865 100644 --- a/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift +++ b/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift @@ -18,7 +18,7 @@ internal extension EncodingError { /// - parameter value: The value that was invalid to encode. /// - parameter path: The path of `CodingKey`s taken to encode this value. /// - returns: An `EncodingError` with the appropriate path and debug description. - internal static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + internal static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { let valueDescription: String if value == T.infinity { valueDescription = "\(T.self).infinity" diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index a6d5b883..911cd613 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -15,8 +15,9 @@ import Foundation /// `XMLEncoder` facilitates the encoding of `Encodable` values into XML. open class XMLEncoder { // MARK: Options + /// The formatting of the output XML data. - public struct OutputFormatting : OptionSet { + public struct OutputFormatting: OptionSet { /// The format's default value. public let rawValue: UInt @@ -30,14 +31,14 @@ open class XMLEncoder { /// Produce XML with dictionary keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) + public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) } - + /// A node's encoding tyoe public enum NodeEncoding { case attribute case element - + public static let `default`: NodeEncoding = .element } @@ -126,7 +127,7 @@ open class XMLEncoder { internal static func _convertToSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - var words : [Range] = [] + var words: [Range] = [] // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase // // myProperty -> my_property @@ -166,24 +167,24 @@ open class XMLEncoder { searchRange = lowerCaseRange.upperBound.. ((CodingKey) -> XMLEncoder.NodeEncoding)) - + internal func nodeEncodings( forType codableType: Encodable.Type, with encoder: Encoder @@ -219,7 +220,7 @@ open class XMLEncoder { open var stringEncodingStrategy: StringEncodingStrategy = .deferredToString /// Contextual user-provided information for use during encoding. - open var userInfo: [CodingUserInfoKey : Any] = [:] + open var userInfo: [CodingUserInfoKey: Any] = [:] /// Options set on the top-level encoder to pass down the encoding hierarchy. internal struct _Options { @@ -229,25 +230,27 @@ open class XMLEncoder { let keyEncodingStrategy: KeyEncodingStrategy let nodeEncodingStrategy: NodeEncodingStrategy let stringEncodingStrategy: StringEncodingStrategy - let userInfo: [CodingUserInfoKey : Any] + let userInfo: [CodingUserInfoKey: Any] } /// The options set on the top-level encoder. internal var options: _Options { - return _Options(dateEncodingStrategy: dateEncodingStrategy, - dataEncodingStrategy: dataEncodingStrategy, - nonConformingFloatEncodingStrategy: nonConformingFloatEncodingStrategy, - keyEncodingStrategy: keyEncodingStrategy, - nodeEncodingStrategy: nodeEncodingStrategy, - stringEncodingStrategy: stringEncodingStrategy, - userInfo: userInfo) + return _Options(dateEncodingStrategy: self.dateEncodingStrategy, + dataEncodingStrategy: self.dataEncodingStrategy, + nonConformingFloatEncodingStrategy: self.nonConformingFloatEncodingStrategy, + keyEncodingStrategy: self.keyEncodingStrategy, + nodeEncodingStrategy: self.nodeEncodingStrategy, + stringEncodingStrategy: self.stringEncodingStrategy, + userInfo: self.userInfo) } // MARK: - Constructing a XML Encoder + /// Initializes `self` with default strategies. public init() {} // MARK: - Encoding Values + /// Encodes the given top-level value and returns its XML representation. /// /// - parameter value: The value to encode. @@ -255,7 +258,7 @@ open class XMLEncoder { /// - returns: A new `Data` value containing the encoded XML data. /// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. /// - throws: An error if any value throws an error during encoding. - open func encode(_ value: T, withRootKey rootKey: String, header: XMLHeader? = nil) throws -> Data { + open func encode(_ value: T, withRootKey rootKey: String, header: XMLHeader? = nil) throws -> Data { let encoder = _XMLEncoder( options: self.options, nodeEncodings: [] @@ -277,7 +280,7 @@ open class XMLEncoder { guard let element = _XMLElement.createRootElement(rootKey: rootKey, object: topLevel) else { throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Unable to encode the given top-level value to XML.")) } - + let withCDATA = stringEncodingStrategy != .deferredToString return element.toXMLString(with: header, withCDATA: withCDATA, formatting: self.outputFormatting).data(using: .utf8, allowLossyConversion: true)! } @@ -294,11 +297,11 @@ internal class _XMLEncoder: Encoder { /// The path to the current point in encoding. public var codingPath: [CodingKey] - + public var nodeEncodings: [(CodingKey) -> XMLEncoder.NodeEncoding] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { + public var userInfo: [CodingUserInfoKey: Any] { return self.options.userInfo } @@ -330,6 +333,7 @@ internal class _XMLEncoder: Encoder { } // MARK: - Encoder Methods + public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. let topContainer: NSMutableDictionary @@ -343,8 +347,7 @@ internal class _XMLEncoder: Encoder { topContainer = container } - - + let container = _XMLKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) return KeyedEncodingContainer(container) } @@ -373,7 +376,7 @@ internal class _XMLEncoder: Encoder { // MARK: - Encoding Containers -fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingContainerProtocol { +fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContainerProtocol { typealias Key = K // MARK: Properties @@ -382,10 +385,10 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont private let encoder: _XMLEncoder /// A reference to the container we're writing to. - private let container: NSMutableDictionary + private let container: NSMutableDictionary /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization @@ -399,14 +402,14 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont // MARK: - Coding Path Operations private func _converted(_ key: CodingKey) -> CodingKey { - switch encoder.options.keyEncodingStrategy { + switch self.encoder.options.keyEncodingStrategy { case .useDefaultKeys: return key case .convertToSnakeCase: let newKeyString = XMLEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _XMLKey(stringValue: newKeyString, intValue: key.intValue) case .custom(let converter): - return converter(codingPath + [key]) + return converter(self.codingPath + [key]) } } @@ -684,7 +687,7 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont } } - public mutating func encode(_ value: T, forKey key: Key) throws { + public mutating func encode(_ value: T, forKey key: Key) throws { guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") } @@ -695,7 +698,7 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont ) self.encoder.nodeEncodings.append(nodeEncodings) defer { - let _ = self.encoder.nodeEncodings.removeLast() + _ = self.encoder.nodeEncodings.removeLast() self.encoder.codingPath.removeLast() } switch strategy(key) { @@ -733,15 +736,15 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont } public mutating func superEncoder() -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, key: _XMLKey.super, convertedKey: _converted(_XMLKey.super), wrapping: self.container) + return _XMLReferencingEncoder(referencing: self.encoder, key: _XMLKey.super, convertedKey: self._converted(_XMLKey.super), wrapping: self.container) } public mutating func superEncoder(forKey key: Key) -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, key: key, convertedKey: _converted(key), wrapping: self.container) + return _XMLReferencingEncoder(referencing: self.encoder, key: key, convertedKey: self._converted(key), wrapping: self.container) } } -fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { +fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { // MARK: Properties /// A reference to the encoder we're writing to. @@ -751,7 +754,7 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { private let container: NSMutableArray /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The number of elements encoded into the container. public var count: Int { @@ -769,21 +772,21 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - public mutating func encodeNil() throws { self.container.add(NSNull()) } - public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } + public mutating func encodeNil() throws { self.container.add(NSNull()) } + public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Float) throws { + public mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. self.encoder.codingPath.append(_XMLKey(index: self.count)) defer { self.encoder.codingPath.removeLast() } @@ -797,7 +800,7 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { self.container.add(try self.encoder.box(value)) } - public mutating func encode(_ value: T) throws { + public mutating func encode(_ value: T) throws { self.encoder.codingPath.append(_XMLKey(index: self.count)) let nodeEncodings = self.encoder.options.nodeEncodingStrategy.nodeEncodings( forType: T.self, @@ -805,7 +808,7 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { ) self.encoder.nodeEncodings.append(nodeEncodings) defer { - let _ = self.encoder.nodeEncodings.removeLast() + _ = self.encoder.nodeEncodings.removeLast() self.encoder.codingPath.removeLast() } self.container.add(try self.encoder.box(value)) @@ -844,96 +847,96 @@ extension _XMLEncoder: SingleValueEncodingContainer { } public func encodeNil() throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: NSNull()) } public func encode(_ value: Bool) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int8) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int16) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int32) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int64) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt8) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt16) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt32) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt64) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: String) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Float) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() try self.storage.push(container: self.box(value)) } public func encode(_ value: Double) throws { - assertCanEncodeNewValue() + self.assertCanEncodeNewValue() try self.storage.push(container: self.box(value)) } - public func encode(_ value: T) throws { - assertCanEncodeNewValue() + public func encode(_ value: T) throws { + self.assertCanEncodeNewValue() try self.storage.push(container: self.box(value)) } } extension _XMLEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } @@ -941,8 +944,8 @@ extension _XMLEncoder { internal func box(_ value: Float) throws -> NSObject { if value.isInfinite || value.isNaN { - guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(value, at: codingPath) + guard case .convertToString(let positiveInfinity: posInfString, let negativeInfinity: negInfString, let nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + throw EncodingError._invalidFloatingPointValue(value, at: self.codingPath) } if value == Float.infinity { @@ -959,8 +962,8 @@ extension _XMLEncoder { internal func box(_ value: Double) throws -> NSObject { if value.isInfinite || value.isNaN { - guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(value, at: codingPath) + guard case .convertToString(let positiveInfinity: posInfString, let negativeInfinity: negInfString, let nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + throw EncodingError._invalidFloatingPointValue(value, at: self.codingPath) } if value == Double.infinity { @@ -995,9 +998,9 @@ extension _XMLEncoder { case .custom(let closure): let depth = self.storage.count try closure(value, self) - + guard self.storage.count > depth else { return NSDictionary() } - + return self.storage.popContainer() } } @@ -1012,19 +1015,19 @@ extension _XMLEncoder { case .custom(let closure): let depth = self.storage.count try closure(value, self) - + guard self.storage.count > depth else { return NSDictionary() } - + return self.storage.popContainer() as NSObject } } - fileprivate func box(_ value: T) throws -> NSObject { + fileprivate func box(_ value: T) throws -> NSObject { return try self.box_(value) ?? NSDictionary() } // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. - fileprivate func box_(_ value: T) throws -> NSObject? { + fileprivate func box_(_ value: T) throws -> NSObject? { if T.self == Date.self || T.self == NSDate.self { return try self.box((value as! Date)) } else if T.self == Data.self || T.self == NSData.self { @@ -1046,4 +1049,3 @@ extension _XMLEncoder { return self.storage.popContainer() } } - diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index ded3b4eb..ac7b9d75 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -16,7 +16,7 @@ internal struct _XMLEncodingStorage { /// The container stack. /// Elements may be any one of the XML types (NSNull, NSNumber, NSString, NSArray, NSDictionary). - private(set) internal var containers: [NSObject] = [] + internal private(set) var containers: [NSObject] = [] // MARK: - Initialization diff --git a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift index 9da655ca..2c36b9c0 100644 --- a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift @@ -12,7 +12,7 @@ import Foundation /// _XMLReferencingEncoder is a special subclass of _XMLEncoder which has its own storage, but references the contents of a different encoder. /// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). -internal class _XMLReferencingEncoder : _XMLEncoder { +internal class _XMLReferencingEncoder: _XMLEncoder { // MARK: Reference types. /// The type of container we're referencing. diff --git a/Sources/XMLCoder/ISO8601DateFormatter.swift b/Sources/XMLCoder/ISO8601DateFormatter.swift index 85fb6889..f8e05ae5 100644 --- a/Sources/XMLCoder/ISO8601DateFormatter.swift +++ b/Sources/XMLCoder/ISO8601DateFormatter.swift @@ -19,5 +19,3 @@ internal var _iso8601Formatter: ISO8601DateFormatter = { formatter.formatOptions = .withInternetDateTime return formatter }() - - diff --git a/Sources/XMLCoder/XMLKey.swift b/Sources/XMLCoder/XMLKey.swift index ffc8f293..27a9f882 100644 --- a/Sources/XMLCoder/XMLKey.swift +++ b/Sources/XMLCoder/XMLKey.swift @@ -12,15 +12,15 @@ import Foundation // Shared Key Types //===----------------------------------------------------------------------===// -internal struct _XMLKey : CodingKey { +internal struct _XMLKey: CodingKey { public var stringValue: String public var intValue: Int? - + public init?(stringValue: String) { self.stringValue = stringValue self.intValue = nil } - + public init?(intValue: Int) { self.stringValue = "\(intValue)" self.intValue = intValue @@ -30,13 +30,11 @@ internal struct _XMLKey : CodingKey { self.stringValue = stringValue self.intValue = intValue } - + internal init(index: Int) { self.stringValue = "Index \(index)" self.intValue = index } - + internal static let `super` = _XMLKey(stringValue: "super")! } - - diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index 9bbf7b61..ba8a235c 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -19,7 +19,7 @@ public struct XMLHeader { public let encoding: String? /// indicates whether a document relies on information from an external source. public let standalone: String? - + public init(version: Double? = nil, encoding: String? = nil, standalone: String? = nil) { self.version = version self.encoding = encoding @@ -27,7 +27,7 @@ public struct XMLHeader { } internal func isEmpty() -> Bool { - return version == nil && encoding == nil && standalone == nil + return self.version == nil && self.encoding == nil && self.standalone == nil } internal func toXML() -> String? { @@ -53,10 +53,10 @@ public struct XMLHeader { internal class _XMLElement { static let attributesKey = "___ATTRIBUTES" - static let escapedCharacterSet = [("&", "&"), ("<", "<"), (">", ">"), ( "'", "'"), ("\"", """)] + static let escapedCharacterSet = [("&", "&"), ("<", "<"), (">", ">"), ("'", "'"), ("\"", """)] var key: String - var value: String? = nil + var value: String? var attributes: [String: String] = [:] var children: [String: [_XMLElement]] = [:] @@ -156,7 +156,7 @@ internal class _XMLElement { fileprivate func flatten() -> [String: Any] { var node: [String: Any] = attributes - for childElement in children { + for childElement in self.children { for child in childElement.value { if let content = child.value { if let oldContent = node[childElement.key] as? Array { @@ -187,101 +187,101 @@ internal class _XMLElement { return node } - + func toXMLString(with header: XMLHeader? = nil, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { if let header = header, let headerXML = header.toXML() { - return headerXML + _toXMLString(withCDATA: cdata, formatting: formatting) + return headerXML + self._toXMLString(withCDATA: cdata, formatting: formatting) } - return _toXMLString(withCDATA: cdata, formatting: formatting) + return self._toXMLString(withCDATA: cdata, formatting: formatting) } - fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - formatXMLElements(from: children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - - fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { - var string = "" - for child in childElement.value { - string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) - string += prettyPrinted ? "\n" : "" - } - return string - } - - fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - formatXMLElements(from: children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - - fileprivate func attributeString(key: String, value: String) -> String { - return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" - } - - fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { - for (key, value) in keyValuePairs { - string += attributeString(key: key, value: value) - } - } - - fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { - for childElement in children { - string += elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - } - - fileprivate func formatSortedXMLAttributes(_ string: inout String) { - formatXMLAttributes(from: attributes.sorted(by: { $0.key < $1.key }), into: &string) - } - - fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { - formatXMLAttributes(from: attributes.map { (key: $0, value: $1) }, into: &string) - } - - fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { - if #available(OSX 10.13, iOS 11.0, *) { - if formatting.contains(.sortedKeys) { - formatSortedXMLAttributes(&string) - return - } - formatUnsortedXMLAttributes(&string) - return - } - formatUnsortedXMLAttributes(&string) - } - - fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { - if #available(OSX 10.13, iOS 11.0, *) { - if formatting.contains(.sortedKeys) { - formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - return - } - formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - return - } - formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - } - - fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { + fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + self.formatXMLElements(from: self.children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { + var string = "" + for child in childElement.value { + string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) + string += prettyPrinted ? "\n" : "" + } + return string + } + + fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + self.formatXMLElements(from: self.children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func attributeString(key: String, value: String) -> String { + return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + } + + fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { + for (key, value) in keyValuePairs { + string += self.attributeString(key: key, value: value) + } + } + + fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { + for childElement in children { + string += self.elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + } + + fileprivate func formatSortedXMLAttributes(_ string: inout String) { + self.formatXMLAttributes(from: self.attributes.sorted(by: { $0.key < $1.key }), into: &string) + } + + fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { + self.formatXMLAttributes(from: self.attributes.map { (key: $0, value: $1) }, into: &string) + } + + fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLAttributes(&string) + return + } + formatUnsortedXMLAttributes(&string) + return + } + self.formatUnsortedXMLAttributes(&string) + } + + fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return + } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return + } + self.formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + } + + fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { let prettyPrinted = formatting.contains(.prettyPrinted) let indentation = String(repeating: " ", count: (prettyPrinted ? level : 0) * 4) var string = indentation string += "<\(key)" - - formatXMLAttributes(formatting, &string) - + + formatXMLAttributes(formatting, &string) + if let value = value { string += ">" if !ignoreEscaping { - string += (cdata == true ? "" : "\(value.escape(_XMLElement.escapedCharacterSet))" ) + string += (cdata == true ? "" : "\(value.escape(_XMLElement.escapedCharacterSet))") } else { string += "\(value)" } - string += "" - } else if !children.isEmpty { + string += "" + } else if !self.children.isEmpty { string += prettyPrinted ? ">\n" : ">" - formatXMLElements(formatting, &string, level, cdata, prettyPrinted) - + self.formatXMLElements(formatting, &string, level, cdata, prettyPrinted) + string += indentation - string += "" + string += "" } else { string += " />" } @@ -324,12 +324,12 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } } - func parse(with data: Data) throws -> _XMLElement? { + func parse(with data: Data) throws -> _XMLElement? { let xmlParser = XMLParser(data: data) xmlParser.delegate = self if xmlParser.parse() { - return root + return self.root } else if let error = xmlParser.parserError { throw error } else { @@ -338,11 +338,11 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } func parserDidStartDocument(_ parser: XMLParser) { - root = nil - stack = [_XMLElement]() + self.root = nil + self.stack = [_XMLElement]() } - func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { + func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String] = [:]) { let node = _XMLElement(key: elementName) node.attributes = attributeDict stack.append(node) @@ -354,11 +354,11 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { currentNode.children[elementName] = [node] } } - currentNode = node + self.currentNode = node } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { - if let poppedNode = stack.popLast(){ + if let poppedNode = stack.popLast() { if let content = poppedNode.value?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) { if content.isEmpty { poppedNode.value = nil @@ -367,22 +367,22 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } } - if (stack.isEmpty) { - root = poppedNode - currentNode = nil + if self.stack.isEmpty { + self.root = poppedNode + self.currentNode = nil } else { - currentNode = stack.last + self.currentNode = self.stack.last } } } func parser(_ parser: XMLParser, foundCharacters string: String) { - currentNode?.value = (currentNode?.value ?? "") + string + self.currentNode?.value = (self.currentNode?.value ?? "") + string } func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) { if let string = String(data: CDATABlock, encoding: .utf8) { - currentNode?.value = (currentNode?.value ?? "") + string + self.currentNode?.value = (self.currentNode?.value ?? "") + string } } @@ -390,4 +390,3 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { print(parseError) } } - diff --git a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift index d8f6f7e1..0a320e21 100644 --- a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift +++ b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift @@ -6,7 +6,7 @@ class NodeEncodingStrategyTests: XCTestCase { let element: Element enum CodingKeys: String, CodingKey { - case element = "element" + case element } } @@ -37,32 +37,32 @@ class NodeEncodingStrategyTests: XCTestCase { return .attribute } } - - fileprivate struct ComplexUnkeyedContainer: Encodable { - let elements: [ComplexElement] - - enum CodingKeys: String, CodingKey { - case elements = "element" - } - } - - fileprivate struct ComplexElement: Encodable { - struct Key: Encodable { - let a: String - let b: String - let c: String - } - - var key: Key = Key(a: "C", b: "B", c: "A") - - enum CodingKeys: CodingKey { - case key - } - - static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { - return .attribute - } - } + + fileprivate struct ComplexUnkeyedContainer: Encodable { + let elements: [ComplexElement] + + enum CodingKeys: String, CodingKey { + case elements = "element" + } + } + + fileprivate struct ComplexElement: Encodable { + struct Key: Encodable { + let a: String + let b: String + let c: String + } + + var key: Key = Key(a: "C", b: "B", c: "A") + + enum CodingKeys: CodingKey { + case key + } + + static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { + return .attribute + } + } func testSingleContainer() { let encoder = XMLEncoder() @@ -74,21 +74,21 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - value - - -""" + """ + + + value + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, encoder in + encoder.nodeEncodingStrategy = .custom { codableType, _ in guard let barType = codableType as? Element.Type else { - return { _ in return .default } + return { _ in .default } } return barType.nodeEncoding(forKey:) } @@ -99,11 +99,11 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - -""" + """ + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -120,23 +120,23 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - value - - - -""" + """ + + + + value + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, encoder in + encoder.nodeEncodingStrategy = .custom { codableType, _ in guard let barType = codableType as? Element.Type else { - return { _ in return .default } + return { _ in .default } } return barType.nodeEncoding(forKey:) } @@ -147,13 +147,13 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - - -""" + """ + + + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -170,24 +170,24 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - value - - - value - - -""" + """ + + + value + + + value + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, encoder in + encoder.nodeEncodingStrategy = .custom { codableType, _ in guard let barType = codableType as? Element.Type else { - return { _ in return .default } + return { _ in .default } } return barType.nodeEncoding(forKey:) } @@ -198,12 +198,12 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - - -""" + """ + + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -215,68 +215,68 @@ class NodeEncodingStrategyTests: XCTestCase { ("testKeyedContainer", testKeyedContainer), ("testUnkeyedContainer", testUnkeyedContainer), ] - - func testItSortsKeysWhenEncodingAsElements() { - let encoder = XMLEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = [.sortedKeys, .prettyPrinted] - } else { - return - } - - do { - let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) - let data = try encoder.encode(container, withRootKey: "container") - let xml = String(data: data, encoding: .utf8)! - - let expected = - """ - - - - C - B - A - - - -""" - XCTAssertEqual(xml, expected) - } catch { - XCTAssert(false, "failed to decode the example: \(error)") - } - } - - func testItSortsKeysWhenEncodingAsAttributes() { - let encoder = XMLEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = [.sortedKeys, .prettyPrinted] - encoder.nodeEncodingStrategy = .custom { key, encoder in - if key == ComplexElement.Key.self { - return { _ in .attribute } - } - return { _ in .element } - } - } else { - return - } - - do { - let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) - let data = try encoder.encode(container, withRootKey: "container") - let xml = String(data: data, encoding: .utf8)! - - let expected = - """ - - - - - -""" - XCTAssertEqual(xml, expected) - } catch { - XCTAssert(false, "failed to decode the example: \(error)") - } - } + + func testItSortsKeysWhenEncodingAsElements() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + C + B + A + + + + """ + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } + + func testItSortsKeysWhenEncodingAsAttributes() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + encoder.nodeEncodingStrategy = .custom { key, _ in + if key == ComplexElement.Key.self { + return { _ in .attribute } + } + return { _ in .element } + } + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + + + """ + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } } diff --git a/Tests/XMLCoderTests/XMLCoderTests.swift b/Tests/XMLCoderTests/XMLCoderTests.swift index 5234dc3f..7945a8ff 100644 --- a/Tests/XMLCoderTests/XMLCoderTests.swift +++ b/Tests/XMLCoderTests/XMLCoderTests.swift @@ -20,7 +20,7 @@ let example = """ struct Relationships: Codable { let items: [Relationship] - + enum CodingKeys: String, CodingKey { case items = "relationship" } @@ -32,11 +32,11 @@ struct Relationship: Codable { case extendedProperties = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" case coreProperties = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" } - + let id: String let type: SchemaType let target: String - + enum CodingKeys: CodingKey { case type case id @@ -48,19 +48,18 @@ class XMLCoderTests: XCTestCase { func testExample() { do { guard let data = example.data(using: .utf8) else { return } - + let decoder = XMLDecoder() decoder.keyDecodingStrategy = .convertFromCapitalized - + let rels = try decoder.decode(Relationships.self, from: data) - + XCTAssertEqual(rels.items[0].id, "rId1") } catch { XCTAssert(false, "failed to decode the example: \(error)") } } - - + static var allTests = [ ("testExample", testExample), ] From 29c9e42df3659d7bb817ade1650b747727c34a3d Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 17:30:33 +0100 Subject: [PATCH 04/10] Simplify .swiftformat --- .swiftformat | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/.swiftformat b/.swiftformat index d624b85c..dad8899a 100644 --- a/.swiftformat +++ b/.swiftformat @@ -1,29 +1,5 @@ ---allman false ---binarygrouping none ---closingparen balanced ---commas always ---comments indent ---decimalgrouping none ---elseposition same-line ---empty void ---exponentcase lowercase ---exponentgrouping disabled ---fractiongrouping disabled ---header ignore ---hexgrouping none ---hexliteralcase uppercase ---ifdef indent ---importgrouping alphabetized --indent 4 --indentcase false --linebreaks lf ---octalgrouping none ---operatorfunc spaced ---patternlet inline ---ranges nospace ---self insert ---semicolons inline --stripunusedargs closure-only --trimwhitespace nonblank-lines ---wraparguments preserve ---wrapcollections beforefirst From 26eddf5227d11f6e4a7fdb9868763c73a502c57e Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 17:31:40 +0100 Subject: [PATCH 05/10] Revert "Add SwiftFormat configuration with inferred rules" This reverts commit 7f710951177a9f49c11c9a93ee7c1cc4b96f6651. # Conflicts: # .swiftformat --- Package.swift | 9 +- Sample XML/RJI/RJI.swift | 2 +- .../Decoder/DecodingErrorExtension.swift | 6 +- Sources/XMLCoder/Decoder/XMLDecoder.swift | 94 +++--- .../XMLCoder/Decoder/XMLDecodingStorage.swift | 19 +- .../Decoder/XMLKeyedDecodingContainer.swift | 56 ++-- .../Decoder/XMLUnkeyedDecodingContainer.swift | 12 +- .../Encoder/EncodingErrorExtension.swift | 2 +- Sources/XMLCoder/Encoder/XMLEncoder.swift | 172 ++++++----- .../XMLCoder/Encoder/XMLEncodingStorage.swift | 2 +- .../Encoder/XMLReferencingEncoder.swift | 2 +- Sources/XMLCoder/ISO8601DateFormatter.swift | 2 + Sources/XMLCoder/XMLKey.swift | 12 +- Sources/XMLCoder/XMLStackParser.swift | 193 ++++++------ .../NodeEncodingStrategyTests.swift | 282 +++++++++--------- Tests/XMLCoderTests/XMLCoderTests.swift | 15 +- 16 files changed, 442 insertions(+), 438 deletions(-) diff --git a/Package.swift b/Package.swift index 103b8c53..cb6843e7 100644 --- a/Package.swift +++ b/Package.swift @@ -9,8 +9,7 @@ let package = Package( // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( name: "XMLCoder", - targets: ["XMLCoder"] - ), + targets: ["XMLCoder"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. @@ -21,11 +20,9 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "XMLCoder", - dependencies: [] - ), + dependencies: []), .testTarget( name: "XMLCoderTests", - dependencies: ["XMLCoder"] - ), + dependencies: ["XMLCoder"]), ] ) diff --git a/Sample XML/RJI/RJI.swift b/Sample XML/RJI/RJI.swift index 7ac9c1cd..f303e378 100644 --- a/Sample XML/RJI/RJI.swift +++ b/Sample XML/RJI/RJI.swift @@ -17,7 +17,7 @@ struct RSS: Decodable { var channel: Channel enum CodingKeys: String, CodingKey { - case channel + case channel = "channel" case dc = "xmlns:dc" case sy = "xmlns:sy" diff --git a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift index 810654bb..d60a2c31 100644 --- a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift +++ b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift @@ -23,7 +23,7 @@ internal extension DecodingError { let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead." return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description)) } - + /// Returns a description of the type of `value` appropriate for an error message. /// /// - parameter value: The value whose type to describe. @@ -38,10 +38,12 @@ internal extension DecodingError { return "a string/data" } else if value is [Any] { return "an array" - } else if value is [String: Any] { + } else if value is [String : Any] { return "a dictionary" } else { return "\(type(of: value))" } } } + + diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 62f7e092..c146542a 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -15,7 +15,6 @@ import Foundation /// `XMLDecoder` facilitates the decoding of XML into semantic `Decodable` types. open class XMLDecoder { // MARK: Options - /// The strategy to use for decoding `Date` values. public enum DateDecodingStrategy { /// Defer to `Date` for decoding. This is the default strategy. @@ -46,7 +45,7 @@ open class XMLDecoder { guard let container = try? decoder.singleValueContainer(), let text = try? container.decode(String.self) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) } guard let dateFormatter = try formatterForKey(codingKey) else { @@ -82,7 +81,7 @@ open class XMLDecoder { guard let container = try? decoder.singleValueContainer(), let text = try? container.decode(String.self) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) } guard let data = try formatterForKey(codingKey) else { @@ -120,15 +119,15 @@ open class XMLDecoder { /// /// - Note: Using a key decoding strategy has a nominal performance cost, as each string key has to be inspected for the `_` character. case convertFromSnakeCase - + /// Convert from "CodingKey" to "codingKey" case convertFromCapitalized - + /// Provide a custom conversion from the key in the encoded XML to the keys specified by the decoded types. /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. case custom((_ codingPath: [CodingKey]) -> CodingKey) - + static func _convertFromCapitalized(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } var result = stringKey @@ -157,7 +156,7 @@ open class XMLDecoder { let trailingUnderscoreRange = stringKey.index(after: lastNonUnderscore)..(_ type: T.Type, from data: Data) throws -> T { + open func decode(_ type: T.Type, from data: Data) throws -> T { let topLevel: [String: Any] do { topLevel = try _XMLStackParser.parse(with: data) @@ -250,7 +247,7 @@ open class XMLDecoder { // MARK: - _XMLDecoder -internal class _XMLDecoder: Decoder { +internal class _XMLDecoder : Decoder { // MARK: Properties /// The decoder's storage. @@ -260,10 +257,10 @@ internal class _XMLDecoder: Decoder { internal let options: XMLDecoder._Options /// The path to the current point in encoding. - public internal(set) var codingPath: [CodingKey] + internal(set) public var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey: Any] { + public var userInfo: [CodingUserInfoKey : Any] { return self.options.userInfo } @@ -286,8 +283,8 @@ internal class _XMLDecoder: Decoder { debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } - guard let topContainer = self.storage.topContainer as? [String: Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String: Any].self, reality: self.storage.topContainer) + guard let topContainer = self.storage.topContainer as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: self.storage.topContainer) } let container = _XMLKeyedDecodingContainer(referencing: self, wrapping: topContainer) @@ -305,7 +302,7 @@ internal class _XMLDecoder: Decoder { if let container = self.storage.topContainer as? [Any] { topContainer = container - } else if let container = self.storage.topContainer as? [AnyHashable: Any] { + } else if let container = self.storage.topContainer as? [AnyHashable: Any] { topContainer = [container] } else { throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: self.storage.topContainer) @@ -319,7 +316,8 @@ internal class _XMLDecoder: Decoder { } } -extension _XMLDecoder: SingleValueDecodingContainer { + +extension _XMLDecoder : SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods private func expectNonNull(_ type: T.Type) throws { @@ -333,77 +331,77 @@ extension _XMLDecoder: SingleValueDecodingContainer { } public func decode(_ type: Bool.Type) throws -> Bool { - try self.expectNonNull(Bool.self) + try expectNonNull(Bool.self) return try self.unbox(self.storage.topContainer, as: Bool.self)! } public func decode(_ type: Int.Type) throws -> Int { - try self.expectNonNull(Int.self) + try expectNonNull(Int.self) return try self.unbox(self.storage.topContainer, as: Int.self)! } public func decode(_ type: Int8.Type) throws -> Int8 { - try self.expectNonNull(Int8.self) + try expectNonNull(Int8.self) return try self.unbox(self.storage.topContainer, as: Int8.self)! } public func decode(_ type: Int16.Type) throws -> Int16 { - try self.expectNonNull(Int16.self) + try expectNonNull(Int16.self) return try self.unbox(self.storage.topContainer, as: Int16.self)! } public func decode(_ type: Int32.Type) throws -> Int32 { - try self.expectNonNull(Int32.self) + try expectNonNull(Int32.self) return try self.unbox(self.storage.topContainer, as: Int32.self)! } public func decode(_ type: Int64.Type) throws -> Int64 { - try self.expectNonNull(Int64.self) + try expectNonNull(Int64.self) return try self.unbox(self.storage.topContainer, as: Int64.self)! } public func decode(_ type: UInt.Type) throws -> UInt { - try self.expectNonNull(UInt.self) + try expectNonNull(UInt.self) return try self.unbox(self.storage.topContainer, as: UInt.self)! } public func decode(_ type: UInt8.Type) throws -> UInt8 { - try self.expectNonNull(UInt8.self) + try expectNonNull(UInt8.self) return try self.unbox(self.storage.topContainer, as: UInt8.self)! } public func decode(_ type: UInt16.Type) throws -> UInt16 { - try self.expectNonNull(UInt16.self) + try expectNonNull(UInt16.self) return try self.unbox(self.storage.topContainer, as: UInt16.self)! } public func decode(_ type: UInt32.Type) throws -> UInt32 { - try self.expectNonNull(UInt32.self) + try expectNonNull(UInt32.self) return try self.unbox(self.storage.topContainer, as: UInt32.self)! } public func decode(_ type: UInt64.Type) throws -> UInt64 { - try self.expectNonNull(UInt64.self) + try expectNonNull(UInt64.self) return try self.unbox(self.storage.topContainer, as: UInt64.self)! } public func decode(_ type: Float.Type) throws -> Float { - try self.expectNonNull(Float.self) + try expectNonNull(Float.self) return try self.unbox(self.storage.topContainer, as: Float.self)! } public func decode(_ type: Double.Type) throws -> Double { - try self.expectNonNull(Double.self) + try expectNonNull(Double.self) return try self.unbox(self.storage.topContainer, as: Double.self)! } public func decode(_ type: String.Type) throws -> String { - try self.expectNonNull(String.self) + try expectNonNull(String.self) return try self.unbox(self.storage.topContainer, as: String.self)! } - public func decode(_ type: T.Type) throws -> T { - try self.expectNonNull(type) + public func decode(_ type: T.Type) throws -> T { + try expectNonNull(type) return try self.unbox(self.storage.topContainer, as: type)! } } @@ -674,7 +672,7 @@ extension _XMLDecoder { } return Float(double) - } else if case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if case let .convertFromString(posInfString, negInfString, nanString) = self.options.nonConformingFloatDecodingStrategy { if string == posInfString { return Float.infinity } else if string == negInfString { @@ -693,12 +691,13 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } if let number = Decimal(string: string) as NSDecimalNumber? { + guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) } return number.doubleValue - } else if case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if case let .convertFromString(posInfString, negInfString, nanString) = self.options.nonConformingFloatDecodingStrategy { if string == posInfString { return Double.infinity } else if string == negInfString { @@ -800,7 +799,7 @@ extension _XMLDecoder { return Decimal(doubleValue) } - internal func unbox(_ value: Any, as type: T.Type) throws -> T? { + internal func unbox(_ value: Any, as type: T.Type) throws -> T? { let decoded: T if type == Date.self || type == NSDate.self { guard let date = try self.unbox(value, as: Date.self) else { return nil } @@ -831,3 +830,4 @@ extension _XMLDecoder { return decoded } } + diff --git a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift index cf27e453..41d19b50 100644 --- a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift +++ b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift @@ -12,33 +12,34 @@ import Foundation internal struct _XMLDecodingStorage { // MARK: Properties - + /// The container stack. /// Elements may be any one of the XML types (String, [String : Any]). - internal private(set) var containers: [Any] = [] - + private(set) internal var containers: [Any] = [] + // MARK: - Initialization - + /// Initializes `self` with no containers. internal init() {} - + // MARK: - Modifying the Stack - + internal var count: Int { return self.containers.count } - + internal var topContainer: Any { precondition(!self.containers.isEmpty, "Empty container stack.") return self.containers.last! } - + internal mutating func push(container: Any) { self.containers.append(container) } - + internal mutating func popContainer() { precondition(!self.containers.isEmpty, "Empty container stack.") self.containers.removeLast() } } + diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index dbe0d6eb..d2fa3e44 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -10,7 +10,7 @@ import Foundation // MARK: Decoding Containers -internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainerProtocol { +internal struct _XMLKeyedDecodingContainer : KeyedDecodingContainerProtocol { typealias Key = K // MARK: Properties @@ -19,15 +19,15 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer private let decoder: _XMLDecoder /// A reference to the container we're reading from. - private let container: [String: Any] + private let container: [String : Any] /// The path of coding keys taken to get to this point in decoding. - public private(set) var codingPath: [CodingKey] + private(set) public var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - internal init(referencing decoder: _XMLDecoder, wrapping container: [String: Any]) { + internal init(referencing decoder: _XMLDecoder, wrapping container: [String : Any]) { self.decoder = decoder switch decoder.options.keyDecodingStrategy { case .useDefaultKeys: @@ -37,15 +37,15 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with dictionaries. self.container = Dictionary(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) - }, uniquingKeysWith: { first, _ in first }) + }, uniquingKeysWith: { (first, _) in first }) case .convertFromCapitalized: self.container = Dictionary(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromCapitalized(key), value) - }, uniquingKeysWith: { first, _ in first }) + }, uniquingKeysWith: { (first, _) in first }) case .custom(let converter): self.container = Dictionary(container.map { key, value in (converter(decoder.codingPath + [_XMLKey(stringValue: key, intValue: nil)]).stringValue, value) - }, uniquingKeysWith: { first, _ in first }) + }, uniquingKeysWith: { (first, _) in first }) } self.codingPath = decoder.codingPath } @@ -61,7 +61,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer } private func _errorDescription(of key: CodingKey) -> String { - switch self.decoder.options.keyDecodingStrategy { + switch decoder.options.keyDecodingStrategy { case .convertFromSnakeCase: // In this case we can attempt to recover the original value by reversing the transform let original = key.stringValue @@ -87,7 +87,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -102,7 +102,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -117,7 +117,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -132,7 +132,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -147,7 +147,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -162,7 +162,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -177,7 +177,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -192,7 +192,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -207,7 +207,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -222,7 +222,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -237,7 +237,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -252,7 +252,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -267,7 +267,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -282,7 +282,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: String.Type, forKey key: Key) throws -> String { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -295,9 +295,9 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer return value } - public func decode(_ type: T.Type, forKey key: Key) throws -> T { + public func decode(_ type: T.Type, forKey key: Key) throws -> T { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(self._errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } self.decoder.codingPath.append(key) @@ -320,8 +320,8 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"")) } - guard let dictionary = value as? [String: Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String: Any].self, reality: value) + guard let dictionary = value as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) } let container = _XMLKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) @@ -354,10 +354,10 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer } public func superDecoder() throws -> Decoder { - return try self._superDecoder(forKey: _XMLKey.super) + return try _superDecoder(forKey: _XMLKey.super) } public func superDecoder(forKey key: Key) throws -> Decoder { - return try self._superDecoder(forKey: key) + return try _superDecoder(forKey: key) } } diff --git a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift index cc669251..87e3f417 100644 --- a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift @@ -8,7 +8,7 @@ import Foundation -internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { +internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { // MARK: Properties /// A reference to the decoder we're reading from. @@ -18,10 +18,10 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { private let container: [Any] /// The path of coding keys taken to get to this point in decoding. - public private(set) var codingPath: [CodingKey] + private(set) public var codingPath: [CodingKey] /// The index of the element we're about to decode. - public private(set) var currentIndex: Int + private(set) public var currentIndex: Int // MARK: - Initialization @@ -280,7 +280,7 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { return decoded } - public mutating func decode(_ type: T.Type) throws -> T { + public mutating func decode(_ type: T.Type) throws -> T { guard !self.isAtEnd else { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } @@ -313,8 +313,8 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } - guard let dictionary = value as? [String: Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String: Any].self, reality: value) + guard let dictionary = value as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) } self.currentIndex += 1 diff --git a/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift b/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift index f2e83865..acc4f405 100644 --- a/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift +++ b/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift @@ -18,7 +18,7 @@ internal extension EncodingError { /// - parameter value: The value that was invalid to encode. /// - parameter path: The path of `CodingKey`s taken to encode this value. /// - returns: An `EncodingError` with the appropriate path and debug description. - internal static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + internal static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { let valueDescription: String if value == T.infinity { valueDescription = "\(T.self).infinity" diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index 911cd613..a6d5b883 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -15,9 +15,8 @@ import Foundation /// `XMLEncoder` facilitates the encoding of `Encodable` values into XML. open class XMLEncoder { // MARK: Options - /// The formatting of the output XML data. - public struct OutputFormatting: OptionSet { + public struct OutputFormatting : OptionSet { /// The format's default value. public let rawValue: UInt @@ -31,14 +30,14 @@ open class XMLEncoder { /// Produce XML with dictionary keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) + public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) } - + /// A node's encoding tyoe public enum NodeEncoding { case attribute case element - + public static let `default`: NodeEncoding = .element } @@ -127,7 +126,7 @@ open class XMLEncoder { internal static func _convertToSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - var words: [Range] = [] + var words : [Range] = [] // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase // // myProperty -> my_property @@ -167,24 +166,24 @@ open class XMLEncoder { searchRange = lowerCaseRange.upperBound.. ((CodingKey) -> XMLEncoder.NodeEncoding)) - + internal func nodeEncodings( forType codableType: Encodable.Type, with encoder: Encoder @@ -220,7 +219,7 @@ open class XMLEncoder { open var stringEncodingStrategy: StringEncodingStrategy = .deferredToString /// Contextual user-provided information for use during encoding. - open var userInfo: [CodingUserInfoKey: Any] = [:] + open var userInfo: [CodingUserInfoKey : Any] = [:] /// Options set on the top-level encoder to pass down the encoding hierarchy. internal struct _Options { @@ -230,27 +229,25 @@ open class XMLEncoder { let keyEncodingStrategy: KeyEncodingStrategy let nodeEncodingStrategy: NodeEncodingStrategy let stringEncodingStrategy: StringEncodingStrategy - let userInfo: [CodingUserInfoKey: Any] + let userInfo: [CodingUserInfoKey : Any] } /// The options set on the top-level encoder. internal var options: _Options { - return _Options(dateEncodingStrategy: self.dateEncodingStrategy, - dataEncodingStrategy: self.dataEncodingStrategy, - nonConformingFloatEncodingStrategy: self.nonConformingFloatEncodingStrategy, - keyEncodingStrategy: self.keyEncodingStrategy, - nodeEncodingStrategy: self.nodeEncodingStrategy, - stringEncodingStrategy: self.stringEncodingStrategy, - userInfo: self.userInfo) + return _Options(dateEncodingStrategy: dateEncodingStrategy, + dataEncodingStrategy: dataEncodingStrategy, + nonConformingFloatEncodingStrategy: nonConformingFloatEncodingStrategy, + keyEncodingStrategy: keyEncodingStrategy, + nodeEncodingStrategy: nodeEncodingStrategy, + stringEncodingStrategy: stringEncodingStrategy, + userInfo: userInfo) } // MARK: - Constructing a XML Encoder - /// Initializes `self` with default strategies. public init() {} // MARK: - Encoding Values - /// Encodes the given top-level value and returns its XML representation. /// /// - parameter value: The value to encode. @@ -258,7 +255,7 @@ open class XMLEncoder { /// - returns: A new `Data` value containing the encoded XML data. /// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. /// - throws: An error if any value throws an error during encoding. - open func encode(_ value: T, withRootKey rootKey: String, header: XMLHeader? = nil) throws -> Data { + open func encode(_ value: T, withRootKey rootKey: String, header: XMLHeader? = nil) throws -> Data { let encoder = _XMLEncoder( options: self.options, nodeEncodings: [] @@ -280,7 +277,7 @@ open class XMLEncoder { guard let element = _XMLElement.createRootElement(rootKey: rootKey, object: topLevel) else { throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Unable to encode the given top-level value to XML.")) } - + let withCDATA = stringEncodingStrategy != .deferredToString return element.toXMLString(with: header, withCDATA: withCDATA, formatting: self.outputFormatting).data(using: .utf8, allowLossyConversion: true)! } @@ -297,11 +294,11 @@ internal class _XMLEncoder: Encoder { /// The path to the current point in encoding. public var codingPath: [CodingKey] - + public var nodeEncodings: [(CodingKey) -> XMLEncoder.NodeEncoding] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey: Any] { + public var userInfo: [CodingUserInfoKey : Any] { return self.options.userInfo } @@ -333,7 +330,6 @@ internal class _XMLEncoder: Encoder { } // MARK: - Encoder Methods - public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. let topContainer: NSMutableDictionary @@ -347,7 +343,8 @@ internal class _XMLEncoder: Encoder { topContainer = container } - + + let container = _XMLKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) return KeyedEncodingContainer(container) } @@ -376,7 +373,7 @@ internal class _XMLEncoder: Encoder { // MARK: - Encoding Containers -fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContainerProtocol { +fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingContainerProtocol { typealias Key = K // MARK: Properties @@ -385,10 +382,10 @@ fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContai private let encoder: _XMLEncoder /// A reference to the container we're writing to. - private let container: NSMutableDictionary + private let container: NSMutableDictionary /// The path of coding keys taken to get to this point in encoding. - public private(set) var codingPath: [CodingKey] + private(set) public var codingPath: [CodingKey] // MARK: - Initialization @@ -402,14 +399,14 @@ fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContai // MARK: - Coding Path Operations private func _converted(_ key: CodingKey) -> CodingKey { - switch self.encoder.options.keyEncodingStrategy { + switch encoder.options.keyEncodingStrategy { case .useDefaultKeys: return key case .convertToSnakeCase: let newKeyString = XMLEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _XMLKey(stringValue: newKeyString, intValue: key.intValue) case .custom(let converter): - return converter(self.codingPath + [key]) + return converter(codingPath + [key]) } } @@ -687,7 +684,7 @@ fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContai } } - public mutating func encode(_ value: T, forKey key: Key) throws { + public mutating func encode(_ value: T, forKey key: Key) throws { guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") } @@ -698,7 +695,7 @@ fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContai ) self.encoder.nodeEncodings.append(nodeEncodings) defer { - _ = self.encoder.nodeEncodings.removeLast() + let _ = self.encoder.nodeEncodings.removeLast() self.encoder.codingPath.removeLast() } switch strategy(key) { @@ -736,15 +733,15 @@ fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContai } public mutating func superEncoder() -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, key: _XMLKey.super, convertedKey: self._converted(_XMLKey.super), wrapping: self.container) + return _XMLReferencingEncoder(referencing: self.encoder, key: _XMLKey.super, convertedKey: _converted(_XMLKey.super), wrapping: self.container) } public mutating func superEncoder(forKey key: Key) -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, key: key, convertedKey: self._converted(key), wrapping: self.container) + return _XMLReferencingEncoder(referencing: self.encoder, key: key, convertedKey: _converted(key), wrapping: self.container) } } -fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { +fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: Properties /// A reference to the encoder we're writing to. @@ -754,7 +751,7 @@ fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { private let container: NSMutableArray /// The path of coding keys taken to get to this point in encoding. - public private(set) var codingPath: [CodingKey] + private(set) public var codingPath: [CodingKey] /// The number of elements encoded into the container. public var count: Int { @@ -772,21 +769,21 @@ fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - public mutating func encodeNil() throws { self.container.add(NSNull()) } - public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } + public mutating func encodeNil() throws { self.container.add(NSNull()) } + public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Float) throws { + public mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. self.encoder.codingPath.append(_XMLKey(index: self.count)) defer { self.encoder.codingPath.removeLast() } @@ -800,7 +797,7 @@ fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { self.container.add(try self.encoder.box(value)) } - public mutating func encode(_ value: T) throws { + public mutating func encode(_ value: T) throws { self.encoder.codingPath.append(_XMLKey(index: self.count)) let nodeEncodings = self.encoder.options.nodeEncodingStrategy.nodeEncodings( forType: T.self, @@ -808,7 +805,7 @@ fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { ) self.encoder.nodeEncodings.append(nodeEncodings) defer { - _ = self.encoder.nodeEncodings.removeLast() + let _ = self.encoder.nodeEncodings.removeLast() self.encoder.codingPath.removeLast() } self.container.add(try self.encoder.box(value)) @@ -847,96 +844,96 @@ extension _XMLEncoder: SingleValueEncodingContainer { } public func encodeNil() throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: NSNull()) } public func encode(_ value: Bool) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int8) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int16) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int32) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Int64) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt8) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt16) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt32) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: UInt64) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: String) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() self.storage.push(container: self.box(value)) } public func encode(_ value: Float) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() try self.storage.push(container: self.box(value)) } public func encode(_ value: Double) throws { - self.assertCanEncodeNewValue() + assertCanEncodeNewValue() try self.storage.push(container: self.box(value)) } - public func encode(_ value: T) throws { - self.assertCanEncodeNewValue() + public func encode(_ value: T) throws { + assertCanEncodeNewValue() try self.storage.push(container: self.box(value)) } } extension _XMLEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } @@ -944,8 +941,8 @@ extension _XMLEncoder { internal func box(_ value: Float) throws -> NSObject { if value.isInfinite || value.isNaN { - guard case .convertToString(let positiveInfinity: posInfString, let negativeInfinity: negInfString, let nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(value, at: self.codingPath) + guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + throw EncodingError._invalidFloatingPointValue(value, at: codingPath) } if value == Float.infinity { @@ -962,8 +959,8 @@ extension _XMLEncoder { internal func box(_ value: Double) throws -> NSObject { if value.isInfinite || value.isNaN { - guard case .convertToString(let positiveInfinity: posInfString, let negativeInfinity: negInfString, let nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(value, at: self.codingPath) + guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + throw EncodingError._invalidFloatingPointValue(value, at: codingPath) } if value == Double.infinity { @@ -998,9 +995,9 @@ extension _XMLEncoder { case .custom(let closure): let depth = self.storage.count try closure(value, self) - + guard self.storage.count > depth else { return NSDictionary() } - + return self.storage.popContainer() } } @@ -1015,19 +1012,19 @@ extension _XMLEncoder { case .custom(let closure): let depth = self.storage.count try closure(value, self) - + guard self.storage.count > depth else { return NSDictionary() } - + return self.storage.popContainer() as NSObject } } - fileprivate func box(_ value: T) throws -> NSObject { + fileprivate func box(_ value: T) throws -> NSObject { return try self.box_(value) ?? NSDictionary() } // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. - fileprivate func box_(_ value: T) throws -> NSObject? { + fileprivate func box_(_ value: T) throws -> NSObject? { if T.self == Date.self || T.self == NSDate.self { return try self.box((value as! Date)) } else if T.self == Data.self || T.self == NSData.self { @@ -1049,3 +1046,4 @@ extension _XMLEncoder { return self.storage.popContainer() } } + diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index ac7b9d75..ded3b4eb 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -16,7 +16,7 @@ internal struct _XMLEncodingStorage { /// The container stack. /// Elements may be any one of the XML types (NSNull, NSNumber, NSString, NSArray, NSDictionary). - internal private(set) var containers: [NSObject] = [] + private(set) internal var containers: [NSObject] = [] // MARK: - Initialization diff --git a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift index 2c36b9c0..9da655ca 100644 --- a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift @@ -12,7 +12,7 @@ import Foundation /// _XMLReferencingEncoder is a special subclass of _XMLEncoder which has its own storage, but references the contents of a different encoder. /// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). -internal class _XMLReferencingEncoder: _XMLEncoder { +internal class _XMLReferencingEncoder : _XMLEncoder { // MARK: Reference types. /// The type of container we're referencing. diff --git a/Sources/XMLCoder/ISO8601DateFormatter.swift b/Sources/XMLCoder/ISO8601DateFormatter.swift index f8e05ae5..85fb6889 100644 --- a/Sources/XMLCoder/ISO8601DateFormatter.swift +++ b/Sources/XMLCoder/ISO8601DateFormatter.swift @@ -19,3 +19,5 @@ internal var _iso8601Formatter: ISO8601DateFormatter = { formatter.formatOptions = .withInternetDateTime return formatter }() + + diff --git a/Sources/XMLCoder/XMLKey.swift b/Sources/XMLCoder/XMLKey.swift index 27a9f882..ffc8f293 100644 --- a/Sources/XMLCoder/XMLKey.swift +++ b/Sources/XMLCoder/XMLKey.swift @@ -12,15 +12,15 @@ import Foundation // Shared Key Types //===----------------------------------------------------------------------===// -internal struct _XMLKey: CodingKey { +internal struct _XMLKey : CodingKey { public var stringValue: String public var intValue: Int? - + public init?(stringValue: String) { self.stringValue = stringValue self.intValue = nil } - + public init?(intValue: Int) { self.stringValue = "\(intValue)" self.intValue = intValue @@ -30,11 +30,13 @@ internal struct _XMLKey: CodingKey { self.stringValue = stringValue self.intValue = intValue } - + internal init(index: Int) { self.stringValue = "Index \(index)" self.intValue = index } - + internal static let `super` = _XMLKey(stringValue: "super")! } + + diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index ba8a235c..9bbf7b61 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -19,7 +19,7 @@ public struct XMLHeader { public let encoding: String? /// indicates whether a document relies on information from an external source. public let standalone: String? - + public init(version: Double? = nil, encoding: String? = nil, standalone: String? = nil) { self.version = version self.encoding = encoding @@ -27,7 +27,7 @@ public struct XMLHeader { } internal func isEmpty() -> Bool { - return self.version == nil && self.encoding == nil && self.standalone == nil + return version == nil && encoding == nil && standalone == nil } internal func toXML() -> String? { @@ -53,10 +53,10 @@ public struct XMLHeader { internal class _XMLElement { static let attributesKey = "___ATTRIBUTES" - static let escapedCharacterSet = [("&", "&"), ("<", "<"), (">", ">"), ("'", "'"), ("\"", """)] + static let escapedCharacterSet = [("&", "&"), ("<", "<"), (">", ">"), ( "'", "'"), ("\"", """)] var key: String - var value: String? + var value: String? = nil var attributes: [String: String] = [:] var children: [String: [_XMLElement]] = [:] @@ -156,7 +156,7 @@ internal class _XMLElement { fileprivate func flatten() -> [String: Any] { var node: [String: Any] = attributes - for childElement in self.children { + for childElement in children { for child in childElement.value { if let content = child.value { if let oldContent = node[childElement.key] as? Array { @@ -187,101 +187,101 @@ internal class _XMLElement { return node } - + func toXMLString(with header: XMLHeader? = nil, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { if let header = header, let headerXML = header.toXML() { - return headerXML + self._toXMLString(withCDATA: cdata, formatting: formatting) - } - return self._toXMLString(withCDATA: cdata, formatting: formatting) - } - - fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - self.formatXMLElements(from: self.children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - - fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { - var string = "" - for child in childElement.value { - string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) - string += prettyPrinted ? "\n" : "" - } - return string - } - - fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - self.formatXMLElements(from: self.children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - - fileprivate func attributeString(key: String, value: String) -> String { - return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" - } - - fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { - for (key, value) in keyValuePairs { - string += self.attributeString(key: key, value: value) + return headerXML + _toXMLString(withCDATA: cdata, formatting: formatting) } + return _toXMLString(withCDATA: cdata, formatting: formatting) } - fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { - for childElement in children { - string += self.elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - } - - fileprivate func formatSortedXMLAttributes(_ string: inout String) { - self.formatXMLAttributes(from: self.attributes.sorted(by: { $0.key < $1.key }), into: &string) - } - - fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { - self.formatXMLAttributes(from: self.attributes.map { (key: $0, value: $1) }, into: &string) - } - - fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { - if #available(OSX 10.13, iOS 11.0, *) { - if formatting.contains(.sortedKeys) { - formatSortedXMLAttributes(&string) - return - } - formatUnsortedXMLAttributes(&string) - return - } - self.formatUnsortedXMLAttributes(&string) - } - - fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { - if #available(OSX 10.13, iOS 11.0, *) { - if formatting.contains(.sortedKeys) { - formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - return - } - formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - return - } - self.formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - } - - fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { + fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + formatXMLElements(from: children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { + var string = "" + for child in childElement.value { + string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) + string += prettyPrinted ? "\n" : "" + } + return string + } + + fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + formatXMLElements(from: children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func attributeString(key: String, value: String) -> String { + return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + } + + fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { + for (key, value) in keyValuePairs { + string += attributeString(key: key, value: value) + } + } + + fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { + for childElement in children { + string += elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + } + + fileprivate func formatSortedXMLAttributes(_ string: inout String) { + formatXMLAttributes(from: attributes.sorted(by: { $0.key < $1.key }), into: &string) + } + + fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { + formatXMLAttributes(from: attributes.map { (key: $0, value: $1) }, into: &string) + } + + fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLAttributes(&string) + return + } + formatUnsortedXMLAttributes(&string) + return + } + formatUnsortedXMLAttributes(&string) + } + + fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return + } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return + } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + } + + fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { let prettyPrinted = formatting.contains(.prettyPrinted) let indentation = String(repeating: " ", count: (prettyPrinted ? level : 0) * 4) var string = indentation string += "<\(key)" - - formatXMLAttributes(formatting, &string) - + + formatXMLAttributes(formatting, &string) + if let value = value { string += ">" if !ignoreEscaping { - string += (cdata == true ? "" : "\(value.escape(_XMLElement.escapedCharacterSet))") + string += (cdata == true ? "" : "\(value.escape(_XMLElement.escapedCharacterSet))" ) } else { string += "\(value)" } - string += "" - } else if !self.children.isEmpty { + string += "" + } else if !children.isEmpty { string += prettyPrinted ? ">\n" : ">" - self.formatXMLElements(formatting, &string, level, cdata, prettyPrinted) - + formatXMLElements(formatting, &string, level, cdata, prettyPrinted) + string += indentation - string += "" + string += "" } else { string += " />" } @@ -324,12 +324,12 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } } - func parse(with data: Data) throws -> _XMLElement? { + func parse(with data: Data) throws -> _XMLElement? { let xmlParser = XMLParser(data: data) xmlParser.delegate = self if xmlParser.parse() { - return self.root + return root } else if let error = xmlParser.parserError { throw error } else { @@ -338,11 +338,11 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } func parserDidStartDocument(_ parser: XMLParser) { - self.root = nil - self.stack = [_XMLElement]() + root = nil + stack = [_XMLElement]() } - func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String] = [:]) { + func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { let node = _XMLElement(key: elementName) node.attributes = attributeDict stack.append(node) @@ -354,11 +354,11 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { currentNode.children[elementName] = [node] } } - self.currentNode = node + currentNode = node } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { - if let poppedNode = stack.popLast() { + if let poppedNode = stack.popLast(){ if let content = poppedNode.value?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) { if content.isEmpty { poppedNode.value = nil @@ -367,22 +367,22 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } } - if self.stack.isEmpty { - self.root = poppedNode - self.currentNode = nil + if (stack.isEmpty) { + root = poppedNode + currentNode = nil } else { - self.currentNode = self.stack.last + currentNode = stack.last } } } func parser(_ parser: XMLParser, foundCharacters string: String) { - self.currentNode?.value = (self.currentNode?.value ?? "") + string + currentNode?.value = (currentNode?.value ?? "") + string } func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) { if let string = String(data: CDATABlock, encoding: .utf8) { - self.currentNode?.value = (self.currentNode?.value ?? "") + string + currentNode?.value = (currentNode?.value ?? "") + string } } @@ -390,3 +390,4 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { print(parseError) } } + diff --git a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift index 0a320e21..d8f6f7e1 100644 --- a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift +++ b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift @@ -6,7 +6,7 @@ class NodeEncodingStrategyTests: XCTestCase { let element: Element enum CodingKeys: String, CodingKey { - case element + case element = "element" } } @@ -37,32 +37,32 @@ class NodeEncodingStrategyTests: XCTestCase { return .attribute } } - - fileprivate struct ComplexUnkeyedContainer: Encodable { - let elements: [ComplexElement] - - enum CodingKeys: String, CodingKey { - case elements = "element" - } - } - - fileprivate struct ComplexElement: Encodable { - struct Key: Encodable { - let a: String - let b: String - let c: String - } - - var key: Key = Key(a: "C", b: "B", c: "A") - - enum CodingKeys: CodingKey { - case key - } - - static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { - return .attribute - } - } + + fileprivate struct ComplexUnkeyedContainer: Encodable { + let elements: [ComplexElement] + + enum CodingKeys: String, CodingKey { + case elements = "element" + } + } + + fileprivate struct ComplexElement: Encodable { + struct Key: Encodable { + let a: String + let b: String + let c: String + } + + var key: Key = Key(a: "C", b: "B", c: "A") + + enum CodingKeys: CodingKey { + case key + } + + static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { + return .attribute + } + } func testSingleContainer() { let encoder = XMLEncoder() @@ -74,21 +74,21 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - value - - - """ +""" + + + value + + +""" XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, _ in + encoder.nodeEncodingStrategy = .custom { codableType, encoder in guard let barType = codableType as? Element.Type else { - return { _ in .default } + return { _ in return .default } } return barType.nodeEncoding(forKey:) } @@ -99,11 +99,11 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - """ +""" + + + +""" XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -120,23 +120,23 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - value - - - - """ + """ + + + + value + + + +""" XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, _ in + encoder.nodeEncodingStrategy = .custom { codableType, encoder in guard let barType = codableType as? Element.Type else { - return { _ in .default } + return { _ in return .default } } return barType.nodeEncoding(forKey:) } @@ -147,13 +147,13 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - - - """ + """ + + + + + +""" XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -170,24 +170,24 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - value - - - value - - - """ +""" + + + value + + + value + + +""" XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, _ in + encoder.nodeEncodingStrategy = .custom { codableType, encoder in guard let barType = codableType as? Element.Type else { - return { _ in .default } + return { _ in return .default } } return barType.nodeEncoding(forKey:) } @@ -198,12 +198,12 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - - """ +""" + + + + +""" XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -215,68 +215,68 @@ class NodeEncodingStrategyTests: XCTestCase { ("testKeyedContainer", testKeyedContainer), ("testUnkeyedContainer", testUnkeyedContainer), ] - - func testItSortsKeysWhenEncodingAsElements() { - let encoder = XMLEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = [.sortedKeys, .prettyPrinted] - } else { - return - } - - do { - let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) - let data = try encoder.encode(container, withRootKey: "container") - let xml = String(data: data, encoding: .utf8)! - - let expected = - """ - - - - C - B - A - - - - """ - XCTAssertEqual(xml, expected) - } catch { - XCTAssert(false, "failed to decode the example: \(error)") - } - } - - func testItSortsKeysWhenEncodingAsAttributes() { - let encoder = XMLEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = [.sortedKeys, .prettyPrinted] - encoder.nodeEncodingStrategy = .custom { key, _ in - if key == ComplexElement.Key.self { - return { _ in .attribute } - } - return { _ in .element } - } - } else { - return - } - - do { - let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) - let data = try encoder.encode(container, withRootKey: "container") - let xml = String(data: data, encoding: .utf8)! - - let expected = - """ - - - - - - """ - XCTAssertEqual(xml, expected) - } catch { - XCTAssert(false, "failed to decode the example: \(error)") - } - } + + func testItSortsKeysWhenEncodingAsElements() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + C + B + A + + + +""" + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } + + func testItSortsKeysWhenEncodingAsAttributes() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + encoder.nodeEncodingStrategy = .custom { key, encoder in + if key == ComplexElement.Key.self { + return { _ in .attribute } + } + return { _ in .element } + } + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + + +""" + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } } diff --git a/Tests/XMLCoderTests/XMLCoderTests.swift b/Tests/XMLCoderTests/XMLCoderTests.swift index 7945a8ff..5234dc3f 100644 --- a/Tests/XMLCoderTests/XMLCoderTests.swift +++ b/Tests/XMLCoderTests/XMLCoderTests.swift @@ -20,7 +20,7 @@ let example = """ struct Relationships: Codable { let items: [Relationship] - + enum CodingKeys: String, CodingKey { case items = "relationship" } @@ -32,11 +32,11 @@ struct Relationship: Codable { case extendedProperties = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" case coreProperties = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" } - + let id: String let type: SchemaType let target: String - + enum CodingKeys: CodingKey { case type case id @@ -48,18 +48,19 @@ class XMLCoderTests: XCTestCase { func testExample() { do { guard let data = example.data(using: .utf8) else { return } - + let decoder = XMLDecoder() decoder.keyDecodingStrategy = .convertFromCapitalized - + let rels = try decoder.decode(Relationships.self, from: data) - + XCTAssertEqual(rels.items[0].id, "rId1") } catch { XCTAssert(false, "failed to decode the example: \(error)") } } - + + static var allTests = [ ("testExample", testExample), ] From 26a68a2ee292e215c251941a0ce391707d39f33c Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 17:32:36 +0100 Subject: [PATCH 06/10] Use less explicit .swiftformat --- Package.swift | 9 +- Sample XML/RJI/RJI.swift | 2 +- .../Decoder/DecodingErrorExtension.swift | 6 +- Sources/XMLCoder/Decoder/XMLDecoder.swift | 226 ++++----- .../XMLCoder/Decoder/XMLDecodingStorage.swift | 31 +- .../Decoder/XMLKeyedDecodingContainer.swift | 138 +++--- .../Decoder/XMLUnkeyedDecodingContainer.swift | 218 ++++----- .../Encoder/EncodingErrorExtension.swift | 2 +- Sources/XMLCoder/Encoder/XMLEncoder.swift | 436 +++++++++--------- .../XMLCoder/Encoder/XMLEncodingStorage.swift | 14 +- .../Encoder/XMLReferencingEncoder.swift | 16 +- Sources/XMLCoder/ISO8601DateFormatter.swift | 2 - Sources/XMLCoder/XMLKey.swift | 20 +- Sources/XMLCoder/XMLStackParser.swift | 165 ++++--- .../NodeEncodingStrategyTests.swift | 282 +++++------ Tests/XMLCoderTests/XMLCoderTests.swift | 15 +- 16 files changed, 789 insertions(+), 793 deletions(-) diff --git a/Package.swift b/Package.swift index cb6843e7..103b8c53 100644 --- a/Package.swift +++ b/Package.swift @@ -9,7 +9,8 @@ let package = Package( // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( name: "XMLCoder", - targets: ["XMLCoder"]), + targets: ["XMLCoder"] + ), ], dependencies: [ // Dependencies declare other packages that this package depends on. @@ -20,9 +21,11 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "XMLCoder", - dependencies: []), + dependencies: [] + ), .testTarget( name: "XMLCoderTests", - dependencies: ["XMLCoder"]), + dependencies: ["XMLCoder"] + ), ] ) diff --git a/Sample XML/RJI/RJI.swift b/Sample XML/RJI/RJI.swift index f303e378..7ac9c1cd 100644 --- a/Sample XML/RJI/RJI.swift +++ b/Sample XML/RJI/RJI.swift @@ -17,7 +17,7 @@ struct RSS: Decodable { var channel: Channel enum CodingKeys: String, CodingKey { - case channel = "channel" + case channel case dc = "xmlns:dc" case sy = "xmlns:sy" diff --git a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift index d60a2c31..810654bb 100644 --- a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift +++ b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift @@ -23,7 +23,7 @@ internal extension DecodingError { let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead." return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description)) } - + /// Returns a description of the type of `value` appropriate for an error message. /// /// - parameter value: The value whose type to describe. @@ -38,12 +38,10 @@ internal extension DecodingError { return "a string/data" } else if value is [Any] { return "an array" - } else if value is [String : Any] { + } else if value is [String: Any] { return "a dictionary" } else { return "\(type(of: value))" } } } - - diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index c146542a..0f58a7fa 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -15,6 +15,7 @@ import Foundation /// `XMLDecoder` facilitates the decoding of XML into semantic `Decodable` types. open class XMLDecoder { // MARK: Options + /// The strategy to use for decoding `Date` values. public enum DateDecodingStrategy { /// Defer to `Date` for decoding. This is the default strategy. @@ -45,7 +46,7 @@ open class XMLDecoder { guard let container = try? decoder.singleValueContainer(), let text = try? container.decode(String.self) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) } guard let dateFormatter = try formatterForKey(codingKey) else { @@ -81,7 +82,7 @@ open class XMLDecoder { guard let container = try? decoder.singleValueContainer(), let text = try? container.decode(String.self) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date text")) } guard let data = try formatterForKey(codingKey) else { @@ -119,19 +120,19 @@ open class XMLDecoder { /// /// - Note: Using a key decoding strategy has a nominal performance cost, as each string key has to be inspected for the `_` character. case convertFromSnakeCase - + /// Convert from "CodingKey" to "codingKey" case convertFromCapitalized - + /// Provide a custom conversion from the key in the encoded XML to the keys specified by the decoded types. /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. case custom((_ codingPath: [CodingKey]) -> CodingKey) - + static func _convertFromCapitalized(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } var result = stringKey - let range = result.startIndex...result.index(after: result.startIndex) + let range = result.startIndex ... result.index(after: result.startIndex) result.replaceSubrange(range, with: result[range].lowercased()) return result } @@ -151,12 +152,12 @@ open class XMLDecoder { stringKey.formIndex(before: &lastNonUnderscore) } - let keyRange = firstNonUnderscore...lastNonUnderscore - let leadingUnderscoreRange = stringKey.startIndex..(_ type: T.Type, from data: Data) throws -> T { + open func decode(_ type: T.Type, from data: Data) throws -> T { let topLevel: [String: Any] do { topLevel = try _XMLStackParser.parse(with: data) @@ -235,7 +238,7 @@ open class XMLDecoder { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid XML.", underlyingError: error)) } - let decoder = _XMLDecoder(referencing: topLevel, options: self.options) + let decoder = _XMLDecoder(referencing: topLevel, options: options) guard let value = try decoder.unbox(topLevel, as: type) else { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: [], debugDescription: "The given data did not contain a top-level value.")) @@ -247,7 +250,7 @@ open class XMLDecoder { // MARK: - _XMLDecoder -internal class _XMLDecoder : Decoder { +internal class _XMLDecoder: Decoder { // MARK: Properties /// The decoder's storage. @@ -257,19 +260,19 @@ internal class _XMLDecoder : Decoder { internal let options: XMLDecoder._Options /// The path to the current point in encoding. - internal(set) public var codingPath: [CodingKey] + public internal(set) var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + public var userInfo: [CodingUserInfoKey: Any] { + return options.userInfo } // MARK: - Initialization /// Initializes `self` with the given top-level container and options. internal init(referencing container: Any, at codingPath: [CodingKey] = [], options: XMLDecoder._Options) { - self.storage = _XMLDecodingStorage() - self.storage.push(container: container) + storage = _XMLDecodingStorage() + storage.push(container: container) self.codingPath = codingPath self.options = options } @@ -277,14 +280,14 @@ internal class _XMLDecoder : Decoder { // MARK: - Decoder Methods public func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { + guard !(storage.topContainer is NSNull) else { throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } - guard let topContainer = self.storage.topContainer as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: self.storage.topContainer) + guard let topContainer = self.storage.topContainer as? [String: Any] else { + throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: storage.topContainer) } let container = _XMLKeyedDecodingContainer(referencing: self, wrapping: topContainer) @@ -292,9 +295,9 @@ internal class _XMLDecoder : Decoder { } public func unkeyedContainer() throws -> UnkeyedDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { + guard !(storage.topContainer is NSNull) else { throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get unkeyed decoding container -- found null value instead.")) } @@ -302,10 +305,10 @@ internal class _XMLDecoder : Decoder { if let container = self.storage.topContainer as? [Any] { topContainer = container - } else if let container = self.storage.topContainer as? [AnyHashable: Any] { + } else if let container = self.storage.topContainer as? [AnyHashable: Any] { topContainer = [container] } else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: self.storage.topContainer) + throw DecodingError._typeMismatch(at: codingPath, expectation: [Any].self, reality: storage.topContainer) } return _XMLUnkeyedDecodingContainer(referencing: self, wrapping: topContainer) @@ -316,93 +319,92 @@ internal class _XMLDecoder : Decoder { } } - -extension _XMLDecoder : SingleValueDecodingContainer { +extension _XMLDecoder: SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods private func expectNonNull(_ type: T.Type) throws { - guard !self.decodeNil() else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected \(type) but found null value instead.")) + guard !decodeNil() else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: codingPath, debugDescription: "Expected \(type) but found null value instead.")) } } public func decodeNil() -> Bool { - return self.storage.topContainer is NSNull + return storage.topContainer is NSNull } public func decode(_ type: Bool.Type) throws -> Bool { try expectNonNull(Bool.self) - return try self.unbox(self.storage.topContainer, as: Bool.self)! + return try unbox(storage.topContainer, as: Bool.self)! } public func decode(_ type: Int.Type) throws -> Int { try expectNonNull(Int.self) - return try self.unbox(self.storage.topContainer, as: Int.self)! + return try unbox(storage.topContainer, as: Int.self)! } public func decode(_ type: Int8.Type) throws -> Int8 { try expectNonNull(Int8.self) - return try self.unbox(self.storage.topContainer, as: Int8.self)! + return try unbox(storage.topContainer, as: Int8.self)! } public func decode(_ type: Int16.Type) throws -> Int16 { try expectNonNull(Int16.self) - return try self.unbox(self.storage.topContainer, as: Int16.self)! + return try unbox(storage.topContainer, as: Int16.self)! } public func decode(_ type: Int32.Type) throws -> Int32 { try expectNonNull(Int32.self) - return try self.unbox(self.storage.topContainer, as: Int32.self)! + return try unbox(storage.topContainer, as: Int32.self)! } public func decode(_ type: Int64.Type) throws -> Int64 { try expectNonNull(Int64.self) - return try self.unbox(self.storage.topContainer, as: Int64.self)! + return try unbox(storage.topContainer, as: Int64.self)! } public func decode(_ type: UInt.Type) throws -> UInt { try expectNonNull(UInt.self) - return try self.unbox(self.storage.topContainer, as: UInt.self)! + return try unbox(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)! + return try unbox(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)! + return try unbox(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)! + return try unbox(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)! + return try unbox(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)! + return try unbox(storage.topContainer, as: Float.self)! } public func decode(_ type: Double.Type) throws -> Double { try expectNonNull(Double.self) - return try self.unbox(self.storage.topContainer, as: Double.self)! + return try unbox(storage.topContainer, as: Double.self)! } public func decode(_ type: String.Type) throws -> String { try expectNonNull(String.self) - return try self.unbox(self.storage.topContainer, as: String.self)! + return try unbox(storage.topContainer, as: String.self)! } - public func decode(_ type: T.Type) throws -> T { + public func decode(_ type: T.Type) throws -> T { try expectNonNull(type) - return try self.unbox(self.storage.topContainer, as: type)! + return try unbox(storage.topContainer, as: type)! } } @@ -421,7 +423,7 @@ extension _XMLDecoder { return false } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } internal func unbox(_ value: Any, as type: Int.Type) throws -> Int? { @@ -430,18 +432,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int = number.intValue guard NSNumber(value: int) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return int @@ -453,18 +455,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int8 = number.int8Value guard NSNumber(value: int8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return int8 @@ -476,18 +478,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int16 = number.int16Value guard NSNumber(value: int16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return int16 @@ -499,18 +501,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int32 = number.int32Value guard NSNumber(value: int32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return int32 @@ -522,18 +524,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int64 = number.int64Value guard NSNumber(value: int64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return int64 @@ -545,18 +547,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint = number.uintValue guard NSNumber(value: uint) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return uint @@ -568,18 +570,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint8 = number.uint8Value guard NSNumber(value: uint8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return uint8 @@ -591,18 +593,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint16 = number.uint16Value guard NSNumber(value: uint16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return uint16 @@ -614,18 +616,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint32 = number.uint32Value guard NSNumber(value: uint32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return uint32 @@ -637,18 +639,18 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } guard let value = Float(string) else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: string) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: string) } let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint64 = number.uint64Value guard NSNumber(value: uint64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number <\(number)> does not fit in \(type).")) } return uint64 @@ -663,16 +665,16 @@ extension _XMLDecoder { let number = NSNumber(value: value) guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let double = number.doubleValue guard abs(double) <= Double(Float.greatestFiniteMagnitude) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed XML number \(number) does not fit in \(type).")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Parsed XML number \(number) does not fit in \(type).")) } return Float(double) - } else if case let .convertFromString(posInfString, negInfString, nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if case let .convertFromString(posInfString, negInfString, nanString) = options.nonConformingFloatDecodingStrategy { if string == posInfString { return Float.infinity } else if string == negInfString { @@ -682,7 +684,7 @@ extension _XMLDecoder { } } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } internal func unbox(_ value: Any, as type: Double.Type) throws -> Double? { @@ -691,13 +693,12 @@ extension _XMLDecoder { guard let string = value as? String else { return nil } if let number = Decimal(string: string) as NSDecimalNumber? { - guard number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } return number.doubleValue - } else if case let .convertFromString(posInfString, negInfString, nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if case let .convertFromString(posInfString, negInfString, nanString) = options.nonConformingFloatDecodingStrategy { if string == posInfString { return Double.infinity } else if string == negInfString { @@ -707,14 +708,14 @@ extension _XMLDecoder { } } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } internal func unbox(_ value: Any, as type: String.Type) throws -> String? { guard !(value is NSNull) else { return nil } guard let string = value as? String else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } return string @@ -723,18 +724,18 @@ extension _XMLDecoder { internal func unbox(_ value: Any, as type: Date.Type) throws -> Date? { guard !(value is NSNull) else { return nil } - switch self.options.dateDecodingStrategy { + switch options.dateDecodingStrategy { case .deferredToDate: - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try Date(from: self) case .secondsSince1970: - let double = try self.unbox(value, as: Double.self)! + let double = try unbox(value, as: Double.self)! return Date(timeIntervalSince1970: double) case .millisecondsSince1970: - let double = try self.unbox(value, as: Double.self)! + let double = try unbox(value, as: Double.self)! return Date(timeIntervalSince1970: double / 1000.0) case .iso8601: @@ -749,16 +750,16 @@ extension _XMLDecoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case .formatted(let formatter): - let string = try self.unbox(value, as: String.self)! + case let .formatted(formatter): + let string = try unbox(value, as: String.self)! guard let date = formatter.date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Date string does not match format expected by formatter.")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Date string does not match format expected by formatter.")) } return date - case .custom(let closure): - self.storage.push(container: value) + case let .custom(closure): + storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } @@ -767,25 +768,25 @@ extension _XMLDecoder { internal func unbox(_ value: Any, as type: Data.Type) throws -> Data? { guard !(value is NSNull) else { return nil } - switch self.options.dataDecodingStrategy { + switch options.dataDecodingStrategy { case .deferredToData: - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try Data(from: self) case .base64: guard let string = value as? String else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } guard let data = Data(base64Encoded: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Encountered Data is not valid Base64.")) + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Encountered Data is not valid Base64.")) } return data - case .custom(let closure): - self.storage.push(container: value) + case let .custom(closure): + storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } @@ -795,11 +796,11 @@ extension _XMLDecoder { guard !(value is NSNull) else { return nil } // Attempt to bridge from NSDecimalNumber. - let doubleValue = try self.unbox(value, as: Double.self)! + let doubleValue = try unbox(value, as: Double.self)! return Decimal(doubleValue) } - internal func unbox(_ value: Any, as type: T.Type) throws -> T? { + internal func unbox(_ value: Any, as type: T.Type) throws -> T? { let decoded: T if type == Date.self || type == NSDate.self { guard let date = try self.unbox(value, as: Date.self) else { return nil } @@ -813,7 +814,7 @@ extension _XMLDecoder { } guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Invalid URL string.")) } @@ -822,7 +823,7 @@ extension _XMLDecoder { guard let decimal = try self.unbox(value, as: Decimal.self) else { return nil } decoded = decimal as! T } else { - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try type.init(from: self) } @@ -830,4 +831,3 @@ extension _XMLDecoder { return decoded } } - diff --git a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift index 41d19b50..8cfa1bc7 100644 --- a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift +++ b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift @@ -12,34 +12,33 @@ import Foundation internal struct _XMLDecodingStorage { // MARK: Properties - + /// The container stack. /// Elements may be any one of the XML types (String, [String : Any]). - private(set) internal var containers: [Any] = [] - + internal private(set) var containers: [Any] = [] + // MARK: - Initialization - + /// Initializes `self` with no containers. internal init() {} - + // MARK: - Modifying the Stack - + internal var count: Int { - return self.containers.count + return containers.count } - + internal var topContainer: Any { - precondition(!self.containers.isEmpty, "Empty container stack.") - return self.containers.last! + precondition(!containers.isEmpty, "Empty container stack.") + return containers.last! } - + internal mutating func push(container: Any) { - self.containers.append(container) + containers.append(container) } - + internal mutating func popContainer() { - precondition(!self.containers.isEmpty, "Empty container stack.") - self.containers.removeLast() + precondition(!containers.isEmpty, "Empty container stack.") + containers.removeLast() } } - diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index d2fa3e44..ffc39a91 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -10,7 +10,7 @@ import Foundation // MARK: Decoding Containers -internal struct _XMLKeyedDecodingContainer : KeyedDecodingContainerProtocol { +internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainerProtocol { typealias Key = K // MARK: Properties @@ -19,15 +19,15 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain private let decoder: _XMLDecoder /// A reference to the container we're reading from. - private let container: [String : Any] + private let container: [String: Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - internal init(referencing decoder: _XMLDecoder, wrapping container: [String : Any]) { + internal init(referencing decoder: _XMLDecoder, wrapping container: [String: Any]) { self.decoder = decoder switch decoder.options.keyDecodingStrategy { case .useDefaultKeys: @@ -37,27 +37,27 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with dictionaries. self.container = Dictionary(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) - }, uniquingKeysWith: { (first, _) in first }) + }, uniquingKeysWith: { first, _ in first }) case .convertFromCapitalized: self.container = Dictionary(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromCapitalized(key), value) - }, uniquingKeysWith: { (first, _) in first }) - case .custom(let converter): + }, uniquingKeysWith: { first, _ in first }) + case let .custom(converter): self.container = Dictionary(container.map { key, value in (converter(decoder.codingPath + [_XMLKey(stringValue: key, intValue: nil)]).stringValue, value) - }, uniquingKeysWith: { (first, _) in first }) + }, uniquingKeysWith: { first, _ in first }) } - self.codingPath = decoder.codingPath + codingPath = decoder.codingPath } // MARK: - KeyedDecodingContainerProtocol Methods public var allKeys: [Key] { - return self.container.keys.compactMap { Key(stringValue: $0) } + return container.keys.compactMap { Key(stringValue: $0) } } public func contains(_ key: Key) -> Bool { - return self.container[key.stringValue] != nil + return container[key.stringValue] != nil } private func _errorDescription(of key: CodingKey) -> String { @@ -87,14 +87,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -102,14 +102,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -117,14 +117,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -132,14 +132,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -147,14 +147,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -162,14 +162,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -177,14 +177,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -192,14 +192,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -207,14 +207,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -222,14 +222,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -237,14 +237,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -252,14 +252,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -267,14 +267,14 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value @@ -282,75 +282,75 @@ internal struct _XMLKeyedDecodingContainer : KeyedDecodingContain public func decode(_ type: String.Type, forKey key: Key) throws -> String { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = try self.decoder.unbox(entry, as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value } - public func decode(_ type: T.Type, forKey key: Key) throws -> T { + public func decode(_ type: T.Type, forKey key: Key) throws -> T { guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) } - self.decoder.codingPath.append(key) + 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.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } return value } public func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = self.container[key.stringValue] else { throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"")) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: value) } - let container = _XMLKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + let container = _XMLKeyedDecodingContainer(referencing: decoder, wrapping: dictionary) return KeyedDecodingContainer(container) } public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = self.container[key.stringValue] else { throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \"\(key.stringValue)\"")) } guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: [Any].self, reality: value) } - return _XMLUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + return _XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: array) } private func _superDecoder(forKey key: CodingKey) throws -> Decoder { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - let value: Any = self.container[key.stringValue] ?? NSNull() - return _XMLDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + let value: Any = container[key.stringValue] ?? NSNull() + return _XMLDecoder(referencing: value, at: decoder.codingPath, options: decoder.options) } public func superDecoder() throws -> Decoder { diff --git a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift index 87e3f417..acf49a36 100644 --- a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift @@ -8,7 +8,7 @@ import Foundation -internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { +internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { // MARK: Properties /// A reference to the decoder we're reading from. @@ -18,10 +18,10 @@ internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { private let container: [Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The index of the element we're about to decode. - private(set) public var currentIndex: Int + public private(set) var currentIndex: Int // MARK: - Initialization @@ -29,27 +29,27 @@ internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { internal init(referencing decoder: _XMLDecoder, wrapping container: [Any]) { self.decoder = decoder self.container = container - self.codingPath = decoder.codingPath - self.currentIndex = 0 + codingPath = decoder.codingPath + currentIndex = 0 } // MARK: - UnkeyedDecodingContainer Methods public var count: Int? { - return self.container.count + return container.count } public var isAtEnd: Bool { - return self.currentIndex >= self.count! + return currentIndex >= count! } public mutating func decodeNil() throws -> Bool { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - if self.container[self.currentIndex] is NSNull { - self.currentIndex += 1 + if container[self.currentIndex] is NSNull { + currentIndex += 1 return true } else { return false @@ -57,308 +57,308 @@ internal struct _XMLUnkeyedDecodingContainer : UnkeyedDecodingContainer { } public mutating func decode(_ type: Bool.Type) throws -> Bool { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int.Type) throws -> Int { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int8.Type) throws -> Int8 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int16.Type) throws -> Int16 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int32.Type) throws -> Int32 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int64.Type) throws -> Int64 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt.Type) throws -> UInt { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt8.Type) throws -> UInt8 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt16.Type) throws -> UInt16 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt32.Type) throws -> UInt32 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt64.Type) throws -> UInt64 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Float.Type) throws -> Float { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Double.Type) throws -> Double { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: String.Type) throws -> String { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } - public mutating func decode(_ type: T.Type) throws -> T { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + public mutating func decode(_ type: T.Type) throws -> T { + guard !isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: type) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer { - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { + guard !isAtEnd else { throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) } let value = self.container[self.currentIndex] guard !(value is NSNull) else { throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: value) } - self.currentIndex += 1 - let container = _XMLKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + currentIndex += 1 + let container = _XMLKeyedDecodingContainer(referencing: decoder, wrapping: dictionary) return KeyedDecodingContainer(container) } public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { + guard !isAtEnd else { throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) } - let value = self.container[self.currentIndex] + let value = container[self.currentIndex] guard !(value is NSNull) else { throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get keyed decoding container -- found null value instead.")) } guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: [Any].self, reality: value) } - self.currentIndex += 1 - return _XMLUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + currentIndex += 1 + return _XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: array) } public mutating func superDecoder() throws -> Decoder { - self.decoder.codingPath.append(_XMLKey(index: self.currentIndex)) + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { + guard !isAtEnd else { throw DecodingError.valueNotFound(Decoder.self, - DecodingError.Context(codingPath: self.codingPath, + DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) } - let value = self.container[self.currentIndex] - self.currentIndex += 1 - return _XMLDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + let value = container[self.currentIndex] + currentIndex += 1 + return _XMLDecoder(referencing: value, at: decoder.codingPath, options: decoder.options) } } diff --git a/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift b/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift index acc4f405..f2e83865 100644 --- a/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift +++ b/Sources/XMLCoder/Encoder/EncodingErrorExtension.swift @@ -18,7 +18,7 @@ internal extension EncodingError { /// - parameter value: The value that was invalid to encode. /// - parameter path: The path of `CodingKey`s taken to encode this value. /// - returns: An `EncodingError` with the appropriate path and debug description. - internal static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + internal static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { let valueDescription: String if value == T.infinity { valueDescription = "\(T.self).infinity" diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index a6d5b883..d4295d21 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -15,8 +15,9 @@ import Foundation /// `XMLEncoder` facilitates the encoding of `Encodable` values into XML. open class XMLEncoder { // MARK: Options + /// The formatting of the output XML data. - public struct OutputFormatting : OptionSet { + public struct OutputFormatting: OptionSet { /// The format's default value. public let rawValue: UInt @@ -30,14 +31,14 @@ open class XMLEncoder { /// Produce XML with dictionary keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) + public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) } - + /// A node's encoding tyoe public enum NodeEncoding { case attribute case element - + public static let `default`: NodeEncoding = .element } @@ -126,7 +127,7 @@ open class XMLEncoder { internal static func _convertToSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - var words : [Range] = [] + var words: [Range] = [] // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase // // myProperty -> my_property @@ -134,15 +135,15 @@ open class XMLEncoder { // // We assume, per Swift naming conventions, that the first character of the key is lowercase. var wordStart = stringKey.startIndex - var searchRange = stringKey.index(after: wordStart)..1 capital letters. Turn those into a word, stopping at the capital before the lower case character. let beforeLowerIndex = stringKey.index(before: lowerCaseRange.lowerBound) - words.append(upperCaseRange.lowerBound.. ((CodingKey) -> XMLEncoder.NodeEncoding)) - + internal func nodeEncodings( forType codableType: Encodable.Type, with encoder: Encoder @@ -191,7 +192,7 @@ open class XMLEncoder { switch self { case .deferredToEncoder: return { _ in .default } - case .custom(let closure): + case let .custom(closure): return closure(codableType, encoder) } } @@ -219,7 +220,7 @@ open class XMLEncoder { open var stringEncodingStrategy: StringEncodingStrategy = .deferredToString /// Contextual user-provided information for use during encoding. - open var userInfo: [CodingUserInfoKey : Any] = [:] + open var userInfo: [CodingUserInfoKey: Any] = [:] /// Options set on the top-level encoder to pass down the encoding hierarchy. internal struct _Options { @@ -229,7 +230,7 @@ open class XMLEncoder { let keyEncodingStrategy: KeyEncodingStrategy let nodeEncodingStrategy: NodeEncodingStrategy let stringEncodingStrategy: StringEncodingStrategy - let userInfo: [CodingUserInfoKey : Any] + let userInfo: [CodingUserInfoKey: Any] } /// The options set on the top-level encoder. @@ -244,10 +245,12 @@ open class XMLEncoder { } // MARK: - Constructing a XML Encoder + /// Initializes `self` with default strategies. public init() {} // MARK: - Encoding Values + /// Encodes the given top-level value and returns its XML representation. /// /// - parameter value: The value to encode. @@ -255,12 +258,12 @@ open class XMLEncoder { /// - returns: A new `Data` value containing the encoded XML data. /// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. /// - throws: An error if any value throws an error during encoding. - open func encode(_ value: T, withRootKey rootKey: String, header: XMLHeader? = nil) throws -> Data { + open func encode(_ value: T, withRootKey rootKey: String, header: XMLHeader? = nil) throws -> Data { let encoder = _XMLEncoder( - options: self.options, + options: options, nodeEncodings: [] ) - encoder.nodeEncodings.append(self.options.nodeEncodingStrategy.nodeEncodings(forType: T.self, with: encoder)) + encoder.nodeEncodings.append(options.nodeEncodingStrategy.nodeEncodings(forType: T.self, with: encoder)) guard let topLevel = try encoder.box_(value) else { throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) did not encode any values.")) @@ -277,9 +280,9 @@ open class XMLEncoder { guard let element = _XMLElement.createRootElement(rootKey: rootKey, object: topLevel) else { throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Unable to encode the given top-level value to XML.")) } - + let withCDATA = stringEncodingStrategy != .deferredToString - return element.toXMLString(with: header, withCDATA: withCDATA, formatting: self.outputFormatting).data(using: .utf8, allowLossyConversion: true)! + return element.toXMLString(with: header, withCDATA: withCDATA, formatting: outputFormatting).data(using: .utf8, allowLossyConversion: true)! } } @@ -294,12 +297,12 @@ internal class _XMLEncoder: Encoder { /// The path to the current point in encoding. public var codingPath: [CodingKey] - + public var nodeEncodings: [(CodingKey) -> XMLEncoder.NodeEncoding] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + public var userInfo: [CodingUserInfoKey: Any] { + return options.userInfo } // MARK: - Initialization @@ -311,7 +314,7 @@ internal class _XMLEncoder: Encoder { codingPath: [CodingKey] = [] ) { self.options = options - self.storage = _XMLEncodingStorage() + storage = _XMLEncodingStorage() self.codingPath = codingPath self.nodeEncodings = nodeEncodings } @@ -326,16 +329,17 @@ internal class _XMLEncoder: Encoder { // // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path. // Things which will not request containers do not need to have the coding path extended for them (but it doesn't matter if it is, because they will not reach here). - return self.storage.count == self.codingPath.count + return storage.count == codingPath.count } // MARK: - Encoder Methods + public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. let topContainer: NSMutableDictionary - if self.canEncodeNewValue { + if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushKeyedContainer() + topContainer = storage.pushKeyedContainer() } else { guard let container = self.storage.containers.last as? NSMutableDictionary else { preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") @@ -343,18 +347,17 @@ internal class _XMLEncoder: Encoder { topContainer = container } - - - let container = _XMLKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + + let container = _XMLKeyedEncodingContainer(referencing: self, codingPath: codingPath, wrapping: topContainer) return KeyedEncodingContainer(container) } public func unkeyedContainer() -> UnkeyedEncodingContainer { // If an existing unkeyed container was already requested, return that one. let topContainer: NSMutableArray - if self.canEncodeNewValue { + if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushUnkeyedContainer() + topContainer = storage.pushUnkeyedContainer() } else { guard let container = self.storage.containers.last as? NSMutableArray else { preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") @@ -363,7 +366,7 @@ internal class _XMLEncoder: Encoder { topContainer = container } - return _XMLUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + return _XMLUnkeyedEncodingContainer(referencing: self, codingPath: codingPath, wrapping: topContainer) } public func singleValueContainer() -> SingleValueEncodingContainer { @@ -373,7 +376,7 @@ internal class _XMLEncoder: Encoder { // MARK: - Encoding Containers -fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingContainerProtocol { +fileprivate struct _XMLKeyedEncodingContainer: KeyedEncodingContainerProtocol { typealias Key = K // MARK: Properties @@ -382,10 +385,10 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont private let encoder: _XMLEncoder /// A reference to the container we're writing to. - private let container: NSMutableDictionary + private let container: NSMutableDictionary /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization @@ -405,7 +408,7 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont case .convertToSnakeCase: let newKeyString = XMLEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _XMLKey(stringValue: newKeyString, intValue: key.intValue) - case .custom(let converter): + case let .custom(converter): return converter(codingPath + [key]) } } @@ -413,11 +416,11 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont // MARK: - KeyedEncodingContainerProtocol Methods public mutating func encodeNil(forKey key: Key) throws { - self.container[_converted(key).stringValue] = NSNull() + container[_converted(key).stringValue] = NSNull() } public mutating func encode(_ value: Bool, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -425,19 +428,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: Int, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -445,19 +448,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: Int8, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -465,19 +468,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: Int16, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -485,19 +488,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: Int32, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -505,19 +508,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: Int64, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -525,19 +528,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: UInt, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -545,19 +548,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: UInt8, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -565,19 +568,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: UInt16, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -585,19 +588,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: UInt32, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -605,19 +608,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: UInt64, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -625,19 +628,19 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: String, forKey key: Key) throws { - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -645,27 +648,27 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + container[_converted(key).stringValue] = encoder.box(value) } } public mutating func encode(_ value: Float, forKey key: Key) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) } public mutating func encode(_ value: Double, forKey key: Key) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") @@ -673,42 +676,42 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = try encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = try encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) } } - public mutating func encode(_ value: T, forKey key: Key) throws { + public mutating func encode(_ value: T, forKey key: Key) throws { guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") } - self.encoder.codingPath.append(key) - let nodeEncodings = self.encoder.options.nodeEncodingStrategy.nodeEncodings( + encoder.codingPath.append(key) + let nodeEncodings = encoder.options.nodeEncodingStrategy.nodeEncodings( forType: T.self, - with: self.encoder + with: encoder ) - self.encoder.nodeEncodings.append(nodeEncodings) + encoder.nodeEncodings.append(nodeEncodings) defer { - let _ = self.encoder.nodeEncodings.removeLast() + _ = self.encoder.nodeEncodings.removeLast() self.encoder.codingPath.removeLast() } switch strategy(key) { case .attribute: if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = try encoder.box(value) } else { let attributesContainer = NSMutableDictionary() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer + attributesContainer[_converted(key).stringValue] = try encoder.box(value) + container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) } } @@ -716,32 +719,32 @@ fileprivate struct _XMLKeyedEncodingContainer : KeyedEncodingCont let dictionary = NSMutableDictionary() self.container[_converted(key).stringValue] = dictionary - self.codingPath.append(key) + codingPath.append(key) defer { self.codingPath.removeLast() } - let container = _XMLKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _XMLKeyedEncodingContainer(referencing: encoder, codingPath: codingPath, wrapping: dictionary) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { let array = NSMutableArray() - self.container[_converted(key).stringValue] = array + container[_converted(key).stringValue] = array - self.codingPath.append(key) + codingPath.append(key) defer { self.codingPath.removeLast() } - return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + return _XMLUnkeyedEncodingContainer(referencing: encoder, codingPath: codingPath, wrapping: array) } public mutating func superEncoder() -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, key: _XMLKey.super, convertedKey: _converted(_XMLKey.super), wrapping: self.container) + return _XMLReferencingEncoder(referencing: encoder, key: _XMLKey.super, convertedKey: _converted(_XMLKey.super), wrapping: container) } public mutating func superEncoder(forKey key: Key) -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, key: key, convertedKey: _converted(key), wrapping: self.container) + return _XMLReferencingEncoder(referencing: encoder, key: key, convertedKey: _converted(key), wrapping: container) } } -fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { +fileprivate struct _XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer { // MARK: Properties /// A reference to the encoder we're writing to. @@ -751,11 +754,11 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { private let container: NSMutableArray /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The number of elements encoded into the container. public var count: Int { - return self.container.count + return container.count } // MARK: - Initialization @@ -769,70 +772,70 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - public mutating func encodeNil() throws { self.container.add(NSNull()) } - public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } - - public mutating func encode(_ value: Float) throws { + public mutating func encodeNil() throws { container.add(NSNull()) } + public mutating func encode(_ value: Bool) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int8) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int16) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int32) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int64) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt8) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt16) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt32) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt64) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: String) throws { container.add(encoder.box(value)) } + + public mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_XMLKey(index: self.count)) + encoder.codingPath.append(_XMLKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } public mutating func encode(_ value: Double) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_XMLKey(index: self.count)) + encoder.codingPath.append(_XMLKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } - public mutating func encode(_ value: T) throws { - self.encoder.codingPath.append(_XMLKey(index: self.count)) - let nodeEncodings = self.encoder.options.nodeEncodingStrategy.nodeEncodings( + public mutating func encode(_ value: T) throws { + encoder.codingPath.append(_XMLKey(index: count)) + let nodeEncodings = encoder.options.nodeEncodingStrategy.nodeEncodings( forType: T.self, - with: self.encoder + with: encoder ) - self.encoder.nodeEncodings.append(nodeEncodings) + encoder.nodeEncodings.append(nodeEncodings) defer { - let _ = self.encoder.nodeEncodings.removeLast() + _ = self.encoder.nodeEncodings.removeLast() self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { - self.codingPath.append(_XMLKey(index: self.count)) + codingPath.append(_XMLKey(index: count)) defer { self.codingPath.removeLast() } let dictionary = NSMutableDictionary() self.container.add(dictionary) - let container = _XMLKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _XMLKeyedEncodingContainer(referencing: encoder, codingPath: codingPath, wrapping: dictionary) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - self.codingPath.append(_XMLKey(index: self.count)) + codingPath.append(_XMLKey(index: count)) defer { self.codingPath.removeLast() } let array = NSMutableArray() - self.container.add(array) - return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + container.add(array) + return _XMLUnkeyedEncodingContainer(referencing: encoder, codingPath: codingPath, wrapping: array) } public mutating func superEncoder() -> Encoder { - return _XMLReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container) + return _XMLReferencingEncoder(referencing: encoder, at: container.count, wrapping: container) } } @@ -840,100 +843,100 @@ extension _XMLEncoder: SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods fileprivate func assertCanEncodeNewValue() { - precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + precondition(canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") } public func encodeNil() throws { assertCanEncodeNewValue() - self.storage.push(container: NSNull()) + storage.push(container: NSNull()) } public func encode(_ value: Bool) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int8) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int16) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int32) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int64) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt8) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt16) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt32) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt64) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: String) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Float) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } public func encode(_ value: Double) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } - public func encode(_ value: T) throws { + public func encode(_ value: T) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } } extension _XMLEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } @@ -941,7 +944,7 @@ extension _XMLEncoder { internal func box(_ value: Float) throws -> NSObject { if value.isInfinite || value.isNaN { - guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = options.nonConformingFloatEncodingStrategy else { throw EncodingError._invalidFloatingPointValue(value, at: codingPath) } @@ -959,7 +962,7 @@ extension _XMLEncoder { internal func box(_ value: Double) throws -> NSObject { if value.isInfinite || value.isNaN { - guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, nan: nanString) = options.nonConformingFloatEncodingStrategy else { throw EncodingError._invalidFloatingPointValue(value, at: codingPath) } @@ -976,10 +979,10 @@ extension _XMLEncoder { } internal func box(_ value: Date) throws -> NSObject { - switch self.options.dateEncodingStrategy { + switch options.dateEncodingStrategy { case .deferredToDate: try value.encode(to: self) - return self.storage.popContainer() + return storage.popContainer() case .secondsSince1970: return NSNumber(value: value.timeIntervalSince1970) case .millisecondsSince1970: @@ -990,60 +993,59 @@ extension _XMLEncoder { } else { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case .formatted(let formatter): + case let .formatted(formatter): return formatter.string(from: value) as NSObject - case .custom(let closure): - let depth = self.storage.count + case let .custom(closure): + let depth = storage.count try closure(value, self) - - guard self.storage.count > depth else { return NSDictionary() } - - return self.storage.popContainer() + + guard storage.count > depth else { return NSDictionary() } + + return storage.popContainer() } } internal func box(_ value: Data) throws -> NSObject { - switch self.options.dataEncodingStrategy { + switch options.dataEncodingStrategy { case .deferredToData: try value.encode(to: self) - return self.storage.popContainer() + return storage.popContainer() case .base64: return value.base64EncodedString() as NSObject - case .custom(let closure): - let depth = self.storage.count + case let .custom(closure): + let depth = storage.count try closure(value, self) - - guard self.storage.count > depth else { return NSDictionary() } - - return self.storage.popContainer() as NSObject + + guard storage.count > depth else { return NSDictionary() } + + return storage.popContainer() as NSObject } } - fileprivate func box(_ value: T) throws -> NSObject { - return try self.box_(value) ?? NSDictionary() + fileprivate func box(_ value: T) throws -> NSObject { + return try box_(value) ?? NSDictionary() } // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. - fileprivate func box_(_ value: T) throws -> NSObject? { + fileprivate func box_(_ value: T) throws -> NSObject? { if T.self == Date.self || T.self == NSDate.self { - return try self.box((value as! Date)) + return try box((value as! Date)) } else if T.self == Data.self || T.self == NSData.self { - return try self.box((value as! Data)) + return try box((value as! Data)) } else if T.self == URL.self || T.self == NSURL.self { - return self.box((value as! URL).absoluteString) + return box((value as! URL).absoluteString) } else if T.self == Decimal.self || T.self == NSDecimalNumber.self { return (value as! NSDecimalNumber) } - let depth = self.storage.count + let depth = storage.count try value.encode(to: self) // The top container should be a new container. - guard self.storage.count > depth else { + guard storage.count > depth else { return nil } - return self.storage.popContainer() + return storage.popContainer() } } - diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index ded3b4eb..89d6e1b1 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -16,7 +16,7 @@ internal struct _XMLEncodingStorage { /// The container stack. /// Elements may be any one of the XML types (NSNull, NSNumber, NSString, NSArray, NSDictionary). - private(set) internal var containers: [NSObject] = [] + internal private(set) var containers: [NSObject] = [] // MARK: - Initialization @@ -26,27 +26,27 @@ internal struct _XMLEncodingStorage { // MARK: - Modifying the Stack internal var count: Int { - return self.containers.count + return containers.count } internal mutating func pushKeyedContainer() -> NSMutableDictionary { let dictionary = NSMutableDictionary() - self.containers.append(dictionary) + containers.append(dictionary) return dictionary } internal mutating func pushUnkeyedContainer() -> NSMutableArray { let array = NSMutableArray() - self.containers.append(array) + containers.append(array) return array } internal mutating func push(container: NSObject) { - self.containers.append(container) + containers.append(container) } internal mutating func popContainer() -> NSObject { - precondition(!self.containers.isEmpty, "Empty container stack.") - return self.containers.popLast()! + precondition(!containers.isEmpty, "Empty container stack.") + return containers.popLast()! } } diff --git a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift index 9da655ca..bc364442 100644 --- a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift @@ -12,7 +12,7 @@ import Foundation /// _XMLReferencingEncoder is a special subclass of _XMLEncoder which has its own storage, but references the contents of a different encoder. /// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). -internal class _XMLReferencingEncoder : _XMLEncoder { +internal class _XMLReferencingEncoder: _XMLEncoder { // MARK: Reference types. /// The type of container we're referencing. @@ -41,14 +41,14 @@ internal class _XMLReferencingEncoder : _XMLEncoder { wrapping array: NSMutableArray ) { self.encoder = encoder - self.reference = .array(array, index) + reference = .array(array, index) super.init( options: encoder.options, nodeEncodings: encoder.nodeEncodings, codingPath: encoder.codingPath ) - self.codingPath.append(_XMLKey(index: index)) + codingPath.append(_XMLKey(index: index)) } /// Initializes `self` by referencing the given dictionary container in the given encoder. @@ -59,14 +59,14 @@ internal class _XMLReferencingEncoder : _XMLEncoder { wrapping dictionary: NSMutableDictionary ) { self.encoder = encoder - self.reference = .dictionary(dictionary, convertedKey.stringValue) + reference = .dictionary(dictionary, convertedKey.stringValue) super.init( options: encoder.options, nodeEncodings: encoder.nodeEncodings, codingPath: encoder.codingPath ) - self.codingPath.append(key) + codingPath.append(key) } // MARK: - Coding Path Operations @@ -75,7 +75,7 @@ internal class _XMLReferencingEncoder : _XMLEncoder { // With a regular encoder, the storage and coding path grow together. // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. // We have to take this into account. - return self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1 + return storage.count == codingPath.count - encoder.codingPath.count - 1 } // MARK: - Deinitialization @@ -90,10 +90,10 @@ internal class _XMLReferencingEncoder : _XMLEncoder { } switch self.reference { - case .array(let array, let index): + case let .array(array, index): array.insert(value, at: index) - case .dictionary(let dictionary, let key): + case let .dictionary(dictionary, key): dictionary[NSString(string: key)] = value } } diff --git a/Sources/XMLCoder/ISO8601DateFormatter.swift b/Sources/XMLCoder/ISO8601DateFormatter.swift index 85fb6889..f8e05ae5 100644 --- a/Sources/XMLCoder/ISO8601DateFormatter.swift +++ b/Sources/XMLCoder/ISO8601DateFormatter.swift @@ -19,5 +19,3 @@ internal var _iso8601Formatter: ISO8601DateFormatter = { formatter.formatOptions = .withInternetDateTime return formatter }() - - diff --git a/Sources/XMLCoder/XMLKey.swift b/Sources/XMLCoder/XMLKey.swift index ffc8f293..c3fb8261 100644 --- a/Sources/XMLCoder/XMLKey.swift +++ b/Sources/XMLCoder/XMLKey.swift @@ -12,17 +12,17 @@ import Foundation // Shared Key Types //===----------------------------------------------------------------------===// -internal struct _XMLKey : CodingKey { +internal struct _XMLKey: CodingKey { public var stringValue: String public var intValue: Int? - + public init?(stringValue: String) { self.stringValue = stringValue - self.intValue = nil + intValue = nil } - + public init?(intValue: Int) { - self.stringValue = "\(intValue)" + stringValue = "\(intValue)" self.intValue = intValue } @@ -30,13 +30,11 @@ internal struct _XMLKey : CodingKey { self.stringValue = stringValue self.intValue = intValue } - + internal init(index: Int) { - self.stringValue = "Index \(index)" - self.intValue = index + stringValue = "Index \(index)" + intValue = index } - + internal static let `super` = _XMLKey(stringValue: "super")! } - - diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index 9bbf7b61..142ca228 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -19,7 +19,7 @@ public struct XMLHeader { public let encoding: String? /// indicates whether a document relies on information from an external source. public let standalone: String? - + public init(version: Double? = nil, encoding: String? = nil, standalone: String? = nil) { self.version = version self.encoding = encoding @@ -31,7 +31,7 @@ public struct XMLHeader { } internal func toXML() -> String? { - guard !self.isEmpty() else { return nil } + guard !isEmpty() else { return nil } var string = "", ">"), ( "'", "'"), ("\"", """)] + static let escapedCharacterSet = [("&", "&"), ("<", "<"), (">", ">"), ("'", "'"), ("\"", """)] var key: String - var value: String? = nil + var value: String? var attributes: [String: String] = [:] var children: [String: [_XMLElement]] = [:] @@ -187,99 +187,99 @@ internal class _XMLElement { return node } - + func toXMLString(with header: XMLHeader? = nil, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { if let header = header, let headerXML = header.toXML() { return headerXML + _toXMLString(withCDATA: cdata, formatting: formatting) } - return _toXMLString(withCDATA: cdata, formatting: formatting) + return _toXMLString(withCDATA: cdata, formatting: formatting) } - fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - formatXMLElements(from: children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - - fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { - var string = "" - for child in childElement.value { - string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) - string += prettyPrinted ? "\n" : "" - } - return string - } - - fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { - formatXMLElements(from: children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - - fileprivate func attributeString(key: String, value: String) -> String { - return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" - } - - fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { - for (key, value) in keyValuePairs { - string += attributeString(key: key, value: value) - } - } - - fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { - for childElement in children { - string += elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) - } - } - - fileprivate func formatSortedXMLAttributes(_ string: inout String) { - formatXMLAttributes(from: attributes.sorted(by: { $0.key < $1.key }), into: &string) - } - - fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { - formatXMLAttributes(from: attributes.map { (key: $0, value: $1) }, into: &string) - } - - fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { - if #available(OSX 10.13, iOS 11.0, *) { - if formatting.contains(.sortedKeys) { - formatSortedXMLAttributes(&string) - return - } - formatUnsortedXMLAttributes(&string) - return - } - formatUnsortedXMLAttributes(&string) - } - - fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { - if #available(OSX 10.13, iOS 11.0, *) { - if formatting.contains(.sortedKeys) { - formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - return - } - formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - return - } - formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) - } - - fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { + fileprivate func formatUnsortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + formatXMLElements(from: children.map { (key: $0, value: $1) }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func elementString(for childElement: (key: String, value: [_XMLElement]), at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) -> String { + var string = "" + for child in childElement.value { + string += child._toXMLString(indented: level + 1, withCDATA: cdata, formatting: formatting) + string += prettyPrinted ? "\n" : "" + } + return string + } + + fileprivate func formatSortedXMLElements(_ string: inout String, _ level: Int, _ cdata: Bool, _ formatting: XMLEncoder.OutputFormatting, _ prettyPrinted: Bool) { + formatXMLElements(from: children.sorted { $0.key < $1.key }, into: &string, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + + fileprivate func attributeString(key: String, value: String) -> String { + return " \(key)=\"\(value.escape(_XMLElement.escapedCharacterSet))\"" + } + + fileprivate func formatXMLAttributes(from keyValuePairs: [(key: String, value: String)], into string: inout String) { + for (key, value) in keyValuePairs { + string += attributeString(key: key, value: value) + } + } + + fileprivate func formatXMLElements(from children: [(key: String, value: [_XMLElement])], into string: inout String, at level: Int, cdata: Bool, formatting: XMLEncoder.OutputFormatting, prettyPrinted: Bool) { + for childElement in children { + string += elementString(for: childElement, at: level, cdata: cdata, formatting: formatting, prettyPrinted: prettyPrinted) + } + } + + fileprivate func formatSortedXMLAttributes(_ string: inout String) { + formatXMLAttributes(from: attributes.sorted(by: { $0.key < $1.key }), into: &string) + } + + fileprivate func formatUnsortedXMLAttributes(_ string: inout String) { + formatXMLAttributes(from: attributes.map { (key: $0, value: $1) }, into: &string) + } + + fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLAttributes(&string) + return + } + formatUnsortedXMLAttributes(&string) + return + } + formatUnsortedXMLAttributes(&string) + } + + fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { + if #available(OSX 10.13, iOS 11.0, *) { + if formatting.contains(.sortedKeys) { + formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return + } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + return + } + formatUnsortedXMLElements(&string, level, cdata, formatting, prettyPrinted) + } + + fileprivate func _toXMLString(indented level: Int = 0, withCDATA cdata: Bool, formatting: XMLEncoder.OutputFormatting, ignoreEscaping: Bool = false) -> String { let prettyPrinted = formatting.contains(.prettyPrinted) let indentation = String(repeating: " ", count: (prettyPrinted ? level : 0) * 4) var string = indentation string += "<\(key)" - - formatXMLAttributes(formatting, &string) - + + formatXMLAttributes(formatting, &string) + if let value = value { string += ">" if !ignoreEscaping { - string += (cdata == true ? "" : "\(value.escape(_XMLElement.escapedCharacterSet))" ) + string += (cdata == true ? "" : "\(value.escape(_XMLElement.escapedCharacterSet))") } else { string += "\(value)" } string += "" } else if !children.isEmpty { string += prettyPrinted ? ">\n" : ">" - formatXMLElements(formatting, &string, level, cdata, prettyPrinted) - + formatXMLElements(formatting, &string, level, cdata, prettyPrinted) + string += indentation string += "" } else { @@ -324,7 +324,7 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } } - func parse(with data: Data) throws -> _XMLElement? { + func parse(with data: Data) throws -> _XMLElement? { let xmlParser = XMLParser(data: data) xmlParser.delegate = self @@ -342,7 +342,7 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { stack = [_XMLElement]() } - func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { + func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String] = [:]) { let node = _XMLElement(key: elementName) node.attributes = attributeDict stack.append(node) @@ -358,7 +358,7 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { - if let poppedNode = stack.popLast(){ + if let poppedNode = stack.popLast() { if let content = poppedNode.value?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) { if content.isEmpty { poppedNode.value = nil @@ -367,7 +367,7 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { } } - if (stack.isEmpty) { + if stack.isEmpty { root = poppedNode currentNode = nil } else { @@ -390,4 +390,3 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { print(parseError) } } - diff --git a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift index d8f6f7e1..0a320e21 100644 --- a/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift +++ b/Tests/XMLCoderTests/NodeEncodingStrategyTests.swift @@ -6,7 +6,7 @@ class NodeEncodingStrategyTests: XCTestCase { let element: Element enum CodingKeys: String, CodingKey { - case element = "element" + case element } } @@ -37,32 +37,32 @@ class NodeEncodingStrategyTests: XCTestCase { return .attribute } } - - fileprivate struct ComplexUnkeyedContainer: Encodable { - let elements: [ComplexElement] - - enum CodingKeys: String, CodingKey { - case elements = "element" - } - } - - fileprivate struct ComplexElement: Encodable { - struct Key: Encodable { - let a: String - let b: String - let c: String - } - - var key: Key = Key(a: "C", b: "B", c: "A") - - enum CodingKeys: CodingKey { - case key - } - - static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { - return .attribute - } - } + + fileprivate struct ComplexUnkeyedContainer: Encodable { + let elements: [ComplexElement] + + enum CodingKeys: String, CodingKey { + case elements = "element" + } + } + + fileprivate struct ComplexElement: Encodable { + struct Key: Encodable { + let a: String + let b: String + let c: String + } + + var key: Key = Key(a: "C", b: "B", c: "A") + + enum CodingKeys: CodingKey { + case key + } + + static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { + return .attribute + } + } func testSingleContainer() { let encoder = XMLEncoder() @@ -74,21 +74,21 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - value - - -""" + """ + + + value + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, encoder in + encoder.nodeEncodingStrategy = .custom { codableType, _ in guard let barType = codableType as? Element.Type else { - return { _ in return .default } + return { _ in .default } } return barType.nodeEncoding(forKey:) } @@ -99,11 +99,11 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - -""" + """ + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -120,23 +120,23 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - value - - - -""" + """ + + + + value + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, encoder in + encoder.nodeEncodingStrategy = .custom { codableType, _ in guard let barType = codableType as? Element.Type else { - return { _ in return .default } + return { _ in .default } } return barType.nodeEncoding(forKey:) } @@ -147,13 +147,13 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = - """ - - - - - -""" + """ + + + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -170,24 +170,24 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - value - - - value - - -""" + """ + + + value + + + value + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") } - encoder.nodeEncodingStrategy = .custom { codableType, encoder in + encoder.nodeEncodingStrategy = .custom { codableType, _ in guard let barType = codableType as? Element.Type else { - return { _ in return .default } + return { _ in .default } } return barType.nodeEncoding(forKey:) } @@ -198,12 +198,12 @@ class NodeEncodingStrategyTests: XCTestCase { let xml = String(data: data, encoding: .utf8)! let expected = -""" - - - - -""" + """ + + + + + """ XCTAssertEqual(xml, expected) } catch { XCTAssert(false, "failed to decode the example: \(error)") @@ -215,68 +215,68 @@ class NodeEncodingStrategyTests: XCTestCase { ("testKeyedContainer", testKeyedContainer), ("testUnkeyedContainer", testUnkeyedContainer), ] - - func testItSortsKeysWhenEncodingAsElements() { - let encoder = XMLEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = [.sortedKeys, .prettyPrinted] - } else { - return - } - - do { - let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) - let data = try encoder.encode(container, withRootKey: "container") - let xml = String(data: data, encoding: .utf8)! - - let expected = - """ - - - - C - B - A - - - -""" - XCTAssertEqual(xml, expected) - } catch { - XCTAssert(false, "failed to decode the example: \(error)") - } - } - - func testItSortsKeysWhenEncodingAsAttributes() { - let encoder = XMLEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = [.sortedKeys, .prettyPrinted] - encoder.nodeEncodingStrategy = .custom { key, encoder in - if key == ComplexElement.Key.self { - return { _ in .attribute } - } - return { _ in .element } - } - } else { - return - } - - do { - let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) - let data = try encoder.encode(container, withRootKey: "container") - let xml = String(data: data, encoding: .utf8)! - - let expected = - """ - - - - - -""" - XCTAssertEqual(xml, expected) - } catch { - XCTAssert(false, "failed to decode the example: \(error)") - } - } + + func testItSortsKeysWhenEncodingAsElements() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + C + B + A + + + + """ + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } + + func testItSortsKeysWhenEncodingAsAttributes() { + let encoder = XMLEncoder() + if #available(macOS 10.13, *) { + encoder.outputFormatting = [.sortedKeys, .prettyPrinted] + encoder.nodeEncodingStrategy = .custom { key, _ in + if key == ComplexElement.Key.self { + return { _ in .attribute } + } + return { _ in .element } + } + } else { + return + } + + do { + let container = ComplexUnkeyedContainer(elements: [ComplexElement()]) + let data = try encoder.encode(container, withRootKey: "container") + let xml = String(data: data, encoding: .utf8)! + + let expected = + """ + + + + + + """ + XCTAssertEqual(xml, expected) + } catch { + XCTAssert(false, "failed to decode the example: \(error)") + } + } } diff --git a/Tests/XMLCoderTests/XMLCoderTests.swift b/Tests/XMLCoderTests/XMLCoderTests.swift index 5234dc3f..7945a8ff 100644 --- a/Tests/XMLCoderTests/XMLCoderTests.swift +++ b/Tests/XMLCoderTests/XMLCoderTests.swift @@ -20,7 +20,7 @@ let example = """ struct Relationships: Codable { let items: [Relationship] - + enum CodingKeys: String, CodingKey { case items = "relationship" } @@ -32,11 +32,11 @@ struct Relationship: Codable { case extendedProperties = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" case coreProperties = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" } - + let id: String let type: SchemaType let target: String - + enum CodingKeys: CodingKey { case type case id @@ -48,19 +48,18 @@ class XMLCoderTests: XCTestCase { func testExample() { do { guard let data = example.data(using: .utf8) else { return } - + let decoder = XMLDecoder() decoder.keyDecodingStrategy = .convertFromCapitalized - + let rels = try decoder.decode(Relationships.self, from: data) - + XCTAssertEqual(rels.items[0].id, "rId1") } catch { XCTAssert(false, "failed to decode the example: \(error)") } } - - + static var allTests = [ ("testExample", testExample), ] From 684bc13385592b000b66fb7a2de4b14a87d69883 Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 17:34:41 +0100 Subject: [PATCH 07/10] Complete if #availables --- Sources/XMLCoder/XMLStackParser.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index 142ca228..d2dafe31 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -237,7 +237,7 @@ internal class _XMLElement { } fileprivate func formatXMLAttributes(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String) { - if #available(OSX 10.13, iOS 11.0, *) { + if #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { if formatting.contains(.sortedKeys) { formatSortedXMLAttributes(&string) return @@ -249,7 +249,7 @@ internal class _XMLElement { } fileprivate func formatXMLElements(_ formatting: XMLEncoder.OutputFormatting, _ string: inout String, _ level: Int, _ cdata: Bool, _ prettyPrinted: Bool) { - if #available(OSX 10.13, iOS 11.0, *) { + if #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { if formatting.contains(.sortedKeys) { formatSortedXMLElements(&string, level, cdata, formatting, prettyPrinted) return From 3ddf8aaaa7f91c8ffa0ca889960c99fb4417960a Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 21:55:57 +0100 Subject: [PATCH 08/10] Add support for char data token --- Sources/XMLCoder/Decoder/XMLDecoder.swift | 16 +++++++- Sources/XMLCoder/XMLStackParser.swift | 37 +++++++++++++++---- .../CharacterDataDecodingTestCase.swift | 34 +++++++++++++++++ Tests/XMLCoderTests/DecodingTestCase.swift | 24 ++++++++++++ XMLCoder.xcodeproj/project.pbxproj | 8 ++++ 5 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift create mode 100644 Tests/XMLCoderTests/DecodingTestCase.swift diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 460d572e..25c33d20 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -196,7 +196,19 @@ open class XMLDecoder { /// Contextual user-provided information for use during decoding. open var userInfo: [CodingUserInfoKey : Any] = [:] - + + /// When an XML Element has both attributes and child elements, the CharData within the element will be keyed with the `characterDataToken` + /// - Note The following XML has both attribute data, child elements, and character data: + /// ``` + /// + /// some string value + /// valuevalue + /// + /// ``` + /// The "some string value" will be keyed on "CharData" + open var characterDataToken: String? + + /// Options set on the top-level encoder to pass down the decoding hierarchy. internal struct _Options { let dateDecodingStrategy: DateDecodingStrategy @@ -230,7 +242,7 @@ open class XMLDecoder { open func decode(_ type: T.Type, from data: Data) throws -> T { let topLevel: [String: Any] do { - topLevel = try _XMLStackParser.parse(with: data) + topLevel = try _XMLStackParser.parse(with: data, charDataToken: self.characterDataToken) } catch { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid XML.", underlyingError: error)) } diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index cb282b32..cf15ddfb 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -153,24 +153,30 @@ internal class _XMLElement { parentElement.children[key] = (parentElement.children[key] ?? []) + [element] } - fileprivate func flatten() -> [String: Any] { + fileprivate func flatten(with charDataKey: String? = nil) -> [String: Any] { var node: [String: Any] = attributes - + + if children.isEmpty { + if let key = charDataKey { + node[key] = value + } + } + for childElement in children { for child in childElement.value { if let content = child.value { if let oldContent = node[childElement.key] as? Array { node[childElement.key] = oldContent + [content] - + } else if let oldContent = node[childElement.key] { node[childElement.key] = [oldContent, content] - + } else { node[childElement.key] = content } } else if !child.children.isEmpty || !child.attributes.isEmpty { let newValue = child.flatten() - + if let existingValue = node[childElement.key] { if var array = existingValue as? Array { array.append(newValue) @@ -254,12 +260,29 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { var currentElementName: String? var currentElementData = "" - static func parse(with data: Data) throws -> [String: Any] { + /// Parses the XML data and returns a dictionary of the parsed output + /// + /// - Parameters: + /// - data: The Data to be parsed + /// - charDataToken: The token to key the charData in mixed content elements off of + /// - Returns: Dictionary of the parsed XML + /// - Throws: DecodingError if there's an issue parsing the XML + /// - Note: + /// When an XML Element has both attributes and child elements, the CharData within the element will be keyed with the `characterDataToken` + /// The following XML has both attribute data, child elements, and character data: + /// ``` + /// + /// some string value + /// valuevalue + /// + /// ``` + /// The "some string value" will be keyed on "CharData" + static func parse(with data: Data, charDataToken: String? = nil) throws -> [String: Any] { let parser = _XMLStackParser() do { if let node = try parser.parse(with: data) { - return node.flatten() + return node.flatten(with: charDataToken) } else { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data could not be parsed into XML.")) } diff --git a/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift b/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift new file mode 100644 index 00000000..ad15c1f6 --- /dev/null +++ b/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift @@ -0,0 +1,34 @@ +import Foundation +import XMLCoder +import XCTest + +class CharacterDataDecodingTestCase: DecodingTestCase { + + override func setUp() { + super.setUp() + decoder.characterDataToken = "#text" + } + + func testItDecodesCharData() { + // given + struct Attribute: Decodable, Equatable { + enum CodingKeys: String, CodingKey { + case name = "name" + case value = "#text" + } + + let name: String + let value: String + } + let xml = """ +0 +""" + + // when + let attr: Attribute = try! decode(xml) + + // then + XCTAssertEqual(attr, Attribute(name: "Xpos", value: "0")) + } +} + diff --git a/Tests/XMLCoderTests/DecodingTestCase.swift b/Tests/XMLCoderTests/DecodingTestCase.swift new file mode 100644 index 00000000..626a280e --- /dev/null +++ b/Tests/XMLCoderTests/DecodingTestCase.swift @@ -0,0 +1,24 @@ +import Foundation +import XMLCoder +import XCTest + +class DecodingTestCase: XCTestCase { + var decoder: XMLDecoder! + + func decode(_ string: String) throws -> T where T: Decodable { + let data = string.data(using: .utf8)! + let result: T = try decoder.decode(T.self, from: data) + return result + } + + override func setUp() { + super.setUp() + decoder = XMLDecoder() + } + + override func tearDown() { + decoder = nil + super.tearDown() + } +} + diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index f83110d6..7a611162 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + A52C85E221B4669600EF98B7 /* DecodingTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52C85E121B4669600EF98B7 /* DecodingTestCase.swift */; }; + A52C85E421B4778A00EF98B7 /* CharacterDataDecodingTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52C85E321B4778A00EF98B7 /* CharacterDataDecodingTestCase.swift */; }; BFE1C59121A4242300EA0458 /* NodeEncodingStrategyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE1C58F21A4232100EA0458 /* NodeEncodingStrategyTests.swift */; }; OBJ_35 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; OBJ_41 /* XMLCoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* XMLCoderTests.swift */; }; @@ -57,6 +59,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + A52C85E121B4669600EF98B7 /* DecodingTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodingTestCase.swift; sourceTree = ""; }; + A52C85E321B4778A00EF98B7 /* CharacterDataDecodingTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterDataDecodingTestCase.swift; sourceTree = ""; }; BFE1C58F21A4232100EA0458 /* NodeEncodingStrategyTests.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = NodeEncodingStrategyTests.swift; sourceTree = ""; tabWidth = 4; }; D1BCEBCF21943CA6000B550F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D1BCEBD021943F09000B550F /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = ""; }; @@ -127,6 +131,8 @@ children = ( OBJ_25 /* XMLCoderTests.swift */, BFE1C58F21A4232100EA0458 /* NodeEncodingStrategyTests.swift */, + A52C85E321B4778A00EF98B7 /* CharacterDataDecodingTestCase.swift */, + A52C85E121B4669600EF98B7 /* DecodingTestCase.swift */, ); name = XMLCoderTests; path = Tests/XMLCoderTests; @@ -294,6 +300,8 @@ files = ( OBJ_41 /* XMLCoderTests.swift in Sources */, BFE1C59121A4242300EA0458 /* NodeEncodingStrategyTests.swift in Sources */, + A52C85E421B4778A00EF98B7 /* CharacterDataDecodingTestCase.swift in Sources */, + A52C85E221B4669600EF98B7 /* DecodingTestCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 7d1a424dadade374a98761318da237d995153de7 Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 22:00:56 +0100 Subject: [PATCH 09/10] Run through SwiftFormat --- Sources/XMLCoder/Decoder/XMLDecoder.swift | 29 +++++----- Sources/XMLCoder/XMLStackParser.swift | 58 +++++++++---------- .../CharacterDataDecodingTestCase.swift | 56 +++++++++--------- Tests/XMLCoderTests/DecodingTestCase.swift | 37 ++++++------ 4 files changed, 88 insertions(+), 92 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index a8b1e833..05a985ba 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -196,20 +196,19 @@ open class XMLDecoder { open var keyDecodingStrategy: KeyDecodingStrategy = .useDefaultKeys /// Contextual user-provided information for use during decoding. - open var userInfo: [CodingUserInfoKey : Any] = [:] - - /// When an XML Element has both attributes and child elements, the CharData within the element will be keyed with the `characterDataToken` - /// - Note The following XML has both attribute data, child elements, and character data: - /// ``` - /// - /// some string value - /// valuevalue - /// - /// ``` - /// The "some string value" will be keyed on "CharData" - open var characterDataToken: String? - - + open var userInfo: [CodingUserInfoKey: Any] = [:] + + /// When an XML Element has both attributes and child elements, the CharData within the element will be keyed with the `characterDataToken` + /// - Note The following XML has both attribute data, child elements, and character data: + /// ``` + /// + /// some string value + /// valuevalue + /// + /// ``` + /// The "some string value" will be keyed on "CharData" + open var characterDataToken: String? + /// Options set on the top-level encoder to pass down the decoding hierarchy. internal struct _Options { let dateDecodingStrategy: DateDecodingStrategy @@ -245,7 +244,7 @@ open class XMLDecoder { open func decode(_ type: T.Type, from data: Data) throws -> T { let topLevel: [String: Any] do { - topLevel = try _XMLStackParser.parse(with: data, charDataToken: self.characterDataToken) + topLevel = try _XMLStackParser.parse(with: data, charDataToken: characterDataToken) } catch { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid XML.", underlyingError: error)) } diff --git a/Sources/XMLCoder/XMLStackParser.swift b/Sources/XMLCoder/XMLStackParser.swift index f43da42f..65652b05 100644 --- a/Sources/XMLCoder/XMLStackParser.swift +++ b/Sources/XMLCoder/XMLStackParser.swift @@ -155,28 +155,28 @@ internal class _XMLElement { fileprivate func flatten(with charDataKey: String? = nil) -> [String: Any] { var node: [String: Any] = attributes - - if children.isEmpty { - if let key = charDataKey { - node[key] = value - } - } - + + if children.isEmpty { + if let key = charDataKey { + node[key] = value + } + } + for childElement in children { for child in childElement.value { if let content = child.value { if let oldContent = node[childElement.key] as? Array { node[childElement.key] = oldContent + [content] - + } else if let oldContent = node[childElement.key] { node[childElement.key] = [oldContent, content] - + } else { node[childElement.key] = content } } else if !child.children.isEmpty || !child.attributes.isEmpty { let newValue = child.flatten() - + if let existingValue = node[childElement.key] { if var array = existingValue as? Array { array.append(newValue) @@ -316,29 +316,29 @@ internal class _XMLStackParser: NSObject, XMLParserDelegate { var currentElementName: String? var currentElementData = "" - /// Parses the XML data and returns a dictionary of the parsed output - /// - /// - Parameters: - /// - data: The Data to be parsed - /// - charDataToken: The token to key the charData in mixed content elements off of - /// - Returns: Dictionary of the parsed XML - /// - Throws: DecodingError if there's an issue parsing the XML - /// - Note: - /// When an XML Element has both attributes and child elements, the CharData within the element will be keyed with the `characterDataToken` - /// The following XML has both attribute data, child elements, and character data: - /// ``` - /// - /// some string value - /// valuevalue - /// - /// ``` - /// The "some string value" will be keyed on "CharData" - static func parse(with data: Data, charDataToken: String? = nil) throws -> [String: Any] { + /// Parses the XML data and returns a dictionary of the parsed output + /// + /// - Parameters: + /// - data: The Data to be parsed + /// - charDataToken: The token to key the charData in mixed content elements off of + /// - Returns: Dictionary of the parsed XML + /// - Throws: DecodingError if there's an issue parsing the XML + /// - Note: + /// When an XML Element has both attributes and child elements, the CharData within the element will be keyed with the `characterDataToken` + /// The following XML has both attribute data, child elements, and character data: + /// ``` + /// + /// some string value + /// valuevalue + /// + /// ``` + /// The "some string value" will be keyed on "CharData" + static func parse(with data: Data, charDataToken: String? = nil) throws -> [String: Any] { let parser = _XMLStackParser() do { if let node = try parser.parse(with: data) { - return node.flatten(with: charDataToken) + return node.flatten(with: charDataToken) } else { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data could not be parsed into XML.")) } diff --git a/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift b/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift index ad15c1f6..ea63f599 100644 --- a/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift +++ b/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift @@ -1,34 +1,32 @@ import Foundation -import XMLCoder import XCTest +import XMLCoder class CharacterDataDecodingTestCase: DecodingTestCase { - - override func setUp() { - super.setUp() - decoder.characterDataToken = "#text" - } - - func testItDecodesCharData() { - // given - struct Attribute: Decodable, Equatable { - enum CodingKeys: String, CodingKey { - case name = "name" - case value = "#text" - } - - let name: String - let value: String - } - let xml = """ -0 -""" - - // when - let attr: Attribute = try! decode(xml) - - // then - XCTAssertEqual(attr, Attribute(name: "Xpos", value: "0")) - } + override func setUp() { + super.setUp() + decoder.characterDataToken = "#text" + } + + func testItDecodesCharData() { + // given + struct Attribute: Decodable, Equatable { + enum CodingKeys: String, CodingKey { + case name + case value = "#text" + } + + let name: String + let value: String + } + let xml = """ + 0 + """ + + // when + let attr: Attribute = try! decode(xml) + + // then + XCTAssertEqual(attr, Attribute(name: "Xpos", value: "0")) + } } - diff --git a/Tests/XMLCoderTests/DecodingTestCase.swift b/Tests/XMLCoderTests/DecodingTestCase.swift index 626a280e..1c8c3fb4 100644 --- a/Tests/XMLCoderTests/DecodingTestCase.swift +++ b/Tests/XMLCoderTests/DecodingTestCase.swift @@ -1,24 +1,23 @@ import Foundation -import XMLCoder import XCTest +import XMLCoder class DecodingTestCase: XCTestCase { - var decoder: XMLDecoder! - - func decode(_ string: String) throws -> T where T: Decodable { - let data = string.data(using: .utf8)! - let result: T = try decoder.decode(T.self, from: data) - return result - } - - override func setUp() { - super.setUp() - decoder = XMLDecoder() - } - - override func tearDown() { - decoder = nil - super.tearDown() - } + var decoder: XMLDecoder! + + func decode(_ string: String) throws -> T where T: Decodable { + let data = string.data(using: .utf8)! + let result: T = try decoder.decode(T.self, from: data) + return result + } + + override func setUp() { + super.setUp() + decoder = XMLDecoder() + } + + override func tearDown() { + decoder = nil + super.tearDown() + } } - From f35bb7f961a2de7281a18d8bfabcdd73c3cb0fa6 Mon Sep 17 00:00:00 2001 From: Quico Moya Date: Sun, 2 Dec 2018 22:59:48 +0100 Subject: [PATCH 10/10] Add test for nested char data --- .../CharacterDataDecodingTestCase.swift | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift b/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift index ea63f599..f83081f3 100644 --- a/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift +++ b/Tests/XMLCoderTests/CharacterDataDecodingTestCase.swift @@ -29,4 +29,42 @@ class CharacterDataDecodingTestCase: DecodingTestCase { // then XCTAssertEqual(attr, Attribute(name: "Xpos", value: "0")) } + + func testItDecodesCharDataWhenNested() { + // given + struct Item: Decodable, Equatable { + enum CodingKeys: String, CodingKey { + case id = "ID" + case creator = "Creator" + case children = "attribute" + } + + let id: String + let creator: String + let children: [Attribute]? + } + + struct Attribute: Decodable, Equatable { + enum CodingKeys: String, CodingKey { + case name + case value = "#text" + } + + let name: String + let value: String? + } + + let xml = """ + + 0 + + """ + + // when + let result: Item = try! decode(xml) + + // then + let expected = Item(id: "1542637462", creator: "Francisco Moya", children: nil) + XCTAssertEqual(result, expected) + } }