diff --git a/.gitignore b/.gitignore index 077c4bc..b3ed1ff 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ playground.xcworkspace # Package.pins # Package.resolved .build/ +.swiftpm/ # CocoaPods # diff --git a/SwiftyXMLParser/Element.swift b/SwiftyXMLParser/Element.swift index b46b1cc..4bd3bfa 100755 --- a/SwiftyXMLParser/Element.swift +++ b/SwiftyXMLParser/Element.swift @@ -30,6 +30,9 @@ extension XML { open var text: String? open var attributes = [String: String]() open var childElements = [Element]() + open var lineNumberStart = -1 + open var lineNumberEnd = -1 + open var CDATA: Data? // for println open weak var parentElement: Element? diff --git a/SwiftyXMLParser/Parser.swift b/SwiftyXMLParser/Parser.swift index 97af9b8..09930c2 100755 --- a/SwiftyXMLParser/Parser.swift +++ b/SwiftyXMLParser/Parser.swift @@ -62,6 +62,7 @@ extension XML { func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { let node = Element(name: elementName) + node.lineNumberStart = parser.lineNumber if !attributeDict.isEmpty { node.attributes = attributeDict } @@ -80,8 +81,13 @@ extension XML { stack.last?.text = "" + string } } + + func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) { + stack.last?.CDATA = CDATABlock + } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { + stack.last?.lineNumberEnd = parser.lineNumber if let trimmingManner = self.trimmingManner { stack.last?.text = stack.last?.text?.trimmingCharacters(in: trimmingManner) } diff --git a/SwiftyXMLParserTests/ParserTests.swift b/SwiftyXMLParserTests/ParserTests.swift index 7635b14..4b7db0c 100755 --- a/SwiftyXMLParserTests/ParserTests.swift +++ b/SwiftyXMLParserTests/ParserTests.swift @@ -27,6 +27,11 @@ import XCTest class ParserTests: XCTestCase { + fileprivate let packageRootPath = URL(fileURLWithPath: #file) + .pathComponents + .dropLast() + .joined(separator: "/") + .dropFirst() override func setUp() { super.setUp() @@ -35,12 +40,15 @@ class ParserTests: XCTestCase { override func tearDown() { super.tearDown() } + + private func getPath(_ name: String) -> String { + "\(packageRootPath)/\(name)" + } func testSuccessParse() { - guard let path = Bundle(for: type(of: self)).path(forResource: "XMLDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("XMLDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser().parse(data) @@ -54,10 +62,9 @@ class ParserTests: XCTestCase { } func testFailParse() { - guard let path = Bundle(for: type(of: self)).path(forResource: "BrokenXMLDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("BrokenXMLDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser().parse(data) @@ -69,10 +76,9 @@ class ParserTests: XCTestCase { } func testTextParseWithMockData() { - guard let path = Bundle(for: type(of: self)).path(forResource: "SimpleDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("SimpleDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser().parse(data) @@ -84,10 +90,9 @@ class ParserTests: XCTestCase { } func testWhitespaceParseWithMockData() { - guard let path = Bundle(for: type(of: self)).path(forResource: "SimpleDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("SimpleDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser().parse(data) @@ -99,10 +104,9 @@ class ParserTests: XCTestCase { } func testReturnParseWithMockData() { - guard let path = Bundle(for: type(of: self)).path(forResource: "SimpleDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("SimpleDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser().parse(data) @@ -114,10 +118,9 @@ class ParserTests: XCTestCase { } func testWhitespaceAndReturnParseWithMockData() { - guard let path = Bundle(for: type(of: self)).path(forResource: "SimpleDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("SimpleDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser().parse(data) @@ -130,10 +133,9 @@ class ParserTests: XCTestCase { } func testWhitespaceAndReturnParseWithMockDataAndTrimmingWhitespaceAndLineBreak() { - guard let path = Bundle(for: type(of: self)).path(forResource: "SimpleDocument", ofType: "xml"), - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - XCTFail("fail to parse") - return + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("SimpleDocument.xml"))) else { + XCTFail("fail to parse") + return } let xml = XML.Parser(trimming: .whitespacesAndNewlines).parse(data) @@ -160,4 +162,19 @@ class ParserTests: XCTestCase { let xml = XML.Parser().parse(str.data(using: .utf8)!) XCTAssertEqual("@ß123\u{1c}", xml["xmlopening"].text?.removingPercentEncoding, "Parsed Success and trim them") } + + func testLineNumbers() { + guard let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("SimpleDocument.xml"))) else { + XCTFail("fail to parse") + return + } + + let xml = XML.Parser().parse(data) + guard let whitespaceReturnElement = xml["Result"]["WhitespaceReturn"].element else { + XCTFail("Element not found") + return + } + XCTAssertEqual(whitespaceReturnElement.lineNumberStart, 4) + XCTAssertEqual(whitespaceReturnElement.lineNumberEnd, 6) + } } diff --git a/SwiftyXMLParserTests/XMLTests.swift b/SwiftyXMLParserTests/XMLTests.swift index 28e82c7..4259f05 100755 --- a/SwiftyXMLParserTests/XMLTests.swift +++ b/SwiftyXMLParserTests/XMLTests.swift @@ -26,37 +26,41 @@ import XCTest @testable import SwiftyXMLParser class XMLTests: XCTestCase { + fileprivate let packageRootPath = URL(fileURLWithPath: #file) + .pathComponents + .dropLast() + .joined(separator: "/") + .dropFirst() override func setUp() { super.setUp() } - + override func tearDown() { super.tearDown() } + private func getPath(_ name: String) -> String { + "\(packageRootPath)/\(name)" + } + func testParse() { - if let path = Bundle(for: type(of: self)).path(forResource: "XMLDocument", ofType: "xml") { - if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) { - let xml = XML.parse(data) - if let _ = xml["ResultSet"].error { - XCTFail("fail to parse") + if let data = try? Data(contentsOf: URL(fileURLWithPath: getPath("XMLDocument.xml"))) { + let xml = XML.parse(data) + if let _ = xml["ResultSet"].error { + XCTFail("fail to parse") - } else { - XCTAssert(true, "sucess to Parse") - } } else { - XCTFail("fail to generate data") + XCTAssert(true, "sucess to Parse") } } else { - XCTFail("fail to parse") + XCTFail("fail to generate data") } } func testSuccessParseFromString() { - if let path = Bundle(for: type(of: self)).path(forResource: "XMLDocument", ofType: "xml"), - let string = try? String(contentsOfFile: path, encoding: String.Encoding.utf8), + if let string = try? String(contentsOfFile: getPath("XMLDocument.xml"), encoding: String.Encoding.utf8), let xml = try? XML.parse(string) { if let _ = xml["ResultSet"].error { XCTFail("fail to parse") @@ -81,5 +85,4 @@ class XMLTests: XCTestCase { XCTFail("Fail Parse") } } - }