Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds subrange indexer for XMLElement #174

Merged
merged 5 commits into from
Feb 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Source/SWXMLHash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,43 @@ public enum XMLIndexer {
}
}

public func filter(_ included: (_ elem: XMLElement, _ index: Int) -> Bool) -> XMLIndexer {
switch self {
case .list(let list):
let results = filterWithIndex(seq: list, included: included)
if results.count == 1 {
return XMLIndexer.element(results.first!)
}
return XMLIndexer.list(results)

case .element(let elem):
return XMLIndexer.list(filterWithIndex(seq: elem.xmlChildren, included: included))

case .stream(let ops):
let found = ops.findElements()

let list: [XMLElement]
if found.all.count == 1 {
list = found.children.map { $0.element! }
} else {
list = found.all.map { $0.element! }
}
let results = filterWithIndex(seq: list, included: included)
if results.count == 1 {
return XMLIndexer.element(results.first!)
}
return XMLIndexer.list(results)

default:
return XMLIndexer.list([])
}
}

private func filterWithIndex(seq: [XMLElement],
included: (_ elem: XMLElement, _ index: Int) -> Bool) -> [XMLElement] {
return zip(seq.indices, seq).filter { included($1, $0) }.map { $1 }
}

/// All child elements from the currently indexed level
public var children: [XMLIndexer] {
var list = [XMLIndexer]()
Expand Down Expand Up @@ -867,6 +904,7 @@ public class XMLElement: XMLContent {
- parameters:
- name: The name of the element to be initialized
- index: The index of the element to be initialized
- options: The SWXMLHash options
*/
init(name: String, index: Int = 0, options: SWXMLHashOptions) {
self.name = name
Expand Down
17 changes: 16 additions & 1 deletion Tests/SWXMLHashTests/LazyXMLParsingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ class LazyXMLParsingTests: XCTestCase {
func testShouldReturnNilWhenKeysDontMatch() {
XCTAssertNil(xml!["root"]["what"]["header"]["foo"].element?.name)
}

func testShouldBeAbleToFilterOnIndexer() {
let subIndexer = xml!["root"]["catalog"]["book"]
.filter { elem, _ in elem.attribute(by: "id")!.text == "bk102" }
.filter { _, index in index >= 1 && index <= 3 }

XCTAssertEqual(subIndexer[0].element?.name, "title")
XCTAssertEqual(subIndexer[1].element?.name, "genre")
XCTAssertEqual(subIndexer[2].element?.name, "price")

XCTAssertEqual(subIndexer[0].element?.text, "Midnight Rain")
XCTAssertEqual(subIndexer[1].element?.text, "Fantasy")
XCTAssertEqual(subIndexer[2].element?.text, "5.95")
}
}

extension LazyXMLParsingTests {
Expand All @@ -158,7 +172,8 @@ extension LazyXMLParsingTests {
("testShouldBeAbleToHandleMixedContent", testShouldBeAbleToHandleMixedContent),
("testShouldHandleInterleavingXMLElements", testShouldHandleInterleavingXMLElements),
("testShouldBeAbleToProvideADescriptionForTheDocument", testShouldBeAbleToProvideADescriptionForTheDocument),
("testShouldReturnNilWhenKeysDontMatch", testShouldReturnNilWhenKeysDontMatch)
("testShouldReturnNilWhenKeysDontMatch", testShouldReturnNilWhenKeysDontMatch),
("testShouldBeAbleToFilterOnIndexer", testShouldBeAbleToFilterOnIndexer)
]
}
}
45 changes: 44 additions & 1 deletion Tests/SWXMLHashTests/XMLParsingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,47 @@ class XMLParsingTests: XCTestCase {
}
XCTAssertNotNil(err)
}

func testShouldBeAbleToCreateASubIndexer() {
let subIndexer = xml!["root"]["catalog"]["book"][1].filter { _, index in index >= 1 && index <= 3 }

XCTAssertEqual(subIndexer[0].element?.name, "title")
XCTAssertEqual(subIndexer[1].element?.name, "genre")
XCTAssertEqual(subIndexer[2].element?.name, "price")

XCTAssertEqual(subIndexer[0].element?.text, "Midnight Rain")
XCTAssertEqual(subIndexer[1].element?.text, "Fantasy")
XCTAssertEqual(subIndexer[2].element?.text, "5.95")
}

func testShouldBeAbleToCreateASubIndexerFromFilter() {
let subIndexer = xml!["root"]["catalog"]["book"][1].filter { elem, _ in
let filterByNames = ["title", "genre", "price"]
return filterByNames.contains(elem.name)
}

XCTAssertEqual(subIndexer[0].element?.name, "title")
XCTAssertEqual(subIndexer[1].element?.name, "genre")
XCTAssertEqual(subIndexer[2].element?.name, "price")

XCTAssertEqual(subIndexer[0].element?.text, "Midnight Rain")
XCTAssertEqual(subIndexer[1].element?.text, "Fantasy")
XCTAssertEqual(subIndexer[2].element?.text, "5.95")
}

func testShouldBeAbleToFilterOnIndexer() {
let subIndexer = xml!["root"]["catalog"]["book"]
.filter { elem, _ in elem.attribute(by: "id")!.text == "bk102" }
.filter { _, index in index >= 1 && index <= 3 }

XCTAssertEqual(subIndexer[0].element?.name, "title")
XCTAssertEqual(subIndexer[1].element?.name, "genre")
XCTAssertEqual(subIndexer[2].element?.name, "price")

XCTAssertEqual(subIndexer[0].element?.text, "Midnight Rain")
XCTAssertEqual(subIndexer[1].element?.text, "Fantasy")
XCTAssertEqual(subIndexer[2].element?.text, "5.95")
}
}

extension XMLParsingTests {
Expand All @@ -269,7 +310,9 @@ extension XMLParsingTests {
("testShouldReturnNilWhenKeysDontMatch", testShouldReturnNilWhenKeysDontMatch),
("testShouldProvideAnErrorObjectWhenKeysDontMatch", testShouldProvideAnErrorObjectWhenKeysDontMatch),
("testShouldProvideAnErrorElementWhenIndexersDontMatch", testShouldProvideAnErrorElementWhenIndexersDontMatch),
("testShouldStillReturnErrorsWhenAccessingViaSubscripting", testShouldStillReturnErrorsWhenAccessingViaSubscripting)
("testShouldStillReturnErrorsWhenAccessingViaSubscripting", testShouldStillReturnErrorsWhenAccessingViaSubscripting),
("testShouldBeAbleToCreateASubIndexerFromFilter", testShouldBeAbleToCreateASubIndexerFromFilter),
("testShouldBeAbleToFilterOnIndexer", testShouldBeAbleToFilterOnIndexer)
]
}
}