Skip to content

Commit

Permalink
Merge pull request #174 from hibento/feature/XMLIndexer-Subrange
Browse files Browse the repository at this point in the history
Adds subrange indexer for XMLElement
  • Loading branch information
drmohundro authored Feb 4, 2018
2 parents 991ff20 + 9d4f07d commit 0b18f5b
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
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)
]
}
}

0 comments on commit 0b18f5b

Please sign in to comment.