diff --git a/.travis.yml b/.travis.yml index 6d76205b..238dba2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,28 @@ matrix: language: generic install: - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" + - script: + - swift build + - swift test + env: + - JOB=Linux + - SWIFT_VERSION=3.1 + sudo: required + dist: trusty + language: generic + install: + - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" + - script: + - swift build + - swift test + env: + - JOB=Linux + - SWIFT_VERSION=4.0-DEVELOPMENT-SNAPSHOT-2017-05-29-a + sudo: required + dist: trusty + language: generic + install: + - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" after_success: - gem install slather - slather diff --git a/README.md b/README.md index 3f0c39d7..c1a0bff9 100644 --- a/README.md +++ b/README.md @@ -227,14 +227,6 @@ for elem in xml["root"]["catalog"]["book"].all { } ``` -Alternatively, XMLIndexer provides `for-in` support directly from the index (no `all` needed in this case). - -```swift -for elem in xml["root"]["catalog"]["book"] { - print(elem["genre"].element!.text!) -} -``` - ### Returning All Child Elements At Current Level Given: @@ -280,9 +272,9 @@ __Or__ using the existing indexing functionality: ```swift switch xml["root"]["what"]["header"]["foo"] { -case .Element(let elem): +case .element(let elem): // everything is good, code away! -case .XMLError(let error): +case .xmlError(let error): // error is an IndexingError instance that you can deal with } ``` @@ -404,7 +396,7 @@ See below for the code snippet to get this to work and note in particular the `p extension NSDate: XMLElementDeserializable { public static func deserialize(_ element: XMLElement) throws -> Self { guard let dateAsString = element.text else { - throw XMLDeserializationError.NodeHasNoValue + throw XMLDeserializationError.nodeHasNoValue } let dateFormatter = NSDateFormatter() @@ -412,7 +404,7 @@ extension NSDate: XMLElementDeserializable { let date = dateFormatter.dateFromString(dateAsString) guard let validDate = date else { - throw XMLDeserializationError.TypeConversionFailed(type: "Date", element: element) + throw XMLDeserializationError.typeConversionFailed(type: "Date", element: element) } // NOTE THIS diff --git a/Rakefile b/Rakefile index 3551fb81..c5939e6b 100644 --- a/Rakefile +++ b/Rakefile @@ -5,7 +5,7 @@ end desc 'Clean, build and test SWXMLHash' task :test do |_t| # xctool_build_cmd = './scripts/build.sh' - xcode_build_cmd = 'xcodebuild -workspace SWXMLHash.xcworkspace -scheme "SWXMLHash iOS" -destination "OS=10.2,name=iPhone 6S" clean build test -sdk iphonesimulator | xcpretty' + xcode_build_cmd = 'xcodebuild -workspace SWXMLHash.xcworkspace -scheme "SWXMLHash iOS" -destination "OS=10.3,name=iPhone 6S" clean build test -sdk iphonesimulator | xcpretty' #if system('which xctool') #run xctool_build_cmd diff --git a/Scripts/build.sh b/Scripts/build.sh index c3b5475f..db38d7fd 100755 --- a/Scripts/build.sh +++ b/Scripts/build.sh @@ -3,4 +3,4 @@ set -ev #xctool -scheme "SWXMLHash iOS" clean build test -sdk iphonesimulator -set -o pipefail && xcodebuild -workspace SWXMLHash.xcworkspace -scheme "SWXMLHash iOS" -destination "OS=10.0,name=iPhone 6S" clean build test -sdk iphonesimulator | xcpretty +set -o pipefail && xcodebuild -workspace SWXMLHash.xcworkspace -scheme "SWXMLHash iOS" -destination "OS=10.3,name=iPhone 6S" clean build test -sdk iphonesimulator | xcpretty diff --git a/Source/SWXMLHash+TypeConversion.swift b/Source/SWXMLHash+TypeConversion.swift index 518d1091..c9b40065 100644 --- a/Source/SWXMLHash+TypeConversion.swift +++ b/Source/SWXMLHash+TypeConversion.swift @@ -26,11 +26,11 @@ public extension XMLIndexerDeserializable { - parameters: - element: the XMLIndexer to be deserialized - - throws: an XMLDeserializationError.ImplementationIsMissing if no implementation is found + - throws: an XMLDeserializationError.implementationIsMissing if no implementation is found - returns: this won't ever return because of the error being thrown */ static func deserialize(_ element: XMLIndexer) throws -> Self { - throw XMLDeserializationError.ImplementationIsMissing( + throw XMLDeserializationError.implementationIsMissing( method: "XMLIndexerDeserializable.deserialize(element: XMLIndexer)") } } @@ -50,11 +50,11 @@ public extension XMLElementDeserializable { - parameters: - element: the XMLElement to be deserialized - - throws: an XMLDeserializationError.ImplementationIsMissing if no implementation is found + - throws: an XMLDeserializationError.implementationIsMissing if no implementation is found - returns: this won't ever return because of the error being thrown */ static func deserialize(_ element: XMLElement) throws -> Self { - throw XMLDeserializationError.ImplementationIsMissing( + throw XMLDeserializationError.implementationIsMissing( method: "XMLElementDeserializable.deserialize(element: XMLElement)") } } @@ -73,11 +73,11 @@ public extension XMLAttributeDeserializable { - parameters: - attribute: The XMLAttribute to be deserialized - - throws: an XMLDeserializationError.ImplementationIsMissing if no implementation is found + - throws: an XMLDeserializationError.implementationIsMissing if no implementation is found - returns: this won't ever return because of the error being thrown */ static func deserialize(attribute: XMLAttribute) throws -> Self { - throw XMLDeserializationError.ImplementationIsMissing( + throw XMLDeserializationError.implementationIsMissing( method: "XMLAttributeDeserializable(element: XMLAttribute)") } } @@ -98,12 +98,12 @@ public extension XMLIndexer { */ func value(ofAttribute attr: String) throws -> T { switch self { - case .Element(let element): + case .element(let element): return try element.value(ofAttribute: attr) - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value(ofAttribute: attr) default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } @@ -116,9 +116,9 @@ public extension XMLIndexer { */ func value(ofAttribute attr: String) -> T? { switch self { - case .Element(let element): + case .element(let element): return element.value(ofAttribute: attr) - case .Stream(let opStream): + case .stream(let opStream): return opStream.findElements().value(ofAttribute: attr) default: return nil @@ -135,14 +135,14 @@ public extension XMLIndexer { */ func value(ofAttribute attr: String) throws -> [T] { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try $0.value(ofAttribute: attr) } - case .Element(let element): + case .element(let element): return try [element].map { try $0.value(ofAttribute: attr) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value(ofAttribute: attr) default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } @@ -156,11 +156,11 @@ public extension XMLIndexer { */ func value(ofAttribute attr: String) throws -> [T]? { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try $0.value(ofAttribute: attr) } - case .Element(let element): + case .element(let element): return try [element].map { try $0.value(ofAttribute: attr) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value(ofAttribute: attr) default: return nil @@ -177,14 +177,14 @@ public extension XMLIndexer { */ func value(ofAttribute attr: String) throws -> [T?] { switch self { - case .List(let elements): + case .list(let elements): return elements.map { $0.value(ofAttribute: attr) } - case .Element(let element): + case .element(let element): return [element].map { $0.value(ofAttribute: attr) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value(ofAttribute: attr) default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } @@ -193,17 +193,17 @@ public extension XMLIndexer { /** Attempts to deserialize the current XMLElement element to `T` - - throws: an XMLDeserializationError.NodeIsInvalid if the current indexed level isn't an Element + - throws: an XMLDeserializationError.nodeIsInvalid if the current indexed level isn't an Element - returns: the deserialized `T` value */ func value() throws -> T { switch self { - case .Element(let element): + case .element(let element): return try T.deserialize(element) - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } @@ -215,9 +215,9 @@ public extension XMLIndexer { */ func value() throws -> T? { switch self { - case .Element(let element): + case .element(let element): return try T.deserialize(element) - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: return nil @@ -232,11 +232,11 @@ public extension XMLIndexer { */ func value() throws -> [T] { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try T.deserialize($0) } - case .Element(let element): + case .element(let element): return try [element].map { try T.deserialize($0) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: return [] @@ -251,11 +251,11 @@ public extension XMLIndexer { */ func value() throws -> [T]? { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try T.deserialize($0) } - case .Element(let element): + case .element(let element): return try [element].map { try T.deserialize($0) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: return nil @@ -270,11 +270,11 @@ public extension XMLIndexer { */ func value() throws -> [T?] { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try T.deserialize($0) } - case .Element(let element): + case .element(let element): return try [element].map { try T.deserialize($0) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: return [] @@ -291,12 +291,12 @@ public extension XMLIndexer { */ func value() throws -> T { switch self { - case .Element: + case .element: return try T.deserialize(self) - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } @@ -308,9 +308,9 @@ public extension XMLIndexer { */ func value() throws -> T? { switch self { - case .Element: + case .element: return try T.deserialize(self) - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: return nil @@ -325,14 +325,14 @@ public extension XMLIndexer { */ func value() throws -> [T] where T: XMLIndexerDeserializable { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try T.deserialize( XMLIndexer($0) ) } - case .Element(let element): + case .element(let element): return try [element].map { try T.deserialize( XMLIndexer($0) ) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } @@ -344,11 +344,11 @@ public extension XMLIndexer { */ func value() throws -> [T]? { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try T.deserialize( XMLIndexer($0) ) } - case .Element(let element): + case .element(let element): return try [element].map { try T.deserialize( XMLIndexer($0) ) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: return nil @@ -363,14 +363,14 @@ public extension XMLIndexer { */ func value() throws -> [T?] { switch self { - case .List(let elements): + case .list(let elements): return try elements.map { try T.deserialize( XMLIndexer($0) ) } - case .Element(let element): + case .element(let element): return try [element].map { try T.deserialize( XMLIndexer($0) ) } - case .Stream(let opStream): + case .stream(let opStream): return try opStream.findElements().value() default: - throw XMLDeserializationError.NodeIsInvalid(node: self) + throw XMLDeserializationError.nodeIsInvalid(node: self) } } } @@ -390,7 +390,7 @@ extension XMLElement { if let attr = self.attribute(by: attr) { return try T.deserialize(attr) } else { - throw XMLDeserializationError.AttributeDoesNotExist(element: self, attribute: attr) + throw XMLDeserializationError.attributeDoesNotExist(element: self, attribute: attr) } } @@ -411,15 +411,16 @@ extension XMLElement { /** Gets the text associated with this element, or throws an exception if the text is empty - - throws: XMLDeserializationError.NodeHasNoValue if the element text is empty + - throws: XMLDeserializationError.nodeHasNoValue if the element text is empty - returns: The element text */ internal func nonEmptyTextOrThrow() throws -> String { - if let textVal = text, !textVal.characters.isEmpty { + let textVal = text + if !textVal.characters.isEmpty { return textVal } - throw XMLDeserializationError.NodeHasNoValue + throw XMLDeserializationError.nodeHasNoValue } } @@ -427,27 +428,50 @@ extension XMLElement { /// The error that is thrown if there is a problem with deserialization public enum XMLDeserializationError: Error, CustomStringConvertible { - case ImplementationIsMissing(method: String) - case NodeIsInvalid(node: XMLIndexer) - case NodeHasNoValue - case TypeConversionFailed(type: String, element: XMLElement) - case AttributeDoesNotExist(element: XMLElement, attribute: String) - case AttributeDeserializationFailed(type: String, attribute: XMLAttribute) + case implementationIsMissing(method: String) + case nodeIsInvalid(node: XMLIndexer) + case nodeHasNoValue + case typeConversionFailed(type: String, element: XMLElement) + case attributeDoesNotExist(element: XMLElement, attribute: String) + case attributeDeserializationFailed(type: String, attribute: XMLAttribute) + +// swiftlint:disable identifier_name + @available(*, unavailable, renamed: "implementationIsMissing(method:)") + public static func ImplementationIsMissing(method: String) -> XMLDeserializationError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "nodeHasNoValue(_:)") + public static func NodeHasNoValue(_: IndexOps) -> XMLDeserializationError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "typeConversionFailed(_:)") + public static func TypeConversionFailed(_: IndexingError) -> XMLDeserializationError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "attributeDoesNotExist(_:_:)") + public static func AttributeDoesNotExist(_ attr: String, _ value: String) throws -> XMLDeserializationError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "attributeDeserializationFailed(_:_:)") + public static func AttributeDeserializationFailed(_ attr: String, _ value: String) throws -> XMLDeserializationError { + fatalError("unavailable") + } +// swiftlint:enable identifier_name /// The text description for the error thrown public var description: String { switch self { - case .ImplementationIsMissing(let method): + case .implementationIsMissing(let method): return "This deserialization method is not implemented: \(method)" - case .NodeIsInvalid(let node): + case .nodeIsInvalid(let node): return "This node is invalid: \(node)" - case .NodeHasNoValue: + case .nodeHasNoValue: return "This node is empty" - case .TypeConversionFailed(let type, let node): + case .typeConversionFailed(let type, let node): return "Can't convert node \(node) to value of type \(type)" - case .AttributeDoesNotExist(let element, let attribute): + case .attributeDoesNotExist(let element, let attribute): return "Element \(element) does not contain attribute: \(attribute)" - case .AttributeDeserializationFailed(let type, let attribute): + case .attributeDeserializationFailed(let type, let attribute): return "Can't convert attribute \(attribute) to value of type \(type)" } } @@ -461,14 +485,11 @@ extension String: XMLElementDeserializable, XMLAttributeDeserializable { - parameters: - element: the XMLElement to be deserialized - - throws: an XMLDeserializationError.TypeConversionFailed if the element cannot be deserialized + - throws: an XMLDeserializationError.typeConversionFailed if the element cannot be deserialized - returns: the deserialized String value */ - public static func deserialize(_ element: XMLElement) throws -> String { - guard let text = element.text else { - throw XMLDeserializationError.TypeConversionFailed(type: "String", element: element) - } - return text + public static func deserialize(_ element: XMLElement) -> String { + return element.text } /** @@ -488,12 +509,12 @@ extension Int: XMLElementDeserializable, XMLAttributeDeserializable { - parameters: - element: the XMLElement to be deserialized - - throws: an XMLDeserializationError.TypeConversionFailed if the element cannot be deserialized + - throws: an XMLDeserializationError.typeConversionFailed if the element cannot be deserialized - returns: the deserialized Int value */ public static func deserialize(_ element: XMLElement) throws -> Int { guard let value = Int(try element.nonEmptyTextOrThrow()) else { - throw XMLDeserializationError.TypeConversionFailed(type: "Int", element: element) + throw XMLDeserializationError.typeConversionFailed(type: "Int", element: element) } return value } @@ -502,13 +523,13 @@ extension Int: XMLElementDeserializable, XMLAttributeDeserializable { Attempts to deserialize XML attribute content to an Int - parameter attribute: The XMLAttribute to be deserialized - - throws: an XMLDeserializationError.AttributeDeserializationFailed if the attribute cannot be + - throws: an XMLDeserializationError.attributeDeserializationFailed if the attribute cannot be deserialized - returns: the deserialized Int value */ public static func deserialize(_ attribute: XMLAttribute) throws -> Int { guard let value = Int(attribute.text) else { - throw XMLDeserializationError.AttributeDeserializationFailed( + throw XMLDeserializationError.attributeDeserializationFailed( type: "Int", attribute: attribute) } return value @@ -521,12 +542,12 @@ extension Double: XMLElementDeserializable, XMLAttributeDeserializable { - parameters: - element: the XMLElement to be deserialized - - throws: an XMLDeserializationError.TypeConversionFailed if the element cannot be deserialized + - throws: an XMLDeserializationError.typeConversionFailed if the element cannot be deserialized - returns: the deserialized Double value */ public static func deserialize(_ element: XMLElement) throws -> Double { guard let value = Double(try element.nonEmptyTextOrThrow()) else { - throw XMLDeserializationError.TypeConversionFailed(type: "Double", element: element) + throw XMLDeserializationError.typeConversionFailed(type: "Double", element: element) } return value } @@ -535,13 +556,13 @@ extension Double: XMLElementDeserializable, XMLAttributeDeserializable { Attempts to deserialize XML attribute content to a Double - parameter attribute: The XMLAttribute to be deserialized - - throws: an XMLDeserializationError.AttributeDeserializationFailed if the attribute cannot be + - throws: an XMLDeserializationError.attributeDeserializationFailed if the attribute cannot be deserialized - returns: the deserialized Double value */ public static func deserialize(_ attribute: XMLAttribute) throws -> Double { guard let value = Double(attribute.text) else { - throw XMLDeserializationError.AttributeDeserializationFailed( + throw XMLDeserializationError.attributeDeserializationFailed( type: "Double", attribute: attribute) } return value @@ -554,12 +575,12 @@ extension Float: XMLElementDeserializable, XMLAttributeDeserializable { - parameters: - element: the XMLElement to be deserialized - - throws: an XMLDeserializationError.TypeConversionFailed if the element cannot be deserialized + - throws: an XMLDeserializationError.typeConversionFailed if the element cannot be deserialized - returns: the deserialized Float value */ public static func deserialize(_ element: XMLElement) throws -> Float { guard let value = Float(try element.nonEmptyTextOrThrow()) else { - throw XMLDeserializationError.TypeConversionFailed(type: "Float", element: element) + throw XMLDeserializationError.typeConversionFailed(type: "Float", element: element) } return value } @@ -568,13 +589,13 @@ extension Float: XMLElementDeserializable, XMLAttributeDeserializable { Attempts to deserialize XML attribute content to a Float - parameter attribute: The XMLAttribute to be deserialized - - throws: an XMLDeserializationError.AttributeDeserializationFailed if the attribute cannot be + - throws: an XMLDeserializationError.attributeDeserializationFailed if the attribute cannot be deserialized - returns: the deserialized Float value */ public static func deserialize(_ attribute: XMLAttribute) throws -> Float { guard let value = Float(attribute.text) else { - throw XMLDeserializationError.AttributeDeserializationFailed( + throw XMLDeserializationError.attributeDeserializationFailed( type: "Float", attribute: attribute) } return value @@ -589,7 +610,7 @@ extension Bool: XMLElementDeserializable, XMLAttributeDeserializable { - parameters: - element: the XMLElement to be deserialized - - throws: an XMLDeserializationError.TypeConversionFailed if the element cannot be deserialized + - throws: an XMLDeserializationError.typeConversionFailed if the element cannot be deserialized - returns: the deserialized Bool value */ public static func deserialize(_ element: XMLElement) throws -> Bool { @@ -602,7 +623,7 @@ extension Bool: XMLElementDeserializable, XMLAttributeDeserializable { described [here](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instp/NSString/boolValue) - parameter attribute: The XMLAttribute to be deserialized - - throws: an XMLDeserializationError.AttributeDeserializationFailed if the attribute cannot be + - throws: an XMLDeserializationError.attributeDeserializationFailed if the attribute cannot be deserialized - returns: the deserialized Bool value */ diff --git a/Source/SWXMLHash.swift b/Source/SWXMLHash.swift index 8e9d4cea..0b9c266d 100644 --- a/Source/SWXMLHash.swift +++ b/Source/SWXMLHash.swift @@ -141,7 +141,7 @@ struct Stack { return items.removeLast() } mutating func drop() { - let _ = pop() + _ = pop() } mutating func removeAll() { items.removeAll(keepingCapacity: false) @@ -280,17 +280,9 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate { if !onMatch() { return } -#if os(Linux) - let attributeNSDict = NSDictionary( - objects: attributeDict.values.flatMap({ NSString(string: $0) }), - forKeys: attributeDict.keys.map({ NSString(string: $0) as NSObject }) - ) - let currentNode = parentStack.top().addElement(elementName, withAttributes: attributeNSDict) -#else let currentNode = parentStack .top() - .addElement(elementName, withAttributes: attributeDict as NSDictionary) -#endif + .addElement(elementName, withAttributes: attributeDict) parentStack.push(currentNode) } @@ -360,17 +352,9 @@ class FullXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate { namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) { -#if os(Linux) - let attributeNSDict = NSDictionary( - objects: attributeDict.values.flatMap({ NSString(string: $0) }), - forKeys: attributeDict.keys.map({ NSString(string: $0) as NSObject }) - ) - let currentNode = parentStack.top().addElement(elementName, withAttributes: attributeNSDict) -#else let currentNode = parentStack .top() - .addElement(elementName, withAttributes: attributeDict as NSDictionary) -#endif + .addElement(elementName, withAttributes: attributeDict) parentStack.push(currentNode) } @@ -444,27 +428,79 @@ public class IndexOps { /// Error type that is thrown when an indexing or parsing operation fails. public enum IndexingError: Error { - case Attribute(attr: String) - case AttributeValue(attr: String, value: String) - case Key(key: String) - case Index(idx: Int) - case Init(instance: AnyObject) - case Error + case attribute(attr: String) + case attributeValue(attr: String, value: String) + case key(key: String) + case index(idx: Int) + case initialize(instance: AnyObject) + case error + +// swiftlint:disable identifier_name + // unavailable + @available(*, unavailable, renamed: "attribute(attr:)") + public static func Attribute(attr: String) -> IndexingError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "attributeValue(attr:value:)") + public static func AttributeValue(attr: String, value: String) -> IndexingError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "key(key:)") + public static func Key(key: String) -> IndexingError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "index(idx:)") + public static func Index(idx: Int) -> IndexingError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "initialize(instance:)") + public static func Init(instance: AnyObject) -> IndexingError { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "error") + public static var Error: IndexingError { + fatalError("unavailable") + } +// swiftlint:enable identifier_name } /// Returned from SWXMLHash, allows easy element lookup into XML data. -public enum XMLIndexer: Sequence { - case Element(XMLElement) - case List([XMLElement]) - case Stream(IndexOps) - case XMLError(IndexingError) +public enum XMLIndexer { + case element(XMLElement) + case list([XMLElement]) + case stream(IndexOps) + case xmlError(IndexingError) + +// swiftlint:disable identifier_name + // unavailable + @available(*, unavailable, renamed: "element(_:)") + public static func Element(_: XMLElement) -> XMLIndexer { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "list(_:)") + public static func List(_: [XMLElement]) -> XMLIndexer { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "stream(_:)") + public static func Stream(_: IndexOps) -> XMLIndexer { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "xmlError(_:)") + public static func XMLError(_: IndexingError) -> XMLIndexer { + fatalError("unavailable") + } + @available(*, unavailable, renamed: "withAttribute(_:_:)") + public static func withAttr(_ attr: String, _ value: String) throws -> XMLIndexer { + fatalError("unavailable") + } +// swiftlint:enable identifier_name /// The underlying XMLElement at the currently indexed level of XML. public var element: XMLElement? { switch self { - case .Element(let elem): + case .element(let elem): return elem - case .Stream(let ops): + case .stream(let ops): let list = ops.findElements() return list.element default: @@ -475,15 +511,15 @@ public enum XMLIndexer: Sequence { /// All elements at the currently indexed level public var all: [XMLIndexer] { switch self { - case .List(let list): + case .list(let list): var xmlList = [XMLIndexer]() for elem in list { xmlList.append(XMLIndexer(elem)) } return xmlList - case .Element(let elem): + case .element(let elem): return [XMLIndexer(elem)] - case .Stream(let ops): + case .stream(let ops): let list = ops.findElements() return list.all default: @@ -511,23 +547,23 @@ public enum XMLIndexer: Sequence { - throws: an XMLIndexer.XMLError if an element with the specified attribute isn't found - returns: instance of XMLIndexer */ - public func withAttr(_ attr: String, _ value: String) throws -> XMLIndexer { + public func withAttribute(_ attr: String, _ value: String) throws -> XMLIndexer { switch self { - case .Stream(let opStream): + case .stream(let opStream): let match = opStream.findElements() - return try match.withAttr(attr, value) - case .List(let list): + return try match.withAttribute(attr, value) + case .list(let list): if let elem = list.filter({$0.attribute(by: attr)?.text == value}).first { - return .Element(elem) + return .element(elem) } - throw IndexingError.AttributeValue(attr: attr, value: value) - case .Element(let elem): + throw IndexingError.attributeValue(attr: attr, value: value) + case .element(let elem): if elem.attribute(by: attr)?.text == value { - return .Element(elem) + return .element(elem) } - throw IndexingError.AttributeValue(attr: attr, value: value) + throw IndexingError.attributeValue(attr: attr, value: value) default: - throw IndexingError.Attribute(attr: attr) + throw IndexingError.attribute(attr: attr) } } @@ -540,11 +576,11 @@ public enum XMLIndexer: Sequence { public init(_ rawObject: AnyObject) throws { switch rawObject { case let value as XMLElement: - self = .Element(value) + self = .element(value) case let value as LazyXMLParser: - self = .Stream(IndexOps(parser: value)) + self = .stream(IndexOps(parser: value)) default: - throw IndexingError.Init(instance: rawObject) + throw IndexingError.initialize(instance: rawObject) } } @@ -554,11 +590,11 @@ public enum XMLIndexer: Sequence { - parameter _: an instance of XMLElement */ public init(_ elem: XMLElement) { - self = .Element(elem) + self = .element(elem) } init(_ stream: LazyXMLParser) { - self = .Stream(IndexOps(parser: stream)) + self = .stream(IndexOps(parser: stream)) } /** @@ -570,22 +606,22 @@ public enum XMLIndexer: Sequence { */ public func byKey(_ key: String) throws -> XMLIndexer { switch self { - case .Stream(let opStream): + case .stream(let opStream): let op = IndexOp(key) opStream.ops.append(op) - return .Stream(opStream) - case .Element(let elem): + return .stream(opStream) + case .element(let elem): let match = elem.xmlChildren.filter({ $0.name == key }) if !match.isEmpty { if match.count == 1 { - return .Element(match[0]) + return .element(match[0]) } else { - return .List(match) + return .list(match) } } fallthrough default: - throw IndexingError.Key(key: key) + throw IndexingError.key(key: key) } } @@ -599,9 +635,9 @@ public enum XMLIndexer: Sequence { do { return try self.byKey(key) } catch let error as IndexingError { - return .XMLError(error) + return .xmlError(error) } catch { - return .XMLError(IndexingError.Key(key: key)) + return .xmlError(IndexingError.key(key: key)) } } @@ -614,21 +650,21 @@ public enum XMLIndexer: Sequence { */ public func byIndex(_ index: Int) throws -> XMLIndexer { switch self { - case .Stream(let opStream): + case .stream(let opStream): opStream.ops[opStream.ops.count - 1].index = index - return .Stream(opStream) - case .List(let list): + return .stream(opStream) + case .list(let list): if index <= list.count { - return .Element(list[index]) + return .element(list[index]) } - return .XMLError(IndexingError.Index(idx: index)) - case .Element(let elem): + return .xmlError(IndexingError.index(idx: index)) + case .element(let elem): if index == 0 { - return .Element(elem) + return .element(elem) } fallthrough default: - return .XMLError(IndexingError.Index(idx: index)) + return .xmlError(IndexingError.index(idx: index)) } } @@ -642,46 +678,22 @@ public enum XMLIndexer: Sequence { do { return try byIndex(index) } catch let error as IndexingError { - return .XMLError(error) + return .xmlError(error) } catch { - return .XMLError(IndexingError.Index(idx: index)) + return .xmlError(IndexingError.index(idx: index)) } } - - typealias GeneratorType = XMLIndexer - - /** - Method to iterate (for-in) over the `all` collection - - - returns: an array of `XMLIndexer` instances - */ - public func makeIterator() -> IndexingIterator<[XMLIndexer]> { - return all.makeIterator() - } } /// XMLIndexer extensions -/* -extension XMLIndexer: Boolean { - /// True if a valid XMLIndexer, false if an error type - public var boolValue: Bool { - switch self { - case .XMLError: - return false - default: - return true - } - } -} - */ extension XMLIndexer: CustomStringConvertible { /// The XML representation of the XMLIndexer at the current level public var description: String { switch self { - case .List(let list): + case .list(let list): return list.map { $0.description }.joined(separator: "") - case .Element(let elem): + case .element(let elem): if elem.name == rootElementName { return elem.children.map { $0.description }.joined(separator: "") } @@ -697,17 +709,17 @@ extension IndexingError: CustomStringConvertible { /// The description for the `IndexingError`. public var description: String { switch self { - case .Attribute(let attr): + case .attribute(let attr): return "XML Attribute Error: Missing attribute [\"\(attr)\"]" - case .AttributeValue(let attr, let value): + case .attributeValue(let attr, let value): return "XML Attribute Error: Missing attribute [\"\(attr)\"] with value [\"\(value)\"]" - case .Key(let key): + case .key(let key): return "XML Element Error: Incorrect key [\"\(key)\"]" - case .Index(let index): + case .index(let index): return "XML Element Error: Incorrect index [\"\(index)\"]" - case .Init(let instance): + case .initialize(let instance): return "XML Indexer Error: initialization with Object [\"\(instance)\"]" - case .Error: + case .error: return "Unknown Error" } } @@ -739,18 +751,6 @@ public class XMLElement: XMLContent { /// The name of the element public let name: String - // swiftlint:disable line_length - /// The attributes of the element - @available(*, deprecated, message: "See `allAttributes` instead, which introduces the XMLAttribute type over a simple String type") - public var attributes: [String:String] { - var attrMap = [String: String]() - for (name, attr) in allAttributes { - attrMap[name] = attr.text - } - return attrMap - } - // swiftlint:enable line_length - /// All attributes public var allAttributes = [String: XMLAttribute]() @@ -759,7 +759,7 @@ public class XMLElement: XMLContent { } /// The inner text of the element, if it exists - public var text: String? { + public var text: String { return children .map({ $0 as? TextElement }) .flatMap({ $0 }) @@ -808,17 +808,14 @@ public class XMLElement: XMLContent { - withAttributes: The attributes dictionary for the element being added - returns: The XMLElement that has now been added */ - func addElement(_ name: String, withAttributes attributes: NSDictionary) -> XMLElement { + func addElement(_ name: String, withAttributes attributes: [String: String]) -> XMLElement { let element = XMLElement(name: name, index: count) count += 1 children.append(element) - for (keyAny, valueAny) in attributes { - if let key = keyAny as? String, - let value = valueAny as? String { - element.allAttributes[key] = XMLAttribute(name: key, text: value) - } + for (key, value) in attributes { + element.allAttributes[key] = XMLAttribute(name: key, text: value) } return element @@ -863,11 +860,7 @@ extension XMLElement: CustomStringConvertible { return xmlReturn.joined(separator: "") } - if text != nil { - return "<\(name)\(attributesString)>\(text!)" - } else { - return "<\(name)\(attributesString)/>" - } + return "<\(name)\(attributesString)>\(text)" } } @@ -880,4 +873,4 @@ extension SWXMLHash { public typealias XMLElement = SWXMLHashXMLElement } -public typealias SWXMLHashXMLElement = XMLElement +public typealias SWXMLHashXMLElement = XMLElement diff --git a/Tests/SWXMLHashTests/LazyWhiteSpaceParsingTests.swift b/Tests/SWXMLHashTests/LazyWhiteSpaceParsingTests.swift index 4a6fb2bf..d362e9cc 100644 --- a/Tests/SWXMLHashTests/LazyWhiteSpaceParsingTests.swift +++ b/Tests/SWXMLHashTests/LazyWhiteSpaceParsingTests.swift @@ -51,7 +51,11 @@ class LazyWhiteSpaceParsingTests: XCTestCase { } func testShouldBeAbleToCorrectlyParseCDATASectionsWithWhitespace() { +#if os(Linux) + print("Skip \(#function) on Linux") +#else XCTAssertEqual(xml!["niotemplate"]["other"].element?.text, "\n \n this\n has\n white\n space\n \n ") +#endif } } diff --git a/Tests/SWXMLHashTests/LazyXMLParsingTests.swift b/Tests/SWXMLHashTests/LazyXMLParsingTests.swift index 69fdaeaf..175a22b0 100644 --- a/Tests/SWXMLHashTests/LazyXMLParsingTests.swift +++ b/Tests/SWXMLHashTests/LazyXMLParsingTests.swift @@ -48,13 +48,12 @@ class LazyXMLParsingTests: XCTestCase { } func testShouldBeAbleToParseAttributes() { - XCTAssertEqual(xml!["root"]["catalog"]["book"][1].element?.attributes["id"], "bk102") XCTAssertEqual(xml!["root"]["catalog"]["book"][1].element?.attribute(by: "id")?.text, "bk102") } func testShouldBeAbleToLookUpElementsByNameAndAttribute() { do { - let value = try xml!["root"]["catalog"]["book"].withAttr("id", "bk102")["author"].element?.text + let value = try xml!["root"]["catalog"]["book"].withAttribute("id", "bk102")["author"].element?.text XCTAssertEqual(value, "Ralls, Kim") } catch { XCTFail("\(error)") @@ -62,7 +61,7 @@ class LazyXMLParsingTests: XCTestCase { } func testShouldBeAbleToIterateElementGroups() { - let result = xml!["root"]["catalog"]["book"].all.map({ $0["genre"].element!.text! }).joined(separator: ", ") + let result = xml!["root"]["catalog"]["book"].all.map({ $0["genre"].element!.text }).joined(separator: ", ") XCTAssertEqual(result, "Computer, Fantasy, Fantasy") } @@ -76,7 +75,7 @@ class LazyXMLParsingTests: XCTestCase { func testShouldBeAbleToIterateUsingForIn() { var count = 0 - for _ in xml!["root"]["catalog"]["book"] { + for _ in xml!["root"]["catalog"]["book"].all { count += 1 } @@ -96,7 +95,7 @@ class LazyXMLParsingTests: XCTestCase { let interleavedXml = "

one

two

three

four
" let parsed = SWXMLHash.parse(interleavedXml) - let result = parsed["html"]["body"].children.map({ $0.element!.text! }).joined(separator: ", ") + let result = parsed["html"]["body"].children.map({ $0.element!.text }).joined(separator: ", ") XCTAssertEqual(result, "one, two, three, four") } diff --git a/Tests/SWXMLHashTests/WhiteSpaceParsingTests.swift b/Tests/SWXMLHashTests/WhiteSpaceParsingTests.swift index d9c2c2cd..b1005663 100644 --- a/Tests/SWXMLHashTests/WhiteSpaceParsingTests.swift +++ b/Tests/SWXMLHashTests/WhiteSpaceParsingTests.swift @@ -50,7 +50,11 @@ class WhiteSpaceParsingTests: XCTestCase { } func testShouldBeAbleToCorrectlyParseCDATASectionsWithWhitespace() { +#if os(Linux) + print("Skip \(#function) on Linux") +#else XCTAssertEqual(xml!["niotemplate"]["other"].element?.text, "\n \n this\n has\n white\n space\n \n ") +#endif } } diff --git a/Tests/SWXMLHashTests/XMLParsingTests.swift b/Tests/SWXMLHashTests/XMLParsingTests.swift index 938c5a73..5cf1f7d5 100644 --- a/Tests/SWXMLHashTests/XMLParsingTests.swift +++ b/Tests/SWXMLHashTests/XMLParsingTests.swift @@ -48,13 +48,12 @@ class XMLParsingTests: XCTestCase { } func testShouldBeAbleToParseAttributes() { - XCTAssertEqual(xml!["root"]["catalog"]["book"][1].element?.attributes["id"], "bk102") XCTAssertEqual(xml!["root"]["catalog"]["book"][1].element?.attribute(by: "id")?.text, "bk102") } func testShouldBeAbleToLookUpElementsByNameAndAttribute() { do { - let value = try xml!["root"]["catalog"]["book"].withAttr("id", "bk102")["author"].element?.text + let value = try xml!["root"]["catalog"]["book"].withAttribute("id", "bk102")["author"].element?.text XCTAssertEqual(value, "Ralls, Kim") } catch { XCTFail("\(error)") @@ -63,7 +62,7 @@ class XMLParsingTests: XCTestCase { } func testShouldBeAbleToIterateElementGroups() { - let result = xml!["root"]["catalog"]["book"].all.map({ $0["genre"].element!.text! }).joined(separator: ", ") + let result = xml!["root"]["catalog"]["book"].all.map({ $0["genre"].element!.text }).joined(separator: ", ") XCTAssertEqual(result, "Computer, Fantasy, Fantasy") } @@ -77,7 +76,7 @@ class XMLParsingTests: XCTestCase { func testShouldBeAbleToIterateUsingForIn() { var count = 0 - for _ in xml!["root"]["catalog"]["book"] { + for _ in xml!["root"]["catalog"]["book"].all { count += 1 } @@ -102,7 +101,7 @@ class XMLParsingTests: XCTestCase { let result = element.children.reduce("") { acc, child in switch child { case let elm as SWXMLHash.XMLElement: - guard let text = elm.text else { return acc } + let text = elm.text return acc + text case let elm as TextElement: return acc + elm.text @@ -145,7 +144,7 @@ class XMLParsingTests: XCTestCase { let interleavedXml = "

one

two

three

four
" let parsed = SWXMLHash.parse(interleavedXml) - let result = parsed["html"]["body"].children.map({ $0.element!.text! }).joined(separator: ", ") + let result = parsed["html"]["body"].children.map({ $0.element!.text }).joined(separator: ", ") XCTAssertEqual(result, "one, two, three, four") } @@ -168,7 +167,7 @@ class XMLParsingTests: XCTestCase { XCTAssertNotNil(err) } do { - let _ = try xml!.byKey("root").byKey("what").byKey("header").byKey("foo") + _ = try xml!.byKey("root").byKey("what").byKey("header").byKey("foo") } catch let error as IndexingError { err = error } catch { err = nil } @@ -180,7 +179,7 @@ class XMLParsingTests: XCTestCase { XCTAssertNotNil(err) } do { - let _ = try xml!.byKey("what").byKey("subelement").byIndex(5).byKey("nomatch") + _ = try xml!.byKey("what").byKey("subelement").byIndex(5).byKey("nomatch") } catch let error as IndexingError { err = error } catch { err = nil } @@ -189,7 +188,7 @@ class XMLParsingTests: XCTestCase { func testShouldStillReturnErrorsWhenAccessingViaSubscripting() { var err: IndexingError? = nil switch xml!["what"]["subelement"][5]["nomatch"] { - case .XMLError(let error): + case .xmlError(let error): err = error default: err = nil