From 1be2e2fc3513b38896cb3e3961b842fc734dc88c Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Tue, 26 Apr 2016 12:13:36 -0700 Subject: [PATCH 01/21] Preparing v1.3 - Unit tests implementation started - Podspec updated --- CheatyXML.podspec | 4 +- CheatyXML.xcodeproj/project.pbxproj | 4 ++ .../xcshareddata/CheatyXML.xccheckout | 41 +++++++++++++++++++ .../xcdebugger/Breakpoints_v2.xcbkptlist | 18 -------- CheatyXMLTests/CheatyXMLTests.swift | 40 +++++++++++++----- CheatyXMLTests/Test.xml | 14 +++++++ 6 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 CheatyXML.xcodeproj/project.xcworkspace/xcshareddata/CheatyXML.xccheckout create mode 100644 CheatyXMLTests/Test.xml diff --git a/CheatyXML.podspec b/CheatyXML.podspec index deca0f7..d48907c 100644 --- a/CheatyXML.podspec +++ b/CheatyXML.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| # s.name = "CheatyXML" - s.version = "1.2" + s.version = "1.3" s.summary = "CheatyXML" s.description = <<-DESC @@ -66,7 +66,7 @@ Pod::Spec.new do |s| # Supports git, hg, bzr, svn and HTTP. # - s.source = { :git => "https://github.com/lobodart/CheatyXML.git", :tag => "v1.2" } + s.source = { :git => "https://github.com/lobodart/CheatyXML.git", :tag => "v1.3" } # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # diff --git a/CheatyXML.xcodeproj/project.pbxproj b/CheatyXML.xcodeproj/project.pbxproj index 0787e66..dff376a 100644 --- a/CheatyXML.xcodeproj/project.pbxproj +++ b/CheatyXML.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 486D48871AB4A19D004F6258 /* CheatyXML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 486D487B1AB4A19D004F6258 /* CheatyXML.framework */; }; 486D488E1AB4A19D004F6258 /* CheatyXMLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */; }; 486D48981AB4A1AF004F6258 /* CheatyXML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D48971AB4A1AF004F6258 /* CheatyXML.swift */; }; + 48CD10F61CCFEAD800A8CFAD /* Test.xml in Resources */ = {isa = PBXBuildFile; fileRef = 48CD10F51CCFEAD800A8CFAD /* Test.xml */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -31,6 +32,7 @@ 486D488C1AB4A19D004F6258 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatyXMLTests.swift; sourceTree = ""; }; 486D48971AB4A1AF004F6258 /* CheatyXML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheatyXML.swift; sourceTree = ""; }; + 48CD10F51CCFEAD800A8CFAD /* Test.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Test.xml; sourceTree = ""; }; 48F5B5041AB4ADAB00E68B10 /* Test.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Test.playground; sourceTree = ""; }; /* End PBXFileReference section */ @@ -94,6 +96,7 @@ isa = PBXGroup; children = ( 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */, + 48CD10F51CCFEAD800A8CFAD /* Test.xml */, 486D488B1AB4A19D004F6258 /* Supporting Files */, ); path = CheatyXMLTests; @@ -206,6 +209,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 48CD10F61CCFEAD800A8CFAD /* Test.xml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/CheatyXML.xcodeproj/project.xcworkspace/xcshareddata/CheatyXML.xccheckout b/CheatyXML.xcodeproj/project.xcworkspace/xcshareddata/CheatyXML.xccheckout new file mode 100644 index 0000000..13b209b --- /dev/null +++ b/CheatyXML.xcodeproj/project.xcworkspace/xcshareddata/CheatyXML.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 2F50476B-C33B-4B0E-8BCA-763A4B422BA9 + IDESourceControlProjectName + project + IDESourceControlProjectOriginsDictionary + + 3F4DDE99D53BFFA66E50FFB6AAFA303FD81D596A + github.com:lobodart/CheatyXML.git + + IDESourceControlProjectPath + CheatyXML.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 3F4DDE99D53BFFA66E50FFB6AAFA303FD81D596A + ../.. + + IDESourceControlProjectURL + github.com:lobodart/CheatyXML.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 3F4DDE99D53BFFA66E50FFB6AAFA303FD81D596A + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 3F4DDE99D53BFFA66E50FFB6AAFA303FD81D596A + IDESourceControlWCCName + CheatyXML + + + + diff --git a/CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 27e6c70..fe2b454 100644 --- a/CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,22 +2,4 @@ - - - - - - diff --git a/CheatyXMLTests/CheatyXMLTests.swift b/CheatyXMLTests/CheatyXMLTests.swift index d569a53..8a8f403 100644 --- a/CheatyXMLTests/CheatyXMLTests.swift +++ b/CheatyXMLTests/CheatyXMLTests.swift @@ -8,12 +8,17 @@ import UIKit import XCTest +import CheatyXML class CheatyXMLTests: XCTestCase { + var filePath: String! + override func setUp() { super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. + + self.filePath = NSBundle(forClass: self.dynamicType).pathForResource("Test", ofType: "xml") + XCTAssert(self.filePath != nil, "Cannot open file Test.xml") } override func tearDown() { @@ -21,16 +26,31 @@ class CheatyXMLTests: XCTestCase { super.tearDown() } - func testExample() { - // This is an example of a functional test case. - XCTAssert(true, "Pass") - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measureBlock() { - // Put the code you want to measure the time of here. + func testConstructor() { + let url: NSURL = NSURL(fileURLWithPath: self.filePath) + let urlParser: XMLParser! = XMLParser(contentsOfURL: url) + XCTAssert(urlParser != nil, "XMLParser constructor with URL failed.") + + do { + let content: String = try String(contentsOfFile: self.filePath) + let stringParser: XMLParser! = XMLParser(string: content) + XCTAssert(stringParser != nil, "XMLParser constructor with String failed.") + + let data: NSData! = NSData(contentsOfURL: url) + XCTAssert(data != nil, "Cannot create NSData from file.") + + let dataParser: XMLParser! = XMLParser(data: data) + XCTAssert(dataParser != nil, "XMLParser constructor with NSData failed.") + } catch { + XCTAssert(false, "Cannot open content of file.") } } + func testTagRetrieving() { + let url: NSURL = NSURL(fileURLWithPath: self.filePath) + let parser: XMLParser = XMLParser(contentsOfURL: url)! + + let blogName: String! = parser["name"].stringValue + XCTAssert(blogName == "MyAwesomeBlog!", "Cannot retrieve blogName.") + } } diff --git a/CheatyXMLTests/Test.xml b/CheatyXMLTests/Test.xml new file mode 100644 index 0000000..faf0dc3 --- /dev/null +++ b/CheatyXMLTests/Test.xml @@ -0,0 +1,14 @@ + + MyAwesomeBlog! + + lobodart + slash705 + +
+ My first article + This is the first article + + 2015-03-15 15:42:42 + +
+
\ No newline at end of file From 980a1e6913caf64f1ef55dd80acb6ef0d97d8173 Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:00:24 -0700 Subject: [PATCH 02/21] Adding Unit Test + Travis CI --- .travis.yml | 5 +++ CheatyXML/CheatyXML.swift | 58 +++++++++++++++++++++-------- CheatyXMLTests/CheatyXMLTests.swift | 49 ++++++++++++++++++++---- CheatyXMLTests/Test.xml | 12 ++++-- 4 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0233dbe --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: objective-c + +xcode_project: CheatyXML.xcodeproj + +xcode_scheme: CheatyXMLTests \ No newline at end of file diff --git a/CheatyXML/CheatyXML.swift b/CheatyXML/CheatyXML.swift index e84cb6b..78ccce9 100644 --- a/CheatyXML/CheatyXML.swift +++ b/CheatyXML/CheatyXML.swift @@ -13,7 +13,7 @@ public class XMLParser: NSObject, NSXMLParserDelegate { public class XMLElement: NSObject, SequenceType, GeneratorType { public let tagName: String! - public var attributes: [NSObject: AnyObject]! { + public var attributes: [NSObject: AnyObject] { get { return self._attributes } @@ -21,7 +21,7 @@ public class XMLParser: NSObject, NSXMLParserDelegate { public var count: Int { get { - if self._parentElement == nil { + guard let _ = self._parentElement else { return 1 } @@ -32,24 +32,56 @@ public class XMLParser: NSObject, NSXMLParserDelegate { public var numberOfChildElements: Int { get { - return self._subElements?.count ?? 0 + return self._subElements.count } } - private var _subElements: [XMLElement]! + private var _subElements: [XMLElement] = [] private var _content: String? private var _parentElement: XMLElement! - private var _attributes: [NSObject: AnyObject]! + private var _attributes: [NSObject: AnyObject] = [:] private var _generatorIndex: Int = 0 //override public var debugDescription: String { get { return self.description() } } - public var stringValue: String! { - get { return self._content! } + private var _numberContent: NSNumber? { + get { + guard let content = self._content else { + return nil + } + + let formatter: NSNumberFormatter = NSNumberFormatter() + formatter.numberStyle = .DecimalStyle + return formatter.numberFromString(content) + } + } + + public var exists: Bool { get { return !(self is XMLNullElement) } } + + public var string: String? { get { return self._content } } + public var stringValue: String { get { return self.string! } } + public var int: Int? { get { return self._numberContent?.integerValue } } + public var intValue: Int { get { return self.int! } } + public var float: Float? { get { return self._numberContent?.floatValue } } + public var floatValue: Float { get { return self.float! } } + public var double: Double? { get { return self._numberContent?.doubleValue } } + public var doubleValue: Double { get { return self.double! } } + public var number: NSNumber? { get { return self._numberContent } } + public var numberValue: NSNumber { get { return self.number! } } + public var array: [XMLElement] { get { return self._parentElement?.arrayOfElementsNamed(self.tagName) ?? self._subElements } } + + public func date(format: String) -> NSDate? { + guard let content = self._content else { + return nil + } + + let dateFormat = NSDateFormatter() + dateFormat.dateFormat = format + return dateFormat.dateFromString(content) } - public var string: String? { - get { return self._content } + public func dateValue(format: String) -> NSDate { + return self.date(format)! } init(tagName: String!) { @@ -78,17 +110,13 @@ public class XMLParser: NSObject, NSXMLParserDelegate { return self.arrayOfElementsNamed(name) } - private final func arrayOfElementsNamed(tagName: String) -> [XMLElement]! { + private final func arrayOfElementsNamed(tagName: String) -> [XMLElement] { return self._subElements.filter({(element: XMLElement) -> Bool in return element.tagName == tagName }) } private final func addSubElement(subElement: XMLElement) { - if self._subElements == nil { - self._subElements = [] - } - self._subElements.append(subElement) } @@ -182,7 +210,7 @@ public class XMLParser: NSObject, NSXMLParserDelegate { } private func initXMLParser() -> Bool { - if self._xmlParser == nil { + guard let _ = self._xmlParser else { return false } diff --git a/CheatyXMLTests/CheatyXMLTests.swift b/CheatyXMLTests/CheatyXMLTests.swift index 8a8f403..5e17927 100644 --- a/CheatyXMLTests/CheatyXMLTests.swift +++ b/CheatyXMLTests/CheatyXMLTests.swift @@ -18,7 +18,9 @@ class CheatyXMLTests: XCTestCase { super.setUp() self.filePath = NSBundle(forClass: self.dynamicType).pathForResource("Test", ofType: "xml") - XCTAssert(self.filePath != nil, "Cannot open file Test.xml") + XCTAssert(self.filePath != nil) + + self.continueAfterFailure = false } override func tearDown() { @@ -29,20 +31,20 @@ class CheatyXMLTests: XCTestCase { func testConstructor() { let url: NSURL = NSURL(fileURLWithPath: self.filePath) let urlParser: XMLParser! = XMLParser(contentsOfURL: url) - XCTAssert(urlParser != nil, "XMLParser constructor with URL failed.") + XCTAssert(urlParser != nil) do { let content: String = try String(contentsOfFile: self.filePath) let stringParser: XMLParser! = XMLParser(string: content) - XCTAssert(stringParser != nil, "XMLParser constructor with String failed.") + XCTAssert(stringParser != nil) let data: NSData! = NSData(contentsOfURL: url) - XCTAssert(data != nil, "Cannot create NSData from file.") + XCTAssert(data != nil) let dataParser: XMLParser! = XMLParser(data: data) - XCTAssert(dataParser != nil, "XMLParser constructor with NSData failed.") + XCTAssert(dataParser != nil) } catch { - XCTAssert(false, "Cannot open content of file.") + XCTAssert(false) } } @@ -51,6 +53,39 @@ class CheatyXMLTests: XCTestCase { let parser: XMLParser = XMLParser(contentsOfURL: url)! let blogName: String! = parser["name"].stringValue - XCTAssert(blogName == "MyAwesomeBlog!", "Cannot retrieve blogName.") + XCTAssert(blogName == "MyAwesomeBlog!") + + let admin: String! = parser["users"]["admin"].stringValue + XCTAssert(admin == "lobodart") + + let article: String! = parser["article"][0]["title"].stringValue + XCTAssert(article == "My first article") + + let article2: String! = parser["article"][1]["title"].stringValue + XCTAssert(article2 == "Another article") + + let articleOtherNotation: String! = parser["article", 0]["title"].stringValue + XCTAssert(articleOtherNotation == "My first article") + + let article2OtherNotation: String! = parser["article", 1]["title"].stringValue + XCTAssert(article2OtherNotation == "Another article") + } + + func testTypeCasts() { + let url: NSURL = NSURL(fileURLWithPath: self.filePath) + let parser: XMLParser = XMLParser(contentsOfURL: url)! + + let articles = parser["article"].array + XCTAssert(articles.count == 2) + + let article = articles[0] + + XCTAssert(article["title"].stringValue == "My first article") + XCTAssert(article["read"].intValue == 324) + XCTAssert(article["rate"].floatValue == 4.3) + XCTAssert(article["rate"].doubleValue == 4.3) + XCTAssert(article["date"].date("yyyy-MM-dd HH:mm:ss") != nil) + XCTAssert(article["title"].exists == true) + XCTAssert(article["foobar"].exists == false) } } diff --git a/CheatyXMLTests/Test.xml b/CheatyXMLTests/Test.xml index faf0dc3..6854d44 100644 --- a/CheatyXMLTests/Test.xml +++ b/CheatyXMLTests/Test.xml @@ -7,8 +7,14 @@
My first article This is the first article - - 2015-03-15 15:42:42 - + 2015-03-15 15:42:42 + 324 + 4.3 +
+
+ Another article + This is another article + 2015-04-15 15:42:42 + 42
\ No newline at end of file From f441f224b1cc955353d8cdbb397b477e9070ad81 Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:02:51 -0700 Subject: [PATCH 03/21] Fix .travis.yml mistake --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0233dbe..5f66b08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,4 @@ language: objective-c xcode_project: CheatyXML.xcodeproj -xcode_scheme: CheatyXMLTests \ No newline at end of file +xcode_scheme: CheatyXML \ No newline at end of file From ca87baedf8b01b5e47b5f359e4a9f2f2a93bca0d Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:08:27 -0700 Subject: [PATCH 04/21] Sharing the CheatyXML scheme --- .../xcschemes/CheatyXML.xcscheme | 11 +++++++---- .../xcschemes/xcschememanagement.plist | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) rename CheatyXML.xcodeproj/{xcuserdata/louisbodart.xcuserdatad => xcshareddata}/xcschemes/CheatyXML.xcscheme (95%) diff --git a/CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcschemes/CheatyXML.xcscheme b/CheatyXML.xcodeproj/xcshareddata/xcschemes/CheatyXML.xcscheme similarity index 95% rename from CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcschemes/CheatyXML.xcscheme rename to CheatyXML.xcodeproj/xcshareddata/xcschemes/CheatyXML.xcscheme index 0102d0e..f2c2e9f 100644 --- a/CheatyXML.xcodeproj/xcuserdata/louisbodart.xcuserdatad/xcschemes/CheatyXML.xcscheme +++ b/CheatyXML.xcodeproj/xcshareddata/xcschemes/CheatyXML.xcscheme @@ -37,10 +37,10 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:CheatyXML.xcodeproj"> + + SchemeUserState - CheatyXML.xcscheme + CheatyXML.xcscheme_^#shared#^_ orderHint 0 From 3593055e11743561872bd4e49d8cd6c86761e895 Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:11:23 -0700 Subject: [PATCH 05/21] Adding Xcode 7.3 to .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5f66b08..3c2ff23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: objective-c +osx_image: xcode7.3 + xcode_project: CheatyXML.xcodeproj xcode_scheme: CheatyXML \ No newline at end of file From 4bbd9edacc0177fe20bff0ab061e6afce4fef41f Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:21:58 -0700 Subject: [PATCH 06/21] Editing .travis.yml --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0233dbe..ac9df8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: objective-c -xcode_project: CheatyXML.xcodeproj +xcode_sdk: iphonesimulator -xcode_scheme: CheatyXMLTests \ No newline at end of file +script: +- xcodebuild -project CheatyXML.xcodeproj -scheme "CheatyXML" -destination "platform=iOS Simulator,name=iPhone 6" test \ No newline at end of file From 86157764f290bbdabdfc480e5de58c7554ac5c49 Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:26:31 -0700 Subject: [PATCH 07/21] Fixing Xcode version in .travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ac9df8e..2f2c582 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: objective-c -xcode_sdk: iphonesimulator +osx_image: xcode7.1 +xcode_sdk: iphonesimulator9.0 script: - xcodebuild -project CheatyXML.xcodeproj -scheme "CheatyXML" -destination "platform=iOS Simulator,name=iPhone 6" test \ No newline at end of file From f8c00876d49c6821dfa3eda0daaa409b8f914736 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Wed, 27 Apr 2016 22:32:15 -0700 Subject: [PATCH 08/21] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9b79c61..c21762b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # CheatyXML + +[![Build Status](https://travis-ci.org/lobodart/CheatyXML.svg?branch=master)](https://travis-ci.org/lobodart/CheatyXML) + CheatyXML is a Swift framework designed to manage XML easily. ## Installation From 50d312eb402e0e74e3220460e64ad7cd4a13fb27 Mon Sep 17 00:00:00 2001 From: Louis BODART Date: Wed, 27 Apr 2016 22:38:35 -0700 Subject: [PATCH 09/21] Fixing memory leak --- CheatyXML/CheatyXML.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CheatyXML/CheatyXML.swift b/CheatyXML/CheatyXML.swift index 78ccce9..fd95a08 100644 --- a/CheatyXML/CheatyXML.swift +++ b/CheatyXML/CheatyXML.swift @@ -182,6 +182,7 @@ public class XMLParser: NSObject, NSXMLParserDelegate { private let _xmlParser: NSXMLParser! private var _pointerTree: [COpaquePointer]! private var _rootElement: XMLElement! + private var _allocatedPointersList: [UnsafeMutablePointer] = [] public init?(contentsOfURL: NSURL) { self._xmlParser = NSXMLParser(contentsOfURL: contentsOfURL) @@ -209,6 +210,12 @@ public class XMLParser: NSObject, NSXMLParserDelegate { self.init(data: NSString(string: string).dataUsingEncoding(NSUTF8StringEncoding)) } + deinit { + for pointer in self._allocatedPointersList { + pointer.dealloc(1) + } + } + private func initXMLParser() -> Bool { guard let _ = self._xmlParser else { return false @@ -239,6 +246,7 @@ public class XMLParser: NSObject, NSXMLParserDelegate { let ps = UnsafeMutablePointer.alloc(1) ps.initialize(newElement) + self._allocatedPointersList.append(ps) let cps = COpaquePointer(ps) self._pointerTree.append(cps) } From 826fa15dfdf9076dabb2922eb7b1d1be6db362ec Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Wed, 27 Apr 2016 22:44:55 -0700 Subject: [PATCH 10/21] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c21762b..690a690 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # CheatyXML [![Build Status](https://travis-ci.org/lobodart/CheatyXML.svg?branch=master)](https://travis-ci.org/lobodart/CheatyXML) +[![Coverage Status](https://coveralls.io/repos/github/lobodart/CheatyXML/badge.svg?branch=master)](https://coveralls.io/github/lobodart/CheatyXML?branch=master) CheatyXML is a Swift framework designed to manage XML easily. From 53027b5ea1429ffba0b52309f0cdcf272c435f5b Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Sun, 17 Jul 2016 00:56:38 -0700 Subject: [PATCH 11/21] Type casting, code refactoring --- CheatyXML.xcodeproj/project.pbxproj | 32 +++- CheatyXML/CheatyXML.swift | 278 ---------------------------- CheatyXML/XMLAttribute.swift | 23 +++ CheatyXML/XMLElement.swift | 28 +++ CheatyXML/XMLNullAttribute.swift | 19 ++ CheatyXML/XMLNullTag.swift | 31 ++++ CheatyXML/XMLParser.swift | 118 ++++++++++++ CheatyXML/XMLTag.swift | 153 +++++++++++++++ CheatyXMLTests/CheatyXMLTests.swift | 31 +++- CheatyXMLTests/Info.plist | 2 +- CheatyXMLTests/Test.xml | 2 + CheatyXMLTests/TestFail.xml | 1 + scripts/ci.sh | 5 + 13 files changed, 438 insertions(+), 285 deletions(-) delete mode 100644 CheatyXML/CheatyXML.swift create mode 100644 CheatyXML/XMLAttribute.swift create mode 100644 CheatyXML/XMLElement.swift create mode 100644 CheatyXML/XMLNullAttribute.swift create mode 100644 CheatyXML/XMLNullTag.swift create mode 100644 CheatyXML/XMLParser.swift create mode 100644 CheatyXML/XMLTag.swift create mode 100644 CheatyXMLTests/TestFail.xml create mode 100644 scripts/ci.sh diff --git a/CheatyXML.xcodeproj/project.pbxproj b/CheatyXML.xcodeproj/project.pbxproj index dff376a..cfac0b0 100644 --- a/CheatyXML.xcodeproj/project.pbxproj +++ b/CheatyXML.xcodeproj/project.pbxproj @@ -10,7 +10,13 @@ 486D48811AB4A19D004F6258 /* CheatyXML.h in Headers */ = {isa = PBXBuildFile; fileRef = 486D48801AB4A19D004F6258 /* CheatyXML.h */; settings = {ATTRIBUTES = (Public, ); }; }; 486D48871AB4A19D004F6258 /* CheatyXML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 486D487B1AB4A19D004F6258 /* CheatyXML.framework */; }; 486D488E1AB4A19D004F6258 /* CheatyXMLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */; }; - 486D48981AB4A1AF004F6258 /* CheatyXML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D48971AB4A1AF004F6258 /* CheatyXML.swift */; }; + 486D48981AB4A1AF004F6258 /* XMLParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D48971AB4A1AF004F6258 /* XMLParser.swift */; }; + 4894F4EB1D3B5C6100BF093C /* TestFail.xml in Resources */ = {isa = PBXBuildFile; fileRef = 4894F4EA1D3B5C6100BF093C /* TestFail.xml */; }; + 48B018D71D3B629D00E31BE4 /* XMLTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018D61D3B629D00E31BE4 /* XMLTag.swift */; }; + 48B018D91D3B62CB00E31BE4 /* XMLNullTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018D81D3B62CB00E31BE4 /* XMLNullTag.swift */; }; + 48B018DB1D3B636900E31BE4 /* XMLElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DA1D3B636900E31BE4 /* XMLElement.swift */; }; + 48B018DD1D3B643800E31BE4 /* XMLAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DC1D3B643800E31BE4 /* XMLAttribute.swift */; }; + 48B018DF1D3B6E3500E31BE4 /* XMLNullAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DE1D3B6E3500E31BE4 /* XMLNullAttribute.swift */; }; 48CD10F61CCFEAD800A8CFAD /* Test.xml in Resources */ = {isa = PBXBuildFile; fileRef = 48CD10F51CCFEAD800A8CFAD /* Test.xml */; }; /* End PBXBuildFile section */ @@ -31,7 +37,13 @@ 486D48861AB4A19D004F6258 /* CheatyXMLTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CheatyXMLTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 486D488C1AB4A19D004F6258 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatyXMLTests.swift; sourceTree = ""; }; - 486D48971AB4A1AF004F6258 /* CheatyXML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheatyXML.swift; sourceTree = ""; }; + 486D48971AB4A1AF004F6258 /* XMLParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLParser.swift; sourceTree = ""; }; + 4894F4EA1D3B5C6100BF093C /* TestFail.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = TestFail.xml; sourceTree = ""; }; + 48B018D61D3B629D00E31BE4 /* XMLTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLTag.swift; sourceTree = ""; }; + 48B018D81D3B62CB00E31BE4 /* XMLNullTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLNullTag.swift; sourceTree = ""; }; + 48B018DA1D3B636900E31BE4 /* XMLElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLElement.swift; sourceTree = ""; }; + 48B018DC1D3B643800E31BE4 /* XMLAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLAttribute.swift; sourceTree = ""; }; + 48B018DE1D3B6E3500E31BE4 /* XMLNullAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLNullAttribute.swift; sourceTree = ""; }; 48CD10F51CCFEAD800A8CFAD /* Test.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Test.xml; sourceTree = ""; }; 48F5B5041AB4ADAB00E68B10 /* Test.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Test.playground; sourceTree = ""; }; /* End PBXFileReference section */ @@ -78,7 +90,12 @@ isa = PBXGroup; children = ( 486D48801AB4A19D004F6258 /* CheatyXML.h */, - 486D48971AB4A1AF004F6258 /* CheatyXML.swift */, + 486D48971AB4A1AF004F6258 /* XMLParser.swift */, + 48B018D61D3B629D00E31BE4 /* XMLTag.swift */, + 48B018DA1D3B636900E31BE4 /* XMLElement.swift */, + 48B018DC1D3B643800E31BE4 /* XMLAttribute.swift */, + 48B018DE1D3B6E3500E31BE4 /* XMLNullAttribute.swift */, + 48B018D81D3B62CB00E31BE4 /* XMLNullTag.swift */, 486D487E1AB4A19D004F6258 /* Supporting Files */, ); path = CheatyXML; @@ -97,6 +114,7 @@ children = ( 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */, 48CD10F51CCFEAD800A8CFAD /* Test.xml */, + 4894F4EA1D3B5C6100BF093C /* TestFail.xml */, 486D488B1AB4A19D004F6258 /* Supporting Files */, ); path = CheatyXMLTests; @@ -210,6 +228,7 @@ buildActionMask = 2147483647; files = ( 48CD10F61CCFEAD800A8CFAD /* Test.xml in Resources */, + 4894F4EB1D3B5C6100BF093C /* TestFail.xml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -220,7 +239,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 486D48981AB4A1AF004F6258 /* CheatyXML.swift in Sources */, + 48B018D71D3B629D00E31BE4 /* XMLTag.swift in Sources */, + 48B018DF1D3B6E3500E31BE4 /* XMLNullAttribute.swift in Sources */, + 486D48981AB4A1AF004F6258 /* XMLParser.swift in Sources */, + 48B018DB1D3B636900E31BE4 /* XMLElement.swift in Sources */, + 48B018DD1D3B643800E31BE4 /* XMLAttribute.swift in Sources */, + 48B018D91D3B62CB00E31BE4 /* XMLNullTag.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/CheatyXML/CheatyXML.swift b/CheatyXML/CheatyXML.swift deleted file mode 100644 index fd95a08..0000000 --- a/CheatyXML/CheatyXML.swift +++ /dev/null @@ -1,278 +0,0 @@ -// -// CheatyXML.swift -// CheatyXML -// -// Created by Louis BODART on 14/03/2015. -// Copyright (c) 2015 Louis BODART. All rights reserved. -// - -import Foundation - -public class XMLParser: NSObject, NSXMLParserDelegate { - - public class XMLElement: NSObject, SequenceType, GeneratorType { - - public let tagName: String! - public var attributes: [NSObject: AnyObject] { - get { - return self._attributes - } - } - - public var count: Int { - get { - guard let _ = self._parentElement else { - return 1 - } - - let array: [XMLElement] = self._parentElement.arrayOfElementsNamed(self.tagName) - return array.count - } - } - - public var numberOfChildElements: Int { - get { - return self._subElements.count - } - } - - private var _subElements: [XMLElement] = [] - private var _content: String? - private var _parentElement: XMLElement! - private var _attributes: [NSObject: AnyObject] = [:] - private var _generatorIndex: Int = 0 - - //override public var debugDescription: String { get { return self.description() } } - - private var _numberContent: NSNumber? { - get { - guard let content = self._content else { - return nil - } - - let formatter: NSNumberFormatter = NSNumberFormatter() - formatter.numberStyle = .DecimalStyle - return formatter.numberFromString(content) - } - } - - public var exists: Bool { get { return !(self is XMLNullElement) } } - - public var string: String? { get { return self._content } } - public var stringValue: String { get { return self.string! } } - public var int: Int? { get { return self._numberContent?.integerValue } } - public var intValue: Int { get { return self.int! } } - public var float: Float? { get { return self._numberContent?.floatValue } } - public var floatValue: Float { get { return self.float! } } - public var double: Double? { get { return self._numberContent?.doubleValue } } - public var doubleValue: Double { get { return self.double! } } - public var number: NSNumber? { get { return self._numberContent } } - public var numberValue: NSNumber { get { return self.number! } } - public var array: [XMLElement] { get { return self._parentElement?.arrayOfElementsNamed(self.tagName) ?? self._subElements } } - - public func date(format: String) -> NSDate? { - guard let content = self._content else { - return nil - } - - let dateFormat = NSDateFormatter() - dateFormat.dateFormat = format - return dateFormat.dateFromString(content) - } - - public func dateValue(format: String) -> NSDate { - return self.date(format)! - } - - init(tagName: String!) { - self.tagName = tagName - } - - // Problem with Swift 1.2 - /*public func description() -> String { - return "XMLElement <\(self.tagName)>, attributes(\(self.attributes?.count ?? 0)): \(self.attributes), children: \(self._subElements?.count ?? 0)" - }*/ - - public func generate() -> XMLElement { - self._generatorIndex = 0 - return self - } - - public func next() -> XMLElement? { - if self._generatorIndex < 0 || self._generatorIndex >= self._subElements.count { - return nil - } - - return self._subElements[self._generatorIndex++] - } - - public func elementsNamed(name: String) -> [XMLElement] { - return self.arrayOfElementsNamed(name) - } - - private final func arrayOfElementsNamed(tagName: String) -> [XMLElement] { - return self._subElements.filter({(element: XMLElement) -> Bool in - return element.tagName == tagName - }) - } - - private final func addSubElement(subElement: XMLElement) { - self._subElements.append(subElement) - } - - public subscript(tagName: String) -> XMLElement! { - get { - return self[tagName, 0] - } - } - - public subscript(index: Int) -> XMLElement! { - get { - return self._parentElement[self.tagName, index] - } - } - - public subscript(tagName: String, index: Int) -> XMLElement! { - get { - if index < 0 { - return XMLNullElement() - } - - let array = self._subElements.filter({(element: XMLElement) -> Bool in - return element.tagName == tagName - }) - - if index >= array.count { - return XMLNullElement() - } - - return array[index] - } - } - } - - public class XMLNullElement: XMLElement { - - init() { super.init(tagName: nil) } - - // Problem with Swift 1.2 - /*public override func description() -> String { - return "XMLNullElement" - }*/ - - public override subscript(tagName: String) -> XMLElement! { - get { return XMLNullElement() } - } - - public override subscript(index: Int) -> XMLElement! { - get { return XMLNullElement() } - } - - public override subscript(tagName: String, index: Int) -> XMLElement! { - get { return XMLNullElement() } - } - } - - public var rootElement: XMLElement! { - get { - return self._rootElement - } - } - - private let _xmlParser: NSXMLParser! - private var _pointerTree: [COpaquePointer]! - private var _rootElement: XMLElement! - private var _allocatedPointersList: [UnsafeMutablePointer] = [] - - public init?(contentsOfURL: NSURL) { - self._xmlParser = NSXMLParser(contentsOfURL: contentsOfURL) - - super.init() - if !self.initXMLParser() { - return nil - } - } - - public init?(data: NSData!) { - self._xmlParser = data != nil ? NSXMLParser(data: data) : nil - - super.init() - if self._xmlParser == nil { - return nil - } - - if !self.initXMLParser() { - return nil - } - } - - public convenience init?(string: String) { - self.init(data: NSString(string: string).dataUsingEncoding(NSUTF8StringEncoding)) - } - - deinit { - for pointer in self._allocatedPointersList { - pointer.dealloc(1) - } - } - - private func initXMLParser() -> Bool { - guard let _ = self._xmlParser else { - return false - } - - self._xmlParser.delegate = self - return self._xmlParser.parse() - } - - public final func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { - - let newElement: XMLElement = XMLElement(tagName: elementName) - if self._rootElement == nil { - self._rootElement = newElement - } - - if !attributeDict.isEmpty { - newElement._attributes = attributeDict - } - - if self._pointerTree == nil { - self._pointerTree = [] - } else { - let nps = UnsafeMutablePointer(self._pointerTree.last!) - newElement._parentElement = nps.memory - nps.memory.addSubElement(newElement) - } - - let ps = UnsafeMutablePointer.alloc(1) - ps.initialize(newElement) - self._allocatedPointersList.append(ps) - let cps = COpaquePointer(ps) - self._pointerTree.append(cps) - } - - public final func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { - self._pointerTree.removeLast() - } - - public final func parser(parser: NSXMLParser, foundCharacters string: String) { - let nps = UnsafeMutablePointer(self._pointerTree.last!) - var tmpString: String! = nps.memory._content ?? "" - tmpString! += string - - let regex: NSRegularExpression = try! NSRegularExpression(pattern: "[^\\n\\s]+", options: []) - if regex.matchesInString(tmpString, options: [], range: NSMakeRange(0, tmpString.characters.count)).count <= 0 { - tmpString = nil - } - - nps.memory._content = tmpString - } - - public subscript(tagName: String) -> XMLElement! { - return self._rootElement[tagName] - } - - public subscript(tagName: String, index: Int) -> XMLElement! { - return self._rootElement[tagName, index] - } -} \ No newline at end of file diff --git a/CheatyXML/XMLAttribute.swift b/CheatyXML/XMLAttribute.swift new file mode 100644 index 0000000..5bb1bb4 --- /dev/null +++ b/CheatyXML/XMLAttribute.swift @@ -0,0 +1,23 @@ +// +// XMLAttribute.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +public class XMLAttribute: XMLElement { + + public let name: String! + + init(name: String!, value: String?) { + self.name = name + super.init(content: value) + } + + public override var description: String { + return "XMLAttribute" + } +} \ No newline at end of file diff --git a/CheatyXML/XMLElement.swift b/CheatyXML/XMLElement.swift new file mode 100644 index 0000000..1fae6d9 --- /dev/null +++ b/CheatyXML/XMLElement.swift @@ -0,0 +1,28 @@ +// +// XMLElement.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +public class XMLElement: NSObject { + + internal var _content: String? + + public var string: String? { get { return self._content } } + public var stringValue: String { get { return self.string! } } + public var int: Int? { get { return Int(self._content ?? "") ?? (self.double != nil ? Int(self.doubleValue) : nil) } } + public var intValue: Int { get { return self.int! } } + public var float: Float? { get { return Float(self._content ?? "") } } + public var floatValue: Float { get { return self.float! } } + public var double: Double? { get { return Double(self._content ?? "") } } + public var doubleValue: Double { get { return self.double! } } + + internal init(content: String?) { + self._content = content + super.init() + } +} \ No newline at end of file diff --git a/CheatyXML/XMLNullAttribute.swift b/CheatyXML/XMLNullAttribute.swift new file mode 100644 index 0000000..15ba768 --- /dev/null +++ b/CheatyXML/XMLNullAttribute.swift @@ -0,0 +1,19 @@ +// +// XMLNullAttribute.swift +// CheatyXML +// +// Created by Louis BODART on 17/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - XMLNullAttribute Class +public class XMLNullAttribute: XMLAttribute { + + public override var description: String { + return "XMLNullAttribute" + } + + init() { super.init(name: nil, value: nil) } +} \ No newline at end of file diff --git a/CheatyXML/XMLNullTag.swift b/CheatyXML/XMLNullTag.swift new file mode 100644 index 0000000..93bb593 --- /dev/null +++ b/CheatyXML/XMLNullTag.swift @@ -0,0 +1,31 @@ +// +// XMLNullTag.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - XMLNullTag Class +public class XMLNullTag: XMLTag { + + public override var description: String { + return "XMLNullTag" + } + + init() { super.init(tagName: nil) } + + public override subscript(tagName: String) -> XMLTag! { + get { return XMLNullTag() } + } + + public override subscript(index: Int) -> XMLTag! { + get { return XMLNullTag() } + } + + public override subscript(tagName: String, index: Int) -> XMLTag! { + get { return XMLNullTag() } + } +} \ No newline at end of file diff --git a/CheatyXML/XMLParser.swift b/CheatyXML/XMLParser.swift new file mode 100644 index 0000000..262b754 --- /dev/null +++ b/CheatyXML/XMLParser.swift @@ -0,0 +1,118 @@ +// +// CheatyXML.swift +// CheatyXML +// +// Created by Louis BODART on 14/03/2015. +// Copyright (c) 2015 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - XMLParser Class +public class XMLParser: NSObject, NSXMLParserDelegate { + + public var rootElement: XMLTag! { + get { + return self._rootElement + } + } + + private let _xmlParser: NSXMLParser! + private var _pointerTree: [COpaquePointer]! + private var _rootElement: XMLTag! + private var _allocatedPointersList: [UnsafeMutablePointer] = [] + + public init?(contentsOfURL: NSURL) { + self._xmlParser = NSXMLParser(contentsOfURL: contentsOfURL) + + super.init() + if !self.initXMLParser() { + return nil + } + } + + public init?(data: NSData!) { + self._xmlParser = data != nil ? NSXMLParser(data: data) : nil + + super.init() + guard let _ = self._xmlParser else { + return nil + } + + if !self.initXMLParser() { + return nil + } + } + + public convenience init?(string: String) { + self.init(data: NSString(string: string).dataUsingEncoding(NSUTF8StringEncoding)) + } + + deinit { + for pointer in self._allocatedPointersList { + pointer.dealloc(1) + } + } + + private func initXMLParser() -> Bool { + guard let _ = self._xmlParser else { + return false + } + + self._xmlParser.delegate = self + return self._xmlParser.parse() + } + + public final func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { + + let newElement: XMLTag = XMLTag(tagName: elementName) + if self._rootElement == nil { + self._rootElement = newElement + } + + if !attributeDict.isEmpty { + newElement._attributes = attributeDict.map({ (name: String, value: String) -> XMLAttribute in + return XMLAttribute(name: name, value: value) + }) + } + + if self._pointerTree == nil { + self._pointerTree = [] + } else { + let nps = UnsafeMutablePointer(self._pointerTree.last!) + newElement._parentElement = nps.memory + nps.memory.addSubElement(newElement) + } + + let ps = UnsafeMutablePointer.alloc(1) + ps.initialize(newElement) + self._allocatedPointersList.append(ps) + let cps = COpaquePointer(ps) + self._pointerTree.append(cps) + } + + public final func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { + self._pointerTree.removeLast() + } + + public final func parser(parser: NSXMLParser, foundCharacters string: String) { + let nps = UnsafeMutablePointer(self._pointerTree.last!) + var tmpString: String! = nps.memory._content ?? "" + tmpString! += string + + let regex: NSRegularExpression = try! NSRegularExpression(pattern: "[^\\n\\s]+", options: []) + if regex.matchesInString(tmpString, options: [], range: NSMakeRange(0, tmpString.characters.count)).count <= 0 { + tmpString = nil + } + + nps.memory._content = tmpString + } + + public subscript(tagName: String) -> XMLTag! { + return self._rootElement[tagName] + } + + public subscript(tagName: String, index: Int) -> XMLTag! { + return self._rootElement[tagName, index] + } +} \ No newline at end of file diff --git a/CheatyXML/XMLTag.swift b/CheatyXML/XMLTag.swift new file mode 100644 index 0000000..28dceb1 --- /dev/null +++ b/CheatyXML/XMLTag.swift @@ -0,0 +1,153 @@ +// +// XMLTag.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - XMLTag Class +public class XMLTag: XMLElement, SequenceType, GeneratorType { + + public let tagName: String! + public var attributes: [XMLAttribute] { + get { + return self._attributes + } + } + + public var count: Int { + get { + guard let _ = self._parentElement else { + return 1 + } + + let array: [XMLTag] = self._parentElement.arrayOfElementsNamed(self.tagName) + return array.count + } + } + + public var numberOfChildElements: Int { + get { + return self._subElements.count + } + } + + internal var _subElements: [XMLTag] = [] + internal var _parentElement: XMLTag! + internal var _attributes: [XMLAttribute] = [] + internal var _generatorIndex: Int = 0 + + public override var debugDescription: String { get { return self.description } } + public override var description: String { + return "XMLTag <\(self.tagName)>, attributes(\(self.attributes.count ?? 0)): \(self.attributes), children: \(self._subElements.count)" + } + + public var exists: Bool { get { return !(self is XMLNullTag) } } + + public var array: [XMLTag] { get { return self._parentElement?.arrayOfElementsNamed(self.tagName) ?? self._subElements } } + + public func date(format: String) -> NSDate? { + guard let content = self._content else { + return nil + } + + let dateFormat = NSDateFormatter() + dateFormat.dateFormat = format + return dateFormat.dateFromString(content) + } + + public func dateValue(format: String) -> NSDate { + return self.date(format)! + } + + public func generate() -> XMLTag { + self._generatorIndex = 0 + return self + } + + public func next() -> XMLTag? { + if self._generatorIndex < 0 || self._generatorIndex >= self._subElements.count { + return nil + } + + let currentIndex: Int = self._generatorIndex + self._generatorIndex += 1 + + return self._subElements[currentIndex] + } + + public func elementsNamed(name: String) -> [XMLTag] { + return self.arrayOfElementsNamed(name) + } + + public func attribute(name: String) -> XMLAttribute { + guard let index = self._attributes.indexOf({ (attribute) -> Bool in + return attribute.name == name + }) else { + return XMLNullAttribute() + } + + return self._attributes[index] + } + + private final func arrayOfElementsNamed(tagName: String) -> [XMLTag] { + return self._subElements.filter({(element: XMLTag) -> Bool in + return element.tagName == tagName + }) + } + + internal final func addSubElement(subElement: XMLTag) { + self._subElements.append(subElement) + } + + init(tagName: String!) { + self.tagName = tagName + super.init(content: nil) + } + + public subscript(tagName: String) -> XMLTag! { + get { + return self[tagName, 0] + } + } + + public subscript(index: Int) -> XMLTag! { + get { + return self._parentElement[self.tagName, index] + } + } + + public subscript(tagName: String, index: Int) -> XMLTag! { + get { + if index < 0 { + return XMLNullTag() + } + + let array = self._subElements.filter({(element: XMLTag) -> Bool in + return element.tagName == tagName + }) + + if index >= array.count { + return XMLNullTag() + } + + return array[index] + } + } +} + +public extension SequenceType where Generator.Element: XMLAttribute { + + public final var dictionary: [String: String] { + get { + return self.reduce([:], combine: { (dict: [String: String], value: XMLAttribute) -> [String: String] in + var newDict = dict + newDict[value.name] = value._content ?? "" + return newDict + }) + } + } +} \ No newline at end of file diff --git a/CheatyXMLTests/CheatyXMLTests.swift b/CheatyXMLTests/CheatyXMLTests.swift index 5e17927..1e1006c 100644 --- a/CheatyXMLTests/CheatyXMLTests.swift +++ b/CheatyXMLTests/CheatyXMLTests.swift @@ -13,6 +13,7 @@ import CheatyXML class CheatyXMLTests: XCTestCase { var filePath: String! + var failFilePath: String! override func setUp() { super.setUp() @@ -20,6 +21,9 @@ class CheatyXMLTests: XCTestCase { self.filePath = NSBundle(forClass: self.dynamicType).pathForResource("Test", ofType: "xml") XCTAssert(self.filePath != nil) + self.failFilePath = NSBundle(forClass: self.dynamicType).pathForResource("TestFail", ofType: "xml") + XCTAssert(self.failFilePath != nil) + self.continueAfterFailure = false } @@ -29,6 +33,9 @@ class CheatyXMLTests: XCTestCase { } func testConstructor() { + let failParser: XMLParser? = XMLParser(contentsOfURL: NSURL(fileURLWithPath: self.failFilePath)) + XCTAssert(failParser == nil) + let url: NSURL = NSURL(fileURLWithPath: self.filePath) let urlParser: XMLParser! = XMLParser(contentsOfURL: url) XCTAssert(urlParser != nil) @@ -84,8 +91,28 @@ class CheatyXMLTests: XCTestCase { XCTAssert(article["read"].intValue == 324) XCTAssert(article["rate"].floatValue == 4.3) XCTAssert(article["rate"].doubleValue == 4.3) - XCTAssert(article["date"].date("yyyy-MM-dd HH:mm:ss") != nil) + XCTAssert(article["date"].dateValue("yyyy-MM-dd HH:mm:ss").isKindOfClass(NSDate)) XCTAssert(article["title"].exists == true) - XCTAssert(article["foobar"].exists == false) + + + XCTAssert(article["foo"].string == nil) + XCTAssert(article["bar"].int == nil) + XCTAssert(article["john"].float == nil) + XCTAssert(article["doe"].double == nil) + XCTAssert(article["date"].date("failFormat") == nil) + XCTAssert(article["failDate"].date("yyyy-MM-dd HH:mm:ss") == nil) + XCTAssert(article["42"].exists == false) + } + + func testAttributeRetrieving() { + let url: NSURL = NSURL(fileURLWithPath: self.filePath) + let parser: XMLParser = XMLParser(contentsOfURL: url)! + + XCTAssert(parser.rootElement.attributes.count == 2) + XCTAssert(parser.rootElement.attribute("version").stringValue == "1.0") + XCTAssert(parser.rootElement.attribute("version").intValue == 1) + XCTAssert(parser.rootElement.attribute("version").doubleValue == 1.0) + XCTAssert(parser.rootElement.attribute("version").floatValue == 1.0) + XCTAssert(parser.rootElement.attribute("creator").stringValue == "lobodart") } } diff --git a/CheatyXMLTests/Info.plist b/CheatyXMLTests/Info.plist index 30a7804..1657f2a 100644 --- a/CheatyXMLTests/Info.plist +++ b/CheatyXMLTests/Info.plist @@ -3,7 +3,7 @@ NSPrincipalClass - CheatyXML + CheatyXMLTests CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/CheatyXMLTests/Test.xml b/CheatyXMLTests/Test.xml index 6854d44..271e66f 100644 --- a/CheatyXMLTests/Test.xml +++ b/CheatyXMLTests/Test.xml @@ -10,6 +10,8 @@ 2015-03-15 15:42:42 324 4.3 + true + false
Another article diff --git a/CheatyXMLTests/TestFail.xml b/CheatyXMLTests/TestFail.xml new file mode 100644 index 0000000..90fd96b --- /dev/null +++ b/CheatyXMLTests/TestFail.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/ci.sh b/scripts/ci.sh new file mode 100644 index 0000000..0008aea --- /dev/null +++ b/scripts/ci.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -e + +xcodebuild -project CheatyXML.xcodeproj -scheme "CheatyXML" -destination "platform=iOS Simulator,name=iPhone 6" test \ No newline at end of file From 667a0e759933a90cd75f5d5d73f3e6dc753237e7 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Sun, 17 Jul 2016 01:57:34 -0700 Subject: [PATCH 12/21] Update README.md --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 690a690..3deb5cc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # CheatyXML +[![CocoaPods](https://img.shields.io/cocoapods/v/CheatyXML.svg?maxAge=2592000)](https://cocoapods.org/pods/CheatyXML) [![Build Status](https://travis-ci.org/lobodart/CheatyXML.svg?branch=master)](https://travis-ci.org/lobodart/CheatyXML) [![Coverage Status](https://coveralls.io/repos/github/lobodart/CheatyXML/badge.svg?branch=master)](https://coveralls.io/github/lobodart/CheatyXML?branch=master) @@ -31,6 +32,7 @@ Let's take the following XML content for all of our examples : This is the first article 2015-03-15 15:42:42 + 42 ...
@@ -124,6 +126,24 @@ let numberOfElements: Int = parser["users"]["moderator"].count let numberOfElements: Int = parser["users"].elementsNamed("moderator").count ``` -- +### Type casting (>= 2.0.0) +CheatyXML allows you to cast tag/attribute values into some common types. You can get either optional or non-optinal value for your cast. +```swift +let firstArticleRate = parser["article", 0]["rate"] +firstArticleRate.int // Optional(42) +firstArticleRate.intValue // 42 +firstArticleRate.float // Optional(42.0) +firstArticleRate.floatValue // 42.0 +``` +If you are not sure about the type, use the optional caster. If you try to cast a value with an inappropriate caster, your app will crash. +```swift +let firstArticleTitle = parser["article", 0]["title"] +firstArticleTitle.string // Optional("My first article") +firstArticleTitle.stringValue // "My first article" +firstArticleTitle.int // nil +firstArticleTitle.intValue // CRASH! +``` +-- ### Missing tags Until now, we always retrieved existing tags but what would happen if a tag doesn't exist ? Fortunaly for us, CheatyXML manages this case. Let's take an example : ```swift @@ -140,11 +160,41 @@ In sum, you can make mistakes without worrying about your application crash as l -- ### Attributes +#### Get one With CheatyXML, getting any attribute is very simple. +##### >= 2.0.0 ```swift -let blogVersion = parser.rootElement.attributes["version"] +let blogVersion = parser.rootElement.attribute("version") +let adminIsActive = parser["users"]["admin"].attribute("is_active") ``` -Another example using a deeper element : +##### Earlier ```swift +let blogVersion = parser.rootElement.attributes["version"] let adminIsActive = parser["users"]["admin"].attributes["is_active"] ``` +As mentionned above, if you are using a version **>= 2.0.0**, you can also use the type casting on attributes. +```swift +let blogVersion = parser.rootElement.attribute("version").floatValue // 1.0 +let creator = parser.rootElement.attribute("creator").stringValue // "lobodart" +``` +> ###### Note +For more information about the optional/non-optional casting, please read the [Type casting][type-casting] part. + +#### Get all +Once uppon a time, it is very easy to get all the tag attributes. +##### >= 2.0.0 +```swift +let attributes = parser.rootElement.attributes // Will give you a [XMLAttribute] +let dic = attributes.dictionary // Will give you a [String: String] +``` +##### Earlier +```swift +let attributes = parser.rootElement.attributes // Will give you a [String: String] +``` + +### TO-DO +- [ ] Add more Unit Tests +- [ ] Class mapping +- [ ] XML Generator + +[type-casting]: [type-casting] From b5df2733d2749dc347596fa3a6659651632151f3 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Sun, 17 Jul 2016 02:10:51 -0700 Subject: [PATCH 13/21] Add CHANGELOG.md --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cd507e9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +## 2.0.0 (July 17, 2016) + +- Swift 3 ready +- Fix small memory leak +- Add type casting for tags/attributes +- Change the way to retrieve attributes +- XMLElement has been renamed to XMLTag which inherit of XMLElement +- Code refactoring (files now well separated) +- Add Unit Test From 438ccade461054a79708f6e28c774101ffdfc0af Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Sun, 17 Jul 2016 02:32:46 -0700 Subject: [PATCH 14/21] Language corrections --- README.md | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3deb5cc..e5d132b 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,16 @@ [![CocoaPods](https://img.shields.io/cocoapods/v/CheatyXML.svg?maxAge=2592000)](https://cocoapods.org/pods/CheatyXML) [![Build Status](https://travis-ci.org/lobodart/CheatyXML.svg?branch=master)](https://travis-ci.org/lobodart/CheatyXML) -[![Coverage Status](https://coveralls.io/repos/github/lobodart/CheatyXML/badge.svg?branch=master)](https://coveralls.io/github/lobodart/CheatyXML?branch=master) CheatyXML is a Swift framework designed to manage XML easily. ## Installation -To install this, simply add the **.xcodeproj** to your project, and do not forget to link the **.framework**. - +### Cocoapods If you're using **cocoapods**, just add `pod 'CheatyXML'` into your `Podfile` file. +### Manual +To install this, simply add the **.xcodeproj** to your project, and do not forget to link the **.framework**. + Whenever you want to use it in your code, simply type : ```swift import CheatyXML @@ -64,27 +65,27 @@ let blogName: String! = parser["name"].stringValue // Returns a String let blogName: String? = parser["name"].string // Returns an optional String ``` > ###### Note -> You don't have to worry about the root element, but if you want to clarify your code, you can add `rootElement` : +> If you want to clarify your code, you can add `rootElement` : ```swift let element = parser.rootElement["name"] // is the same as the notation seen before ``` -If you want to access to deeper elements like `admin` for example, just chain : +If you want to access to deeper elements like `admin`, just chain : ```swift let blogAdmin: String! = parser["users"]["admin"].stringValue print(blogAdmin) // lobodart ``` -- ### Working with multiple elements -Now let's take a look at the `article` element. Our `blog` element contains a couple of articles. +Now let's take a look at the `article` element. We can see that our `blog` contains a few articles. #### Get an element using its index If we want to get the title of the first article, we can do it like this : ```swift let firstArticleTitle: String! = parser["article", 0]["title"].stringValue let firstArticleTitle: String! = parser["article"][0]["title"].stringValue ``` -Both notation have the same effect. Choose the one you like most. +Both notations have the same effect. Choose the one you like most. #### Browse children of an element To iterate over **all** children of an element, just use the `for in` classic syntax : ```swift @@ -114,11 +115,11 @@ article ``` Of course, you can use this method on any deeper elements (like `users` for example). #### Number of children of an element -If you want to get the total number of child elements contained in an element, you can use this code : +If you want to get the total number of children contained in an element, you can use this code : ```swift // Suppose we have 3 moderators in our example let numberOfElements: Int = parser["users"].numberOfChildElements -print(numberOfElements) // 4 +print(numberOfElements) // 4 (3 moderators + 1 admin) ``` Note that this code counts **all** child elements contained in `users`. Now suppose we want to get the number of moderators **only**. There are 2 different syntaxes. Once again, choose your favorite one : ```swift @@ -127,7 +128,7 @@ let numberOfElements: Int = parser["users"].elementsNamed("moderator").count ``` -- ### Type casting (>= 2.0.0) -CheatyXML allows you to cast tag/attribute values into some common types. You can get either optional or non-optinal value for your cast. +CheatyXML allows you to cast tag/attribute values into some common types. You can get either optional or non-optional value for your cast. ```swift let firstArticleRate = parser["article", 0]["rate"] firstArticleRate.int // Optional(42) @@ -145,7 +146,7 @@ firstArticleTitle.intValue // CRASH! ``` -- ### Missing tags -Until now, we always retrieved existing tags but what would happen if a tag doesn't exist ? Fortunaly for us, CheatyXML manages this case. Let's take an example : +Until now, we always retrieved existing tags but what would happen if a tag doesn't exist ? Fortunately for us, CheatyXML can handle this case. Let's take an example : ```swift let articleDate: String! = parser["article", 0]["infos"]["date"].stringValue print(articleDate) // 2015-03-15 15:42:42 @@ -153,7 +154,7 @@ let articleDateFail: String! = parser["articles", 0]["infos"]["date"].string // print(articleDateFail) // nil ``` > ###### Note -If you have doubts on your chain, keep in mind that using `.string` is safer than using `.stringValue`. In the previous example, using `.stringValue` on `articleDateFail` will result in your application to crash. +If you have any doubt, keep in mind that using `.string` is safer than using `.stringValue`. In the previous example, using `.stringValue` on `articleDateFail` will result in your application to crash. In sum, you can make mistakes without worrying about your application crash as long as you don't use `.stringValue`. @@ -178,7 +179,7 @@ let blogVersion = parser.rootElement.attribute("version").floatValue // 1.0 let creator = parser.rootElement.attribute("creator").stringValue // "lobodart" ``` > ###### Note -For more information about the optional/non-optional casting, please read the [Type casting][type-casting] part. +For more information about the optional/non-optional casting, please read the **Type casting** part. #### Get all Once uppon a time, it is very easy to get all the tag attributes. @@ -196,5 +197,3 @@ let attributes = parser.rootElement.attributes // Will give you a [String: Strin - [ ] Add more Unit Tests - [ ] Class mapping - [ ] XML Generator - -[type-casting]: [type-casting] From e5cf3dcd77e0d905e94fcf576c9b3b199aad1d78 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:00:46 +0200 Subject: [PATCH 15/21] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd507e9..bd1f1b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ -## 2.0.0 (July 17, 2016) +## 2.0 (July 17, 2016) -- Swift 3 ready +- Swift 3 Update - Fix small memory leak - Add type casting for tags/attributes - Change the way to retrieve attributes -- XMLElement has been renamed to XMLTag which inherit of XMLElement +- All classes are now prefixed by a 'C' (CXMLParser, ...) to clearly identify CheatyXML +- XMLElement has been renamed to CXMLTag which inherit of CXMLElement - Code refactoring (files now well separated) - Add Unit Test From cf8d9e98353ad39dae4ab3d46311af8d24f7cfd6 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:02:02 +0200 Subject: [PATCH 16/21] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e5d132b..207b714 100644 --- a/README.md +++ b/README.md @@ -44,18 +44,18 @@ Let's take the following XML content for all of our examples : ``` -There are different ways to create an instance of XMLParser. +There are different ways to create an instance of CXMLParser. ##### Using an URL ```swift -let parser: XMLParser! = XMLParser(contentsOfURL: ...) // NSURL +let parser: CXMLParser! = CXMLParser(contentsOfURL: ...) // NSURL ``` ##### Using a string ```swift -let parser: XMLParser! = XMLParser(string: ...) // String +let parser: CXMLParser! = CXMLParser(string: ...) // String ``` ##### Using data ```swift -let parser: XMLParser! = XMLParser(data: ...) // NSData +let parser: CXMLParser! = CXMLParser(data: ...) // NSData ``` -- ### Retrieving an element using tags @@ -185,7 +185,7 @@ For more information about the optional/non-optional casting, please read the ** Once uppon a time, it is very easy to get all the tag attributes. ##### >= 2.0.0 ```swift -let attributes = parser.rootElement.attributes // Will give you a [XMLAttribute] +let attributes = parser.rootElement.attributes // Will give you a [CXMLAttribute] let dic = attributes.dictionary // Will give you a [String: String] ``` ##### Earlier From 0c1b5715b8a5c0c94d20ff76f3416c0f09c55a76 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:05:05 +0200 Subject: [PATCH 17/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd1f1b6..1e83ed4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0 (July 17, 2016) +## 2.0.0 (July 17, 2016) - Swift 3 Update - Fix small memory leak From d5199d5cb1e7995b74a8951fa5d4af2d5a2ec2ae Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:05:20 +0200 Subject: [PATCH 18/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e83ed4..51aa995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0 (July 17, 2016) +## 2.0.0 (September 19, 2016) - Swift 3 Update - Fix small memory leak From e3beea5e961813b7a7c21e3ae941776c85c0cbb7 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:07:24 +0200 Subject: [PATCH 19/21] Final update Swift 3, version 2.0.0 --- CheatyXML.podspec | 6 +- CheatyXML.xcodeproj/project.pbxproj | 60 ++++--- ...XMLAttribute.swift => CXMLAttribute.swift} | 12 +- CheatyXML/CXMLElement.swift | 28 ++++ ...ttribute.swift => CXMLNullAttribute.swift} | 12 +- CheatyXML/CXMLNullTag.swift | 31 ++++ CheatyXML/CXMLParser.swift | 122 ++++++++++++++ CheatyXML/CXMLTag.swift | 152 +++++++++++++++++ CheatyXML/Info.plist | 4 +- CheatyXML/XMLElement.swift | 28 ---- CheatyXML/XMLNullTag.swift | 31 ---- CheatyXML/XMLParser.swift | 118 -------------- CheatyXML/XMLTag.swift | 153 ------------------ CheatyXMLTests/CheatyXMLTests.swift | 30 ++-- 14 files changed, 401 insertions(+), 386 deletions(-) rename CheatyXML/{XMLAttribute.swift => CXMLAttribute.swift} (61%) create mode 100644 CheatyXML/CXMLElement.swift rename CheatyXML/{XMLNullAttribute.swift => CXMLNullAttribute.swift} (52%) create mode 100644 CheatyXML/CXMLNullTag.swift create mode 100644 CheatyXML/CXMLParser.swift create mode 100644 CheatyXML/CXMLTag.swift delete mode 100644 CheatyXML/XMLElement.swift delete mode 100644 CheatyXML/XMLNullTag.swift delete mode 100644 CheatyXML/XMLParser.swift delete mode 100644 CheatyXML/XMLTag.swift diff --git a/CheatyXML.podspec b/CheatyXML.podspec index d48907c..c9103c9 100644 --- a/CheatyXML.podspec +++ b/CheatyXML.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| # s.name = "CheatyXML" - s.version = "1.3" + s.version = "2.0.0" s.summary = "CheatyXML" s.description = <<-DESC @@ -49,7 +49,7 @@ Pod::Spec.new do |s| # s.author = "Louis Bodart" - s.social_media_url = "http://twitter.com/lobodart" + s.social_media_url = "https://twitter.com/lobodart" # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # # @@ -66,7 +66,7 @@ Pod::Spec.new do |s| # Supports git, hg, bzr, svn and HTTP. # - s.source = { :git => "https://github.com/lobodart/CheatyXML.git", :tag => "v1.3" } + s.source = { :git => "https://github.com/lobodart/CheatyXML.git", :tag => "v2.0.0" } # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # diff --git a/CheatyXML.xcodeproj/project.pbxproj b/CheatyXML.xcodeproj/project.pbxproj index cfac0b0..b3c7f18 100644 --- a/CheatyXML.xcodeproj/project.pbxproj +++ b/CheatyXML.xcodeproj/project.pbxproj @@ -10,13 +10,13 @@ 486D48811AB4A19D004F6258 /* CheatyXML.h in Headers */ = {isa = PBXBuildFile; fileRef = 486D48801AB4A19D004F6258 /* CheatyXML.h */; settings = {ATTRIBUTES = (Public, ); }; }; 486D48871AB4A19D004F6258 /* CheatyXML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 486D487B1AB4A19D004F6258 /* CheatyXML.framework */; }; 486D488E1AB4A19D004F6258 /* CheatyXMLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */; }; - 486D48981AB4A1AF004F6258 /* XMLParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D48971AB4A1AF004F6258 /* XMLParser.swift */; }; + 486D48981AB4A1AF004F6258 /* CXMLParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486D48971AB4A1AF004F6258 /* CXMLParser.swift */; }; 4894F4EB1D3B5C6100BF093C /* TestFail.xml in Resources */ = {isa = PBXBuildFile; fileRef = 4894F4EA1D3B5C6100BF093C /* TestFail.xml */; }; - 48B018D71D3B629D00E31BE4 /* XMLTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018D61D3B629D00E31BE4 /* XMLTag.swift */; }; - 48B018D91D3B62CB00E31BE4 /* XMLNullTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018D81D3B62CB00E31BE4 /* XMLNullTag.swift */; }; - 48B018DB1D3B636900E31BE4 /* XMLElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DA1D3B636900E31BE4 /* XMLElement.swift */; }; - 48B018DD1D3B643800E31BE4 /* XMLAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DC1D3B643800E31BE4 /* XMLAttribute.swift */; }; - 48B018DF1D3B6E3500E31BE4 /* XMLNullAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DE1D3B6E3500E31BE4 /* XMLNullAttribute.swift */; }; + 48B018D71D3B629D00E31BE4 /* CXMLTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018D61D3B629D00E31BE4 /* CXMLTag.swift */; }; + 48B018D91D3B62CB00E31BE4 /* CXMLNullTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018D81D3B62CB00E31BE4 /* CXMLNullTag.swift */; }; + 48B018DB1D3B636900E31BE4 /* CXMLElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DA1D3B636900E31BE4 /* CXMLElement.swift */; }; + 48B018DD1D3B643800E31BE4 /* CXMLAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DC1D3B643800E31BE4 /* CXMLAttribute.swift */; }; + 48B018DF1D3B6E3500E31BE4 /* CXMLNullAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B018DE1D3B6E3500E31BE4 /* CXMLNullAttribute.swift */; }; 48CD10F61CCFEAD800A8CFAD /* Test.xml in Resources */ = {isa = PBXBuildFile; fileRef = 48CD10F51CCFEAD800A8CFAD /* Test.xml */; }; /* End PBXBuildFile section */ @@ -37,13 +37,13 @@ 486D48861AB4A19D004F6258 /* CheatyXMLTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CheatyXMLTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 486D488C1AB4A19D004F6258 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 486D488D1AB4A19D004F6258 /* CheatyXMLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatyXMLTests.swift; sourceTree = ""; }; - 486D48971AB4A1AF004F6258 /* XMLParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLParser.swift; sourceTree = ""; }; + 486D48971AB4A1AF004F6258 /* CXMLParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CXMLParser.swift; sourceTree = ""; }; 4894F4EA1D3B5C6100BF093C /* TestFail.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = TestFail.xml; sourceTree = ""; }; - 48B018D61D3B629D00E31BE4 /* XMLTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLTag.swift; sourceTree = ""; }; - 48B018D81D3B62CB00E31BE4 /* XMLNullTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLNullTag.swift; sourceTree = ""; }; - 48B018DA1D3B636900E31BE4 /* XMLElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLElement.swift; sourceTree = ""; }; - 48B018DC1D3B643800E31BE4 /* XMLAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLAttribute.swift; sourceTree = ""; }; - 48B018DE1D3B6E3500E31BE4 /* XMLNullAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLNullAttribute.swift; sourceTree = ""; }; + 48B018D61D3B629D00E31BE4 /* CXMLTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CXMLTag.swift; sourceTree = ""; }; + 48B018D81D3B62CB00E31BE4 /* CXMLNullTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CXMLNullTag.swift; sourceTree = ""; }; + 48B018DA1D3B636900E31BE4 /* CXMLElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CXMLElement.swift; sourceTree = ""; }; + 48B018DC1D3B643800E31BE4 /* CXMLAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CXMLAttribute.swift; sourceTree = ""; }; + 48B018DE1D3B6E3500E31BE4 /* CXMLNullAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CXMLNullAttribute.swift; sourceTree = ""; }; 48CD10F51CCFEAD800A8CFAD /* Test.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Test.xml; sourceTree = ""; }; 48F5B5041AB4ADAB00E68B10 /* Test.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Test.playground; sourceTree = ""; }; /* End PBXFileReference section */ @@ -90,12 +90,12 @@ isa = PBXGroup; children = ( 486D48801AB4A19D004F6258 /* CheatyXML.h */, - 486D48971AB4A1AF004F6258 /* XMLParser.swift */, - 48B018D61D3B629D00E31BE4 /* XMLTag.swift */, - 48B018DA1D3B636900E31BE4 /* XMLElement.swift */, - 48B018DC1D3B643800E31BE4 /* XMLAttribute.swift */, - 48B018DE1D3B6E3500E31BE4 /* XMLNullAttribute.swift */, - 48B018D81D3B62CB00E31BE4 /* XMLNullTag.swift */, + 486D48971AB4A1AF004F6258 /* CXMLParser.swift */, + 48B018D61D3B629D00E31BE4 /* CXMLTag.swift */, + 48B018DA1D3B636900E31BE4 /* CXMLElement.swift */, + 48B018DC1D3B643800E31BE4 /* CXMLAttribute.swift */, + 48B018DE1D3B6E3500E31BE4 /* CXMLNullAttribute.swift */, + 48B018D81D3B62CB00E31BE4 /* CXMLNullTag.swift */, 486D487E1AB4A19D004F6258 /* Supporting Files */, ); path = CheatyXML; @@ -191,9 +191,12 @@ TargetAttributes = { 486D487A1AB4A19D004F6258 = { CreatedOnToolsVersion = 6.2; + DevelopmentTeam = 58G6JMC92R; + LastSwiftMigration = 0800; }; 486D48851AB4A19D004F6258 = { CreatedOnToolsVersion = 6.2; + LastSwiftMigration = 0800; }; }; }; @@ -239,12 +242,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 48B018D71D3B629D00E31BE4 /* XMLTag.swift in Sources */, - 48B018DF1D3B6E3500E31BE4 /* XMLNullAttribute.swift in Sources */, - 486D48981AB4A1AF004F6258 /* XMLParser.swift in Sources */, - 48B018DB1D3B636900E31BE4 /* XMLElement.swift in Sources */, - 48B018DD1D3B643800E31BE4 /* XMLAttribute.swift in Sources */, - 48B018D91D3B62CB00E31BE4 /* XMLNullTag.swift in Sources */, + 48B018D71D3B629D00E31BE4 /* CXMLTag.swift in Sources */, + 48B018DF1D3B6E3500E31BE4 /* CXMLNullAttribute.swift in Sources */, + 486D48981AB4A1AF004F6258 /* CXMLParser.swift in Sources */, + 48B018DB1D3B636900E31BE4 /* CXMLElement.swift in Sources */, + 48B018DD1D3B643800E31BE4 /* CXMLAttribute.swift in Sources */, + 48B018D91D3B62CB00E31BE4 /* CXMLNullTag.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -356,7 +359,9 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 58G6JMC92R; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -364,9 +369,11 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = fr.louisbodart.CheatyXML; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -375,6 +382,7 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 58G6JMC92R; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -382,8 +390,10 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = fr.louisbodart.CheatyXML; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -401,6 +411,7 @@ INFOPLIST_FILE = CheatyXMLTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -414,6 +425,7 @@ INFOPLIST_FILE = CheatyXMLTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/CheatyXML/XMLAttribute.swift b/CheatyXML/CXMLAttribute.swift similarity index 61% rename from CheatyXML/XMLAttribute.swift rename to CheatyXML/CXMLAttribute.swift index 5bb1bb4..fe3ae44 100644 --- a/CheatyXML/XMLAttribute.swift +++ b/CheatyXML/CXMLAttribute.swift @@ -1,5 +1,5 @@ // -// XMLAttribute.swift +// CXMLAttribute.swift // CheatyXML // // Created by Louis BODART on 16/07/2016. @@ -8,16 +8,16 @@ import Foundation -public class XMLAttribute: XMLElement { +open class CXMLAttribute: CXMLElement { - public let name: String! + open let name: String! init(name: String!, value: String?) { self.name = name super.init(content: value) } - public override var description: String { - return "XMLAttribute" + open override var description: String { + return "CXMLAttribute" } -} \ No newline at end of file +} diff --git a/CheatyXML/CXMLElement.swift b/CheatyXML/CXMLElement.swift new file mode 100644 index 0000000..d335a9f --- /dev/null +++ b/CheatyXML/CXMLElement.swift @@ -0,0 +1,28 @@ +// +// CXMLElement.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +open class CXMLElement: NSObject { + + internal var _content: String? + + open var string: String? { get { return self._content } } + open var stringValue: String { get { return self.string! } } + open var int: Int? { get { return Int(self._content ?? "") ?? (self.double != nil ? Int(self.doubleValue) : nil) } } + open var intValue: Int { get { return self.int! } } + open var float: Float? { get { return Float(self._content ?? "") } } + open var floatValue: Float { get { return self.float! } } + open var double: Double? { get { return Double(self._content ?? "") } } + open var doubleValue: Double { get { return self.double! } } + + internal init(content: String?) { + self._content = content + super.init() + } +} diff --git a/CheatyXML/XMLNullAttribute.swift b/CheatyXML/CXMLNullAttribute.swift similarity index 52% rename from CheatyXML/XMLNullAttribute.swift rename to CheatyXML/CXMLNullAttribute.swift index 15ba768..2edd0ac 100644 --- a/CheatyXML/XMLNullAttribute.swift +++ b/CheatyXML/CXMLNullAttribute.swift @@ -1,5 +1,5 @@ // -// XMLNullAttribute.swift +// CXMLNullAttribute.swift // CheatyXML // // Created by Louis BODART on 17/07/2016. @@ -8,12 +8,12 @@ import Foundation -// MARK: - XMLNullAttribute Class -public class XMLNullAttribute: XMLAttribute { +// MARK: - CXMLNullAttribute Class +open class CXMLNullAttribute: CXMLAttribute { - public override var description: String { - return "XMLNullAttribute" + open override var description: String { + return "CXMLNullAttribute" } init() { super.init(name: nil, value: nil) } -} \ No newline at end of file +} diff --git a/CheatyXML/CXMLNullTag.swift b/CheatyXML/CXMLNullTag.swift new file mode 100644 index 0000000..aeeacc3 --- /dev/null +++ b/CheatyXML/CXMLNullTag.swift @@ -0,0 +1,31 @@ +// +// CXMLNullTag.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - CXMLNullTag Class +open class CXMLNullTag: CXMLTag { + + open override var description: String { + return "CXMLNullTag" + } + + init() { super.init(tagName: nil) } + + open override subscript(tagName: String) -> CXMLTag! { + get { return CXMLNullTag() } + } + + open override subscript(index: Int) -> CXMLTag! { + get { return CXMLNullTag() } + } + + open override subscript(tagName: String, index: Int) -> CXMLTag! { + get { return CXMLNullTag() } + } +} diff --git a/CheatyXML/CXMLParser.swift b/CheatyXML/CXMLParser.swift new file mode 100644 index 0000000..14f0840 --- /dev/null +++ b/CheatyXML/CXMLParser.swift @@ -0,0 +1,122 @@ +// +// CXMLParser.swift +// CheatyXML +// +// Created by Louis BODART on 14/03/2015. +// Copyright (c) 2015 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - CXMLParser Class +public class CXMLParser: NSObject, XMLParserDelegate { + + open var rootElement: CXMLTag! { + get { + return self._rootElement + } + } + + fileprivate let _xmlParser: Foundation.XMLParser! + fileprivate var _pointerTree: [OpaquePointer]! + fileprivate var _rootElement: CXMLTag! + fileprivate var _allocatedPointersList: [UnsafeMutablePointer] = [] + + public init?(contentsOfURL: URL) { + self._xmlParser = Foundation.XMLParser(contentsOf: contentsOfURL) + + super.init() + if !self.initXMLParser() { + return nil + } + } + + public init?(data: Data?) { + guard let data = data else { + return nil + } + + self._xmlParser = Foundation.XMLParser(data: data) + + super.init() + guard let _ = self._xmlParser else { + return nil + } + + if !self.initXMLParser() { + return nil + } + } + + public convenience init?(string: String) { + self.init(data: string.data(using: String.Encoding.utf8)) + } + + deinit { + for pointer in self._allocatedPointersList { + pointer.deallocate(capacity: 1) + } + } + + fileprivate func initXMLParser() -> Bool { + guard let _ = self._xmlParser else { + return false + } + + self._xmlParser.delegate = self + return self._xmlParser.parse() + } + + public final func parser(_ parser: Foundation.XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { + + let newElement: CXMLTag = CXMLTag(tagName: elementName) + if self._rootElement == nil { + self._rootElement = newElement + } + + if !attributeDict.isEmpty { + newElement._attributes = attributeDict.map({ (name: String, value: String) -> CXMLAttribute in + return CXMLAttribute(name: name, value: value) + }) + } + + if self._pointerTree == nil { + self._pointerTree = [] + } else { + let nps = UnsafeMutablePointer(self._pointerTree.last!) + newElement._parentElement = nps.pointee + nps.pointee.addSubElement(newElement) + } + + let ps = UnsafeMutablePointer.allocate(capacity: 1) + ps.initialize(to: newElement) + self._allocatedPointersList.append(ps) + let cps = OpaquePointer(ps) + self._pointerTree.append(cps) + } + + public final func parser(_ parser: Foundation.XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { + self._pointerTree.removeLast() + } + + public final func parser(_ parser: Foundation.XMLParser, foundCharacters string: String) { + let nps = UnsafeMutablePointer(self._pointerTree.last!) + var tmpString: String! = nps.pointee._content ?? "" + tmpString! += string + + let regex: NSRegularExpression = try! NSRegularExpression(pattern: "[^\\n\\s]+", options: []) + if regex.matches(in: tmpString, options: [], range: NSMakeRange(0, tmpString.characters.count)).count <= 0 { + tmpString = nil + } + + nps.pointee._content = tmpString + } + + open subscript(tagName: String) -> CXMLTag! { + return self._rootElement[tagName] + } + + open subscript(tagName: String, index: Int) -> CXMLTag! { + return self._rootElement[tagName, index] + } +} diff --git a/CheatyXML/CXMLTag.swift b/CheatyXML/CXMLTag.swift new file mode 100644 index 0000000..98e2a30 --- /dev/null +++ b/CheatyXML/CXMLTag.swift @@ -0,0 +1,152 @@ +// +// CXMLTag.swift +// CheatyXML +// +// Created by Louis BODART on 16/07/2016. +// Copyright © 2016 Louis BODART. All rights reserved. +// + +import Foundation + +// MARK: - CXMLTag Class +open class CXMLTag: CXMLElement, Sequence, IteratorProtocol { + + open let tagName: String! + open var attributes: [CXMLAttribute] { + get { + return self._attributes + } + } + + open var count: Int { + get { + guard let _ = self._parentElement else { + return 1 + } + + let array: [CXMLTag] = self._parentElement.arrayOfElementsNamed(self.tagName) + return array.count + } + } + + open var numberOfChildElements: Int { + get { + return self._subElements.count + } + } + + internal var _subElements: [CXMLTag] = [] + internal var _parentElement: CXMLTag! + internal var _attributes: [CXMLAttribute] = [] + internal var _generatorIndex: Int = 0 + + open override var debugDescription: String { get { return self.description } } + open override var description: String { + return "CXMLTag <\(self.tagName)>, attributes(\(self.attributes.count)): \(self.attributes), children: \(self._subElements.count)" + } + + open var exists: Bool { get { return !(self is CXMLNullTag) } } + + open var array: [CXMLTag] { get { return self._parentElement?.arrayOfElementsNamed(self.tagName) ?? self._subElements } } + + open func date(_ format: String) -> Date? { + guard let content = self._content else { + return nil + } + + let dateFormat = DateFormatter() + dateFormat.dateFormat = format + return dateFormat.date(from: content) + } + + open func dateValue(_ format: String) -> Date { + return self.date(format)! + } + + open func makeIterator() -> CXMLTag { + self._generatorIndex = 0 + return self + } + + open func next() -> CXMLTag? { + if self._generatorIndex < 0 || self._generatorIndex >= self._subElements.count { + return nil + } + + defer { self._generatorIndex += 1 } + + return self._subElements[self._generatorIndex] + } + + open func elementsNamed(_ name: String) -> [CXMLTag] { + return self.arrayOfElementsNamed(name) + } + + open func attribute(_ name: String) -> CXMLAttribute { + guard let index = self._attributes.index(where: { (attribute) -> Bool in + return attribute.name == name + }) else { + return CXMLNullAttribute() + } + + return self._attributes[index] + } + + fileprivate final func arrayOfElementsNamed(_ tagName: String) -> [CXMLTag] { + return self._subElements.filter({(element: CXMLTag) -> Bool in + return element.tagName == tagName + }) + } + + internal final func addSubElement(_ subElement: CXMLTag) { + self._subElements.append(subElement) + } + + init(tagName: String!) { + self.tagName = tagName + super.init(content: nil) + } + + open subscript(tagName: String) -> CXMLTag! { + get { + return self[tagName, 0] + } + } + + open subscript(index: Int) -> CXMLTag! { + get { + return self._parentElement[self.tagName, index] + } + } + + open subscript(tagName: String, index: Int) -> CXMLTag! { + get { + if index < 0 { + return CXMLNullTag() + } + + let array = self._subElements.filter({(element: CXMLTag) -> Bool in + return element.tagName == tagName + }) + + if index >= array.count { + return CXMLNullTag() + } + + return array[index] + } + } +} + +public extension Sequence where Iterator.Element: CXMLAttribute { + + public final var dictionary: [String: String] { + get { + return self.reduce([:], { (dict: [String: String], value: CXMLAttribute) -> [String: String] in + var newDict = dict + newDict[value.name] = value._content ?? "" + return newDict + }) + } + } +} diff --git a/CheatyXML/Info.plist b/CheatyXML/Info.plist index 74ff320..24ee2dd 100644 --- a/CheatyXML/Info.plist +++ b/CheatyXML/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - RealmTeam.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.0 + 2.0.0 CFBundleSignature ???? CFBundleVersion diff --git a/CheatyXML/XMLElement.swift b/CheatyXML/XMLElement.swift deleted file mode 100644 index 1fae6d9..0000000 --- a/CheatyXML/XMLElement.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// XMLElement.swift -// CheatyXML -// -// Created by Louis BODART on 16/07/2016. -// Copyright © 2016 Louis BODART. All rights reserved. -// - -import Foundation - -public class XMLElement: NSObject { - - internal var _content: String? - - public var string: String? { get { return self._content } } - public var stringValue: String { get { return self.string! } } - public var int: Int? { get { return Int(self._content ?? "") ?? (self.double != nil ? Int(self.doubleValue) : nil) } } - public var intValue: Int { get { return self.int! } } - public var float: Float? { get { return Float(self._content ?? "") } } - public var floatValue: Float { get { return self.float! } } - public var double: Double? { get { return Double(self._content ?? "") } } - public var doubleValue: Double { get { return self.double! } } - - internal init(content: String?) { - self._content = content - super.init() - } -} \ No newline at end of file diff --git a/CheatyXML/XMLNullTag.swift b/CheatyXML/XMLNullTag.swift deleted file mode 100644 index 93bb593..0000000 --- a/CheatyXML/XMLNullTag.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// XMLNullTag.swift -// CheatyXML -// -// Created by Louis BODART on 16/07/2016. -// Copyright © 2016 Louis BODART. All rights reserved. -// - -import Foundation - -// MARK: - XMLNullTag Class -public class XMLNullTag: XMLTag { - - public override var description: String { - return "XMLNullTag" - } - - init() { super.init(tagName: nil) } - - public override subscript(tagName: String) -> XMLTag! { - get { return XMLNullTag() } - } - - public override subscript(index: Int) -> XMLTag! { - get { return XMLNullTag() } - } - - public override subscript(tagName: String, index: Int) -> XMLTag! { - get { return XMLNullTag() } - } -} \ No newline at end of file diff --git a/CheatyXML/XMLParser.swift b/CheatyXML/XMLParser.swift deleted file mode 100644 index 262b754..0000000 --- a/CheatyXML/XMLParser.swift +++ /dev/null @@ -1,118 +0,0 @@ -// -// CheatyXML.swift -// CheatyXML -// -// Created by Louis BODART on 14/03/2015. -// Copyright (c) 2015 Louis BODART. All rights reserved. -// - -import Foundation - -// MARK: - XMLParser Class -public class XMLParser: NSObject, NSXMLParserDelegate { - - public var rootElement: XMLTag! { - get { - return self._rootElement - } - } - - private let _xmlParser: NSXMLParser! - private var _pointerTree: [COpaquePointer]! - private var _rootElement: XMLTag! - private var _allocatedPointersList: [UnsafeMutablePointer] = [] - - public init?(contentsOfURL: NSURL) { - self._xmlParser = NSXMLParser(contentsOfURL: contentsOfURL) - - super.init() - if !self.initXMLParser() { - return nil - } - } - - public init?(data: NSData!) { - self._xmlParser = data != nil ? NSXMLParser(data: data) : nil - - super.init() - guard let _ = self._xmlParser else { - return nil - } - - if !self.initXMLParser() { - return nil - } - } - - public convenience init?(string: String) { - self.init(data: NSString(string: string).dataUsingEncoding(NSUTF8StringEncoding)) - } - - deinit { - for pointer in self._allocatedPointersList { - pointer.dealloc(1) - } - } - - private func initXMLParser() -> Bool { - guard let _ = self._xmlParser else { - return false - } - - self._xmlParser.delegate = self - return self._xmlParser.parse() - } - - public final func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { - - let newElement: XMLTag = XMLTag(tagName: elementName) - if self._rootElement == nil { - self._rootElement = newElement - } - - if !attributeDict.isEmpty { - newElement._attributes = attributeDict.map({ (name: String, value: String) -> XMLAttribute in - return XMLAttribute(name: name, value: value) - }) - } - - if self._pointerTree == nil { - self._pointerTree = [] - } else { - let nps = UnsafeMutablePointer(self._pointerTree.last!) - newElement._parentElement = nps.memory - nps.memory.addSubElement(newElement) - } - - let ps = UnsafeMutablePointer.alloc(1) - ps.initialize(newElement) - self._allocatedPointersList.append(ps) - let cps = COpaquePointer(ps) - self._pointerTree.append(cps) - } - - public final func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { - self._pointerTree.removeLast() - } - - public final func parser(parser: NSXMLParser, foundCharacters string: String) { - let nps = UnsafeMutablePointer(self._pointerTree.last!) - var tmpString: String! = nps.memory._content ?? "" - tmpString! += string - - let regex: NSRegularExpression = try! NSRegularExpression(pattern: "[^\\n\\s]+", options: []) - if regex.matchesInString(tmpString, options: [], range: NSMakeRange(0, tmpString.characters.count)).count <= 0 { - tmpString = nil - } - - nps.memory._content = tmpString - } - - public subscript(tagName: String) -> XMLTag! { - return self._rootElement[tagName] - } - - public subscript(tagName: String, index: Int) -> XMLTag! { - return self._rootElement[tagName, index] - } -} \ No newline at end of file diff --git a/CheatyXML/XMLTag.swift b/CheatyXML/XMLTag.swift deleted file mode 100644 index 28dceb1..0000000 --- a/CheatyXML/XMLTag.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// XMLTag.swift -// CheatyXML -// -// Created by Louis BODART on 16/07/2016. -// Copyright © 2016 Louis BODART. All rights reserved. -// - -import Foundation - -// MARK: - XMLTag Class -public class XMLTag: XMLElement, SequenceType, GeneratorType { - - public let tagName: String! - public var attributes: [XMLAttribute] { - get { - return self._attributes - } - } - - public var count: Int { - get { - guard let _ = self._parentElement else { - return 1 - } - - let array: [XMLTag] = self._parentElement.arrayOfElementsNamed(self.tagName) - return array.count - } - } - - public var numberOfChildElements: Int { - get { - return self._subElements.count - } - } - - internal var _subElements: [XMLTag] = [] - internal var _parentElement: XMLTag! - internal var _attributes: [XMLAttribute] = [] - internal var _generatorIndex: Int = 0 - - public override var debugDescription: String { get { return self.description } } - public override var description: String { - return "XMLTag <\(self.tagName)>, attributes(\(self.attributes.count ?? 0)): \(self.attributes), children: \(self._subElements.count)" - } - - public var exists: Bool { get { return !(self is XMLNullTag) } } - - public var array: [XMLTag] { get { return self._parentElement?.arrayOfElementsNamed(self.tagName) ?? self._subElements } } - - public func date(format: String) -> NSDate? { - guard let content = self._content else { - return nil - } - - let dateFormat = NSDateFormatter() - dateFormat.dateFormat = format - return dateFormat.dateFromString(content) - } - - public func dateValue(format: String) -> NSDate { - return self.date(format)! - } - - public func generate() -> XMLTag { - self._generatorIndex = 0 - return self - } - - public func next() -> XMLTag? { - if self._generatorIndex < 0 || self._generatorIndex >= self._subElements.count { - return nil - } - - let currentIndex: Int = self._generatorIndex - self._generatorIndex += 1 - - return self._subElements[currentIndex] - } - - public func elementsNamed(name: String) -> [XMLTag] { - return self.arrayOfElementsNamed(name) - } - - public func attribute(name: String) -> XMLAttribute { - guard let index = self._attributes.indexOf({ (attribute) -> Bool in - return attribute.name == name - }) else { - return XMLNullAttribute() - } - - return self._attributes[index] - } - - private final func arrayOfElementsNamed(tagName: String) -> [XMLTag] { - return self._subElements.filter({(element: XMLTag) -> Bool in - return element.tagName == tagName - }) - } - - internal final func addSubElement(subElement: XMLTag) { - self._subElements.append(subElement) - } - - init(tagName: String!) { - self.tagName = tagName - super.init(content: nil) - } - - public subscript(tagName: String) -> XMLTag! { - get { - return self[tagName, 0] - } - } - - public subscript(index: Int) -> XMLTag! { - get { - return self._parentElement[self.tagName, index] - } - } - - public subscript(tagName: String, index: Int) -> XMLTag! { - get { - if index < 0 { - return XMLNullTag() - } - - let array = self._subElements.filter({(element: XMLTag) -> Bool in - return element.tagName == tagName - }) - - if index >= array.count { - return XMLNullTag() - } - - return array[index] - } - } -} - -public extension SequenceType where Generator.Element: XMLAttribute { - - public final var dictionary: [String: String] { - get { - return self.reduce([:], combine: { (dict: [String: String], value: XMLAttribute) -> [String: String] in - var newDict = dict - newDict[value.name] = value._content ?? "" - return newDict - }) - } - } -} \ No newline at end of file diff --git a/CheatyXMLTests/CheatyXMLTests.swift b/CheatyXMLTests/CheatyXMLTests.swift index 1e1006c..397f1ee 100644 --- a/CheatyXMLTests/CheatyXMLTests.swift +++ b/CheatyXMLTests/CheatyXMLTests.swift @@ -18,10 +18,10 @@ class CheatyXMLTests: XCTestCase { override func setUp() { super.setUp() - self.filePath = NSBundle(forClass: self.dynamicType).pathForResource("Test", ofType: "xml") + self.filePath = Bundle(for: type(of: self)).path(forResource: "Test", ofType: "xml") XCTAssert(self.filePath != nil) - self.failFilePath = NSBundle(forClass: self.dynamicType).pathForResource("TestFail", ofType: "xml") + self.failFilePath = Bundle(for: type(of: self)).path(forResource: "TestFail", ofType: "xml") XCTAssert(self.failFilePath != nil) self.continueAfterFailure = false @@ -33,22 +33,22 @@ class CheatyXMLTests: XCTestCase { } func testConstructor() { - let failParser: XMLParser? = XMLParser(contentsOfURL: NSURL(fileURLWithPath: self.failFilePath)) + let failParser: CXMLParser? = CXMLParser(contentsOfURL: URL(fileURLWithPath: self.failFilePath)) XCTAssert(failParser == nil) - let url: NSURL = NSURL(fileURLWithPath: self.filePath) - let urlParser: XMLParser! = XMLParser(contentsOfURL: url) + let url: URL = URL(fileURLWithPath: self.filePath) + let urlParser: CXMLParser! = CXMLParser(contentsOfURL: url) XCTAssert(urlParser != nil) do { let content: String = try String(contentsOfFile: self.filePath) - let stringParser: XMLParser! = XMLParser(string: content) + let stringParser: CXMLParser! = CXMLParser(string: content) XCTAssert(stringParser != nil) - let data: NSData! = NSData(contentsOfURL: url) + let data: Data! = try? Data(contentsOf: url) XCTAssert(data != nil) - let dataParser: XMLParser! = XMLParser(data: data) + let dataParser: CheatyXML.XMLParser! = CheatyXML.XMLParser(data: data) XCTAssert(dataParser != nil) } catch { XCTAssert(false) @@ -56,8 +56,8 @@ class CheatyXMLTests: XCTestCase { } func testTagRetrieving() { - let url: NSURL = NSURL(fileURLWithPath: self.filePath) - let parser: XMLParser = XMLParser(contentsOfURL: url)! + let url: URL = URL(fileURLWithPath: self.filePath) + let parser: CXMLParser = CXMLParser(contentsOfURL: url)! let blogName: String! = parser["name"].stringValue XCTAssert(blogName == "MyAwesomeBlog!") @@ -79,8 +79,8 @@ class CheatyXMLTests: XCTestCase { } func testTypeCasts() { - let url: NSURL = NSURL(fileURLWithPath: self.filePath) - let parser: XMLParser = XMLParser(contentsOfURL: url)! + let url: URL = URL(fileURLWithPath: self.filePath) + let parser: CXMLParser = CXMLParser(contentsOfURL: url)! let articles = parser["article"].array XCTAssert(articles.count == 2) @@ -91,7 +91,7 @@ class CheatyXMLTests: XCTestCase { XCTAssert(article["read"].intValue == 324) XCTAssert(article["rate"].floatValue == 4.3) XCTAssert(article["rate"].doubleValue == 4.3) - XCTAssert(article["date"].dateValue("yyyy-MM-dd HH:mm:ss").isKindOfClass(NSDate)) + XCTAssert(article["date"].dateValue("yyyy-MM-dd HH:mm:ss") is Date) XCTAssert(article["title"].exists == true) @@ -105,8 +105,8 @@ class CheatyXMLTests: XCTestCase { } func testAttributeRetrieving() { - let url: NSURL = NSURL(fileURLWithPath: self.filePath) - let parser: XMLParser = XMLParser(contentsOfURL: url)! + let url: URL = URL(fileURLWithPath: self.filePath) + let parser: CXMLParser = CXMLParser(contentsOfURL: url)! XCTAssert(parser.rootElement.attributes.count == 2) XCTAssert(parser.rootElement.attribute("version").stringValue == "1.0") From 8e3e927bb080660e6826e3068411d6b4b2a9089a Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:15:52 +0200 Subject: [PATCH 20/21] Changing TravisCI Xcode version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f2c582..aa19da3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: objective-c -osx_image: xcode7.1 +osx_image: xcode8 xcode_sdk: iphonesimulator9.0 script: From 580d78e79ef059e90725c2058afcb808bea24731 Mon Sep 17 00:00:00 2001 From: Louis Bodart Date: Mon, 19 Sep 2016 15:27:21 +0200 Subject: [PATCH 21/21] Adding Swift version file, Lint OK, Merge rdy --- .swift-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..f398a20 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 \ No newline at end of file