Skip to content

Commit

Permalink
Improved error handling (fixed Issue tadija#62)
Browse files Browse the repository at this point in the history
Added error property of ErrorType enum with possible error cases
Removed errorElementName static property
Modified subscript logic of AEXMLElement to return empty element with ElementNotFound error (if element does not exist)
Modified root property of AEXMLDocument to return empty element with RootElementMissing error (if root element does not exist)
Improved logic in testRootElement and testNotExistingElement unit tests
Minor changes in example ViewController and README.md
  • Loading branch information
tadija committed May 2, 2016
1 parent 91aed4f commit 4a14c27
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 25 deletions.
4 changes: 2 additions & 2 deletions Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class ViewController: UIViewController {
// prints <cat breed="Siberian" color="lightgray">Tinna</cat>
print(xmlDoc.root["cats"]["cat"].xmlStringCompact)

// prints element <badexample> not found
print(xmlDoc["badexample"]["notexisting"].stringValue)
// prints Optional(AEXMLExample.AEXMLElement.Error.ElementNotFound)
print(xmlDoc["NotExistingElement"].error)
}
catch {
print("\(error)")
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ do {
// prints <cat breed="Siberian" color="lightgray">Tinna</cat>
print(xmlDoc.root["cats"]["cat"].xmlStringCompact)

// prints element <badexample> not found
print(xmlDoc["badexample"]["notexisting"].stringValue)
}
// prints Optional(AEXMLExample.AEXMLElement.Error.ElementNotFound)
print(xmlDoc["NotExistingElement"].error)
}
catch {
print("\(error)")
}
Expand Down
49 changes: 31 additions & 18 deletions Source/AEXML.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ import Foundation
*/
public class AEXMLElement {

/// A type representing an error value that can be inside `error` property.
public enum Error: ErrorType {
case ElementNotFound
case RootElementMissing
}

private struct Defaults {
static let name = String()
static let attributes = [String : String]()
}

// MARK: Properties

/// Every `AEXMLElement` should have its parent element instead of `AEXMLDocument` which parent is `nil`.
Expand All @@ -49,6 +60,9 @@ public class AEXMLElement {
/// XML Element attributes (defaults to empty dictionary).
public var attributes: [String : String]

/// Error value (`nil` if there is no error).
public var error: Error?

/// String representation of `value` property (if `value` is `nil` this is empty String).
public var stringValue: String { return value ?? String() }

Expand All @@ -61,11 +75,6 @@ public class AEXMLElement {
/// Double representation of `value` property (this is **0.00** if `value` can't be represented as Double).
public var doubleValue: Double { return (stringValue as NSString).doubleValue }

private struct Defaults {
static let name = String()
static let attributes = [String : String]()
}

// MARK: Lifecycle

/**
Expand All @@ -85,18 +94,16 @@ public class AEXMLElement {

// MARK: XML Read

/// This element name is used when unable to find element.
public static let errorElementName = "AEXMLError"

// The first element with given name **(AEXMLError element if not exists)**.
// The first element with given name **(Empty element with error if not exists)**.
public subscript(key: String) -> AEXMLElement {
if name == AEXMLElement.errorElementName {
return self
} else {
let filtered = children.filter { $0.name == key }
let errorElement = AEXMLElement(AEXMLElement.errorElementName, value: "element <\(key)> not found")
return filtered.count > 0 ? filtered.first! : errorElement
guard let
first = children.filter({ $0.name == key }).first
else {
let errorElement = AEXMLElement(key)
errorElement.error = Error.ElementNotFound
return errorElement
}
return first
}

/// Returns all of the elements with equal name as `self` **(nil if not exists)**.
Expand Down Expand Up @@ -323,9 +330,15 @@ public class AEXMLDocument: AEXMLElement {
/// Options for NSXMLParser (default values are `false`)
public let xmlParserOptions: NSXMLParserOptions

/// Root (the first child element) element of XML Document **(AEXMLError element if not exists)**.
private let errorElement = AEXMLElement(AEXMLElement.errorElementName, value: "XML Document must have root element.")
public var root: AEXMLElement { return children.count == 1 ? children.first! : errorElement }
/// Root (the first child element) element of XML Document **(Empty element with error if not exists)**.
public var root: AEXMLElement {
guard let rootElement = children.first else {
let errorElement = AEXMLElement()
errorElement.error = Error.RootElementMissing
return errorElement
}
return rootElement
}

// MARK: Lifecycle

Expand Down
9 changes: 7 additions & 2 deletions Tests/AEXMLTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class AEXMLTests: XCTestCase {

func testRootElement() {
XCTAssertEqual(exampleXML.root.name, "animals", "Should be able to find root element.")

let documentWithoutRootElement = AEXMLDocument()
let rootElement = documentWithoutRootElement.root
XCTAssertEqual(rootElement.error, AEXMLElement.Error.RootElementMissing, "Should have RootElementMissing error.")
}

func testParentElement() {
Expand Down Expand Up @@ -162,8 +166,9 @@ class AEXMLTests: XCTestCase {

func testNotExistingElement() {
// non-optional
XCTAssertEqual(exampleXML.root["ducks"]["duck"].name, AEXMLElement.errorElementName, "Should be able to tell you if element does not exist.")
XCTAssertEqual(exampleXML.root["ducks"]["duck"].stringValue, "element <ducks> not found", "Should be able to tell you which element does not exist.")
XCTAssertNotNil(exampleXML.root["ducks"]["duck"].error, "Should contain error inside element which does not exist.")
XCTAssertEqual(exampleXML.root["ducks"]["duck"].error, AEXMLElement.Error.ElementNotFound, "Should have ElementNotFound error.")
XCTAssertEqual(exampleXML.root["ducks"]["duck"].stringValue, String(), "Should have empty value.")

// optional
if let _ = exampleXML.root["ducks"]["duck"].first {
Expand Down

0 comments on commit 4a14c27

Please sign in to comment.