我是解析新手,找不到任何过时且未提出更多问题的教程。我正在尝试解析一个简单的xml文件url。xml非常简单:
<xml> <record> <EmpName>A Employee</EmpName> <EmpPhone>111-222-3333</EmpPhone> <EmpEmail>a@employee.com</EmpEmail> <EmpAddress>12345 Fake Street</EmpAddress> <EmpAddress1>MyTown, Mystate ZIP</EmpAddress1> </record> </xml>
并且只想将其保存为NSDictionary(标签作为键,数据作为值)。到目前为止,我所能成功完成的工作是在控制台中使用以下命令打印xml字符串:
let url = NSURL(string: "http://www.urlexample.com/file.xml") let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in println(NSString(data: data, encoding: NSUTF8StringEncoding)) } print(task) task.resume()
我浏览过所有发现的在线教程,这些教程要么过时,要么过于复杂。任何帮助表示赞赏。
过程很简单:
XMLParser
delegate
因此,在Swift 3/4中,它看起来像:
let task = URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data, error == nil else { print(error ?? "Unknown error") return } let parser = XMLParser(data: data) parser.delegate = self if parser.parse() { print(self.results ?? "No results") } } task.resume()
问题是如何实现这些XMLParserDelegate方法。三种关键方法是didStartElement(准备接收字符的位置),foundCharacters(处理解析的实际值的位置)和didEndElement(保存结果的位置)。
XMLParserDelegate
didStartElement
foundCharacters
didEndElement
您问过如何解析单个记录(即单个字典),但是我将向您展示一种更通用的模式来解析一系列记录,这是XML更为常见的情况。如果您不需要值数组(或只需获取第一个值),显然可以看到如何简化此过程。
// a few constants that identify what element names we're looking for inside the XML // a few constants that identify what element names we're looking for inside the XML let recordKey = "record" let dictionaryKeys = Set<String>(["EmpName", "EmpPhone", "EmpEmail", "EmpAddress", "EmpAddress1"]) // a few variables to hold the results as we parse the XML var results: [[String: String]]? // the whole array of dictionaries var currentDictionary: [String: String]? // the current dictionary var currentValue: String? // the current value for one of the keys in the dictionary
和
extension ViewController: XMLParserDelegate { // initialize results structure func parserDidStartDocument(_ parser: XMLParser) { results = [] } // start element // // - If we're starting a "record" create the dictionary that will hold the results // - If we're starting one of our dictionary keys, initialize `currentValue` (otherwise leave `nil`) func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { if elementName == recordKey { currentDictionary = [:] } else if dictionaryKeys.contains(elementName) { currentValue = "" } } // found characters // // - If this is an element we care about, append those characters. // - If `currentValue` still `nil`, then do nothing. func parser(_ parser: XMLParser, foundCharacters string: String) { currentValue? += string } // end element // // - If we're at the end of the whole dictionary, then save that dictionary in our array // - If we're at the end of an element that belongs in the dictionary, then save that value in the dictionary func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if elementName == recordKey { results!.append(currentDictionary!) currentDictionary = nil } else if dictionaryKeys.contains(elementName) { currentDictionary![elementName] = currentValue currentValue = nil } } // Just in case, if there's an error, report it. (We don't want to fly blind here.) func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { print(parseError) currentValue = nil currentDictionary = nil results = nil } }