Parse XML data in swift
Because your XML contains all of the values with attributes of the element, you don't need to implement foundCharacters
. Just didStartElement
, e.g., your parser delegate might look as simple as:
var song: String?var artist: String?func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { switch elementName { case "Song": song = attributeDict["title"] case "Artist": artist = attributeDict["name"] default: break }}
Two observations:
I'd be inclined to pull this parsing code out of the view controller, though, and put it in a dedicated object, to help prevent "view controller bloat".
I'd also use
URLSession
in case the response to request happens to be a little slow. Generally, one should avoid usingXMLParser(contentsOf:)
, because that performs the request synchronously.In your case, since you’re requesting the data from
localhost
, perhaps that’s less of a concern. But, still, it’s prudent to always perform HTTP requests asynchronously.
Anyway, that might yield something like:
class SongParser: NSObject { var song: String? var artist: String? class func requestSong(completionHandler: @escaping (String?, String?, Error?) -> Void) { let url = URL(string: "http://localhost/jazler/NowOnAir.xml")! let task = URLSession.shared.dataTask(with: url) { data, _, error in guard let data = data, error == nil else { DispatchQueue.main.async { completionHandler(nil, nil, error) } return } let delegate = SongParser() let parser = XMLParser(data: data) parser.delegate = delegate parser.parse() DispatchQueue.main.async { completionHandler(delegate.song, delegate.artist, parser.parserError) } } task.resume() }}extension SongParser: XMLParserDelegate { func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { switch elementName { case "Song": song = attributeDict["title"] case "Artist": artist = attributeDict["name"] default: break } } }
And you'd use it like so:
SongParser.requestSong { song, artist, error in guard let song = song, let artist = artist, error == nil else { print(error ?? "Unknown error") return } print("Song:", song) print("Artist:", artist)}
First convert your xml into NSData and call the parser to parse it.
//converting into NSDatavar data: Data? = theXML.data(using: .utf8)//initiate NSXMLParser with this datavar parser: XMLParser? = XMLParser(data: data ?? Data())//setting delegateparser?.delegate = self//call the method to parsevar result: Bool? = parser?.parse()parser?.shouldResolveExternalEntities = true
Now, you need to implement the NSXMLParser delegate into your class.
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {currentElement = elementNameprint("CurrentElementl: [\(elementName)]")}func parser(_ parser: XMLParser, foundCharacters string: String) {print("foundCharacters: [\(string)]")}
You will find the value under key of your xml.