Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
Updated to support changes to the Swift Language in Xcode 6 beta 5. A…
Browse files Browse the repository at this point in the history
…lso updated SWXMLHash to latest commit.
  • Loading branch information
MikePulsiferDOL committed Aug 14, 2014
1 parent 2447ed4 commit 2469c10
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 317 deletions.
5 changes: 2 additions & 3 deletions GovDataRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,14 @@ class GovDataRequest {
var err: NSError?
if self.responseFormat == "JSON" {
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err?) {
if(err != nil) {
// If there is an error parson JSON, print it to the console
NSLog ("Error parsing the JSON")
}
self.delegate?.didCompleteWithDictionary(jsonResult)
} else if self.responseFormat == "XML" {
let parser = SWXMLHash()
var dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
let xml = parser.parse(dataString)
let xml = SWXMLHash.parse(dataString)
self.delegate?.didCompleteWithXML(xml)
}
})
Expand Down
277 changes: 277 additions & 0 deletions SWXMLHash.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
//
// SWXMLHash.swift
//
// Copyright (c) 2014 David Mohundro
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation

/// Simple XML parser.
public class SWXMLHash {
/**
Method to parse XML passed in as a string.

:param: xml The XML to be parsed

:returns: An XMLIndexer instance that is used to look up elements in the XML
*/
class public func parse(xml: String) -> XMLIndexer {
return parse((xml as NSString).dataUsingEncoding(NSUTF8StringEncoding))
}

/**
Method to parse XML passed in as an NSData instance.

:param: xml The XML to be parsed

:returns: An XMLIndexer instance that is used to look up elements in the XML
*/
class public func parse(data: NSData) -> XMLIndexer {
var parser = XMLParser()
return parser.parse(data)
}
}

/// The implementation of NSXMLParserDelegate and where the parsing actually happens.
class XMLParser : NSObject, NSXMLParserDelegate {
var parsingElement: String = ""

override init() {
currentNode = root
super.init()
}

var lastResults: String = ""

var root = XMLElement(name: "root")
var currentNode: XMLElement
var parentStack = [XMLElement]()

func parse(data: NSData) -> XMLIndexer {
// clear any prior runs of parse... expected that this won't be necessary, but you never know
parentStack.removeAll(keepCapacity: false)
root = XMLElement(name: "root")

parentStack.append(root)

let parser = NSXMLParser(data: data)
parser.delegate = self
parser.parse()

return XMLIndexer(root)
}

func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName: String!, attributes attributeDict: NSDictionary!) {

self.parsingElement = elementName

currentNode = parentStack[parentStack.count - 1].addElement(elementName, withAttributes: attributeDict)
parentStack.append(currentNode)

lastResults = ""
}

func parser(parser: NSXMLParser!, foundCharacters string: String!) {
lastResults += string
}

func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
if !lastResults.isEmpty {
currentNode.text = lastResults
}

parentStack.removeLast()
}
}

/// Returned from SWXMLHash, allows easy element lookup into XML data.
public enum XMLIndexer {
case Element(XMLElement)
case List([XMLElement])
case Error(NSError)

/// The underlying XMLElement at the currently indexed level of XML.
public var element: XMLElement? {
get {
switch self {
case .Element(let elem):
return elem
default:
return nil
}
}
}

/// The underlying array of XMLElements at the currently indexed level of XML.
public var all: [XMLIndexer] {
get {
switch self {
case .List(let list):
var xmlList = [XMLIndexer]()
for elem in list {
xmlList.append(XMLIndexer(elem))
}
return xmlList
case .Element(let elem):
return [XMLIndexer(elem)]
default:
return []
}
}
}

/**
Initializes the XMLIndexer

:param: _ should be an instance of XMLElement, but supports other values for error handling

:returns: instance of XMLIndexer
*/
public init(_ rawObject: AnyObject) {
switch rawObject {
case let value as XMLElement:
self = .Element(value)
default:
self = .Error(NSError(domain: "SWXMLDomain", code: 1000, userInfo: nil))
}
}

/**
Find an XML element at the current level by element name

:param: key The element name to index by

:returns: instance of XMLIndexer to match the element (or elements) found by key
*/
public subscript(key: String) -> XMLIndexer {
get {
let userInfo = [NSLocalizedDescriptionKey: "XML Element Error: Incorrect key [\"\(key)\"]"]
switch self {
case .Element(let elem):
if let match = elem.elements[key] {
if match.count == 1 {
return .Element(match[0])
}
else {
return .List(match)
}
}
return .Error(NSError(domain: "SWXMLDomain", code: 1000, userInfo: userInfo))
default:
return .Error(NSError(domain: "SWXMLDomain", code: 1000, userInfo: userInfo))
}
}
}

/**
Find an XML element by index within a list of XML Elements at the current level

:param: index The 0-based index to index by

:returns: instance of XMLIndexer to match the element (or elements) found by key
*/
public subscript(index: Int) -> XMLIndexer {
get {
let userInfo = [NSLocalizedDescriptionKey: "XML Element Error: Incorrect index [\"\(index)\"]"]
switch self {
case .List(let list):
if index <= list.count {
return .Element(list[index])
}
return .Error(NSError(domain: "SWXMLDomain", code: 1000, userInfo: userInfo))
case .Element(let elem):
if index == 0 {
return .Element(elem)
}
else {
return .Error(NSError(domain: "SWXMLDomain", code: 1000, userInfo: userInfo))
}
default:
return .Error(NSError(domain: "SWXMLDomain", code: 1000, userInfo: userInfo))
}
}
}
}

/// XMLIndexer extensions
extension XMLIndexer: BooleanType {
/// True if a valid XMLIndexer, false if an error type
public var boolValue: Bool {
get {
switch self {
case .Error:
return false
default:
return true
}
}
}
}

/// Models an XML element, including name, text and attributes
public class XMLElement {
/// The name of the element
public let name: String
/// The inner text of the element, if it exists
public var text: String?
/// The attributes of the element
public var attributes = [String:String]()

var elements = [String:[XMLElement]]()

/**
Initialize an XMLElement instance

:param: name The name of the element to be initialized

:returns: a new instance of XMLElement
*/
init(name: String) {
self.name = name
}

/**
Adds a new XMLElement underneath this instance of XMLElement

:param: name The name of the new element to be added
:param: withAttributes The attributes dictionary for the element being added

:returns: The XMLElement that has now been added
*/
func addElement(name: String, withAttributes attributes: NSDictionary) -> XMLElement {
let element = XMLElement(name: name)

if var group = elements[name] {
group.append(element)
elements[name] = group
}
else {
elements[name] = [element]
}

for (keyAny,valueAny) in attributes {
let key = keyAny as String
let value = valueAny as String
element.attributes[key] = value
}

return element
}
}
35 changes: 0 additions & 35 deletions SWXMLHash/Extensions.swift

This file was deleted.

26 changes: 0 additions & 26 deletions SWXMLHash/Info.plist

This file was deleted.

19 changes: 0 additions & 19 deletions SWXMLHash/SWXMLHash.h

This file was deleted.

Loading

0 comments on commit 2469c10

Please sign in to comment.