在Swift中使用NSXMLParser时访问元素的值

时间:2014-12-16 18:33:23

标签: xml swift xml-parsing nsxmlparser

我正在尝试解析http://apps.wku.edu/iwku/maps/buildings/data/SouthCampus-Buildings.xml

上的XML

在Swift Playground中使用以下代码

import UIKit

var str = "Hello, playground"

class Parse: NSObject, NSXMLParserDelegate{

func beginParse(){        
    let url = NSURL(string: "http://apps.wku.edu/iwku/maps/buildings/data/SouthCampus-Buildings.xml")
    var xml = NSXMLParser(contentsOfURL: url)

    xml?.delegate = self
    xml?.parse()
}

func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: NSDictionary!) {
    println("Element's name is \(elementName)")
    println("Element's attributes are \(attributeDict)")
    }
}

var instance = Parse()

instance.beginParse()

不幸的是我在控制台中的输出如下所示: enter image description here

为什么我的attributeDict似乎是空的,如何访问与这些元素相关的值?

3 个答案:

答案 0 :(得分:5)

使用NSXMLParser解析XML文件并不像您期望的那样容易。您必须实现NSXMLParserDelegate协议中的多个方法来捕获事件。您已经为didStartElement执行了此操作,它为(对我而言)提供了预期结果:元素名称及其属性(上面链接的XML文件中没有属性)。

到目前为止,一切正常......

既然您已经抓住了元素的开头,那么您必须注意进一步处理:

  • 协议方法foundCharacters在元素的开头和结尾之间触发。也许好几次。您必须实现该方法并将找到的字符附加到字符串变量,具体取决于元素的名称。

  • didEndElement被触发时,您的字符串变量将完全填充元素的内容

如果XML文件具有深层次结构,那么事情可能会越来越复杂。

很抱歉这个广泛的答案,但遗憾的是,没有获取该XML文件并使用NSXMLParser给我一个深度嵌套的字典方法。

答案 1 :(得分:2)

属性是标记内的属性。例如,如果您的标签看起来像:

<building id="foo">

在这种情况下,id将位于attributeDict

但是,在这种情况下,您的XML看起来像:

<buildings>
    <building>
        <name>Commonwealth School</name>
        <building_code>SC</building_code>
        <latitude>36.965075</latitude>
        <longitude>-86.467144</longitude>
        <image_url>
        http://www.wku.edu/marketingandcommunications/images/wkucuptallrb.jpg
        </image_url>
        <description/>
        <handicap_accessible/>
        <address/>
        <url/>
        <aliases>
            <alias>South Campus</alias>
            <alias>Community College</alias>
        </aliases>
        <email/>
        <phone/>
        <organizations/>
    </building>
    ...

因此,考虑<name>Commonwealth School</name>,这将导致对

的一系列调用
  • didStartElement
  • foundCharacters(可多次调用)和
  • didEndElement

答案 2 :(得分:0)

我制作了一个简单的示例应用,它从此Feed中读取XML - jokes-n-fun RSS feed并在表格视图中显示检索到的数据,这里是链接:jokes-n-fun@github,共享源代码可以用作制作类似iOS应用程序的参考。要回答您的问题,您可以参考AtomParser.swift class中编写的代码,复制粘贴在此处:

import UIKit

// MARK: - declaring typealias to store closures with dictionary
typealias StartTagRuleBlock = (NSMutableDictionary, [NSObject : AnyObject]) -> Void
typealias EndTagRuleBlock = (NSMutableDictionary, String) -> Void

// MARK: - Protocol declared
protocol CompletionObserver {
    func dataSourcePopulated(dataSourceArray : NSArray) -> ()
}

class AtomParser : NSObject, NSXMLParserDelegate {
    // MARK: - Properties
    let triggerTag : String
    let parseUrl : String

    var dataArray : NSMutableArray = NSMutableArray()

    var collectedCharacters : NSMutableString?
    var recordDict : NSMutableDictionary?
    var parser : NSXMLParser?
    var startElementRuleMappingDict:[String: StartTagRuleBlock] = [String: StartTagRuleBlock]()
    var endElementRuleMappingDict:[String: EndTagRuleBlock] = [String: EndTagRuleBlock]()
    var endTagRules : NSDictionary?

    var completionObserver : CompletionObserver?

    // MARK: - Designated initializer
    /**
    Designated initializer to initialize AtomParser class.

    :param: triggerTag     Tag which distinguishes each record.
    :param: parseUrl       URL supplying xml to be parser.

    :returns: Void.
    */
    init(triggerTag : String, parseUrl : String) {
        self.triggerTag = triggerTag
        self.parseUrl = parseUrl
    }

    // MARK: - Initiate parsing
    func startParsing () {
        let url = NSURL(string: self.parseUrl)
        parser = NSXMLParser(contentsOfURL: url)
        parser?.delegate = self
        parser?.parse()
    }

    // MARK: - Parser delegates
    func parserDidStartDocument(parser: NSXMLParser!) {
        self.dataArray.removeAllObjects()
    }

    func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {
        if elementName == triggerTag {
            recordDict = NSMutableDictionary(capacity: 1)
        }
        else if recordDict != nil {
            if let startTagMappingElement = self.startElementRuleMappingDict[elementName] {
                startTagMappingElement(recordDict!,attributeDict)
            }

            collectedCharacters = NSMutableString(string: "")

        }
        else {
            // no need to handle these tags
        }
    }

    func parser(parser: NSXMLParser!, foundCharacters string: String!) {
        collectedCharacters?.appendString(string)
    }

    func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
        if let mutableDictionary = recordDict {
            if elementName == triggerTag {
                dataArray.addObject(recordDict!)
            }
            else if recordDict != nil {
                if let endTagMappingElement = self.endElementRuleMappingDict[elementName] {
                    endTagMappingElement(recordDict!,"\(String(collectedCharacters!))")  
                }
            }
            else {
                // no need to handle these tags
            }
        }
    }

    func parserDidEndDocument(parser: NSXMLParser) {
        let arrayToReturn = NSArray(array: dataArray)
        completionObserver?.dataSourcePopulated(arrayToReturn)
    }
}