Skip to content

Commit

Permalink
Merge pull request #171 from drmohundro/add-userinfo-support
Browse files Browse the repository at this point in the history
Add userInfo support
  • Loading branch information
drmohundro authored Jan 15, 2018
2 parents 6d2b827 + a2511c1 commit a90a62e
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 12 deletions.
39 changes: 30 additions & 9 deletions Source/SWXMLHash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public class SWXMLHashOptions {

/// Encoding used for XML parsing. Default is set to UTF8
public var encoding = String.Encoding.utf8

/// Any contextual information set by the user for encoding
public var userInfo = [CodingUserInfoKey: Any]()
}

/// Simple XML parser
Expand Down Expand Up @@ -250,12 +253,12 @@ extension XMLParserDelegate {
/// The implementation of XMLParserDelegate and where the lazy parsing actually happens.
class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
required init(_ options: SWXMLHashOptions) {
root = XMLElement(name: rootElementName, options: options)
self.options = options
self.root.caseInsensitive = options.caseInsensitive
super.init()
}

var root = XMLElement(name: rootElementName, caseInsensitive: false)
let root: XMLElement
var parentStack = Stack<XMLElement>()
var elementStack = Stack<String>()

Expand All @@ -272,7 +275,6 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
// clear any prior runs of parse... expected that this won't be necessary,
// but you never know
parentStack.removeAll()
root = XMLElement(name: rootElementName, caseInsensitive: options.caseInsensitive)
parentStack.push(root)

self.ops = ops
Expand Down Expand Up @@ -338,12 +340,12 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
/// The implementation of XMLParserDelegate and where the parsing actually happens.
class FullXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
required init(_ options: SWXMLHashOptions) {
root = XMLElement(name: rootElementName, options: options)
self.options = options
self.root.caseInsensitive = options.caseInsensitive
super.init()
}

var root = XMLElement(name: rootElementName, caseInsensitive: false)
let root: XMLElement
var parentStack = Stack<XMLElement>()
let options: SWXMLHashOptions

Expand Down Expand Up @@ -556,6 +558,15 @@ public enum XMLIndexer {
return list
}

public var userInfo: [CodingUserInfoKey: Any] {
switch self {
case .element(let elem):
return elem.userInfo
default:
return [:]
}
}

/**
Allows for element lookup by matching attribute values.

Expand Down Expand Up @@ -775,11 +786,19 @@ public class XMLElement: XMLContent {
/// The name of the element
public let name: String

public var caseInsensitive: Bool
/// Whether the element is case insensitive or not
public var caseInsensitive: Bool {
return options.caseInsensitive
}

var userInfo: [CodingUserInfoKey: Any] {
return options.userInfo
}

/// All attributes
public var allAttributes = [String: XMLAttribute]()

/// Find an attribute by name
public func attribute(by name: String) -> XMLAttribute? {
if caseInsensitive {
return allAttributes.first(where: { $0.key.compare(name, true) })?.value
Expand Down Expand Up @@ -813,8 +832,10 @@ public class XMLElement: XMLContent {

/// All child elements (text or XML)
public var children = [XMLContent]()

var count: Int = 0
var index: Int
let options: SWXMLHashOptions

var xmlChildren: [XMLElement] {
return children.flatMap { $0 as? XMLElement }
Expand All @@ -827,10 +848,10 @@ public class XMLElement: XMLContent {
- name: The name of the element to be initialized
- index: The index of the element to be initialized
*/
init(name: String, index: Int = 0, caseInsensitive: Bool) {
init(name: String, index: Int = 0, options: SWXMLHashOptions) {
self.name = name
self.caseInsensitive = caseInsensitive
self.index = index
self.options = options
}

/**
Expand All @@ -843,7 +864,7 @@ public class XMLElement: XMLContent {
*/

func addElement(_ name: String, withAttributes attributes: [String: String], caseInsensitive: Bool) -> XMLElement {
let element = XMLElement(name: name, index: count, caseInsensitive: caseInsensitive)
let element = XMLElement(name: name, index: count, options: options)
count += 1

children.append(element)
Expand Down
17 changes: 16 additions & 1 deletion Tests/SWXMLHashTests/LazyTypesConversionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,28 @@ class LazyTypesConversionTests: XCTestCase {
XCTFail("\(error)")
}
}

func testShouldBeAbleToGetUserInfoDuringDeserialization() {
parser = SWXMLHash.config { config in
let options = SampleUserInfo(apiVersion: .v1)
config.userInfo = [ SampleUserInfo.key: options ]
}.parse(xmlWithBasicTypes)

do {
let value: BasicItem = try parser!["root"]["basicItem"].value()
XCTAssertEqual(value.name, "the name of basic item (v1)")
} catch {
XCTFail("\(error)")
}
}
}

extension LazyTypesConversionTests {
static var allTests: [(String, (LazyTypesConversionTests) -> () throws -> Void)] {
return [
("testShouldConvertValueToNonOptional", testShouldConvertValueToNonOptional),
("testShouldConvertAttributeToNonOptional", testShouldConvertAttributeToNonOptional)
("testShouldConvertAttributeToNonOptional", testShouldConvertAttributeToNonOptional),
("testShouldBeAbleToGetUserInfoDuringDeserialization", testShouldBeAbleToGetUserInfoDuringDeserialization)
]
}
}
48 changes: 46 additions & 2 deletions Tests/SWXMLHashTests/TypeConversionBasicTypesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ import XCTest
// swiftlint:disable line_length
// swiftlint:disable type_body_length

struct SampleUserInfo {
enum ApiVersion {
case v1
case v2
}

var apiVersion = ApiVersion.v2

func suffix() -> String {
if apiVersion == ApiVersion.v1 {
return " (v1)"
} else {
return ""
}
}

static let key = CodingUserInfoKey(rawValue: "test")!

init(apiVersion: ApiVersion) {
self.apiVersion = apiVersion
}
}

class TypeConversionBasicTypesTests: XCTestCase {
var parser: XMLIndexer?
let xmlWithBasicTypes = """
Expand Down Expand Up @@ -524,15 +547,35 @@ class TypeConversionBasicTypesTests: XCTestCase {
XCTFail("\(error)")
}
}

func testShouldBeAbleToGetUserInfoDuringDeserialization() {
parser = SWXMLHash.config { config in
let options = SampleUserInfo(apiVersion: .v1)
config.userInfo = [ SampleUserInfo.key: options ]
}.parse(xmlWithBasicTypes)

do {
let value: BasicItem = try parser!["root"]["basicItem"].value()
XCTAssertEqual(value.name, "the name of basic item (v1)")
} catch {
XCTFail("\(error)")
}
}
}

struct BasicItem: XMLIndexerDeserializable {
let name: String
let price: Double

static func deserialize(_ node: XMLIndexer) throws -> BasicItem {
var name: String = try node["name"].value()

if let opts = node.userInfo[SampleUserInfo.key] as? SampleUserInfo {
name += opts.suffix()
}

return try BasicItem(
name: node["name"].value(),
name: name,
price: node["price"].value()
)
}
Expand Down Expand Up @@ -618,7 +661,8 @@ extension TypeConversionBasicTypesTests {
("testAttributeItemShouldThrowWhenConvertingMissingToNonOptional", testAttributeItemShouldThrowWhenConvertingMissingToNonOptional),
("testAttributeItemShouldConvertAttributeItemToOptional", testAttributeItemShouldConvertAttributeItemToOptional),
("testAttributeItemShouldConvertEmptyToOptional", testAttributeItemShouldConvertEmptyToOptional),
("testAttributeItemShouldConvertMissingToOptional", testAttributeItemShouldConvertMissingToOptional)
("testAttributeItemShouldConvertMissingToOptional", testAttributeItemShouldConvertMissingToOptional),
("testShouldBeAbleToGetUserInfoDuringDeserialization", testShouldBeAbleToGetUserInfoDuringDeserialization)
]
}
}

0 comments on commit a90a62e

Please sign in to comment.