Xmlparser.Sharedparser.Decode() in Swift3

Parsing XML from URL in Swift

The process is simple:

  1. Create XMLParser object, passing it the data.
  2. Specify the delegate for that parser.
  3. Initiate the parsing.

So, in Swift 3/4, that looks like:

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()

The question is how do you implement the XMLParserDelegate methods. The three critical methods are didStartElement (where you prepare to receive characters), foundCharacters (where you handle the actual values parsed), and didEndElement (where you save you results).

You asked how to parse a single record (i.e. a single dictionary), but I'll show you a more general pattern for parsing a series of them, which is a far more common situation with XML. You can obviously see how to simplify this if you didn't need an array of values (or just grab the first one).

// 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

And

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
}

}

For Swift 2 rendition, see previous revision of this answer.

xml parsing in iOS swift

Here's some parsing code I wrote in Swift 3 based off of a Google News RSS reader I previously wrote in Swift 2.0. I have this code modified to handle a list of PrintLetterBarcodeData elements as well as a single one:

class BarcodeData {
var uid: String
var name: String
var gender: String
var yob: String
var co: String
var house: String
var street: String
var lm: String
var vtc: String
var po: String
var dist: String
var subdist: String
var state: String
var pc: String
var dob: String

init?(dictionary: [String : String]) {
guard let uid = dictionary["uid"],
let name = dictionary["name"],
let gender = dictionary["gender"],
let yob = dictionary["yob"],
let co = dictionary["co"],
let house = dictionary["house"],
let street = dictionary["street"],
let lm = dictionary["lm"],
let vtc = dictionary["vtc"],
let po = dictionary["po"],
let dist = dictionary["dist"],
let subdist = dictionary["subdist"],
let state = dictionary["state"],
let pc = dictionary["pc"],
let dob = dictionary["dob"] else {
return nil
}

self.uid = uid
self.name = name
self.gender = gender
self.yob = yob
self.co = co
self.house = house
self.street = street
self.lm = lm
self.vtc = vtc
self.po = po
self.dist = dist
self.subdist = subdist
self.state = state
self.pc = pc
self.dob = dob

}
}

class MyParser: NSObject {
var parser: XMLParser

var barcodes = [BarcodeData]()

init(xml: String) {
parser = XMLParser(data: xml.data(using: String.Encoding.utf8)!)
super.init()
parser.delegate = self
}

func parseXML() -> [BarcodeData] {
parser.parse()
return barcodes
}

}

extension MyParser: XMLParserDelegate {

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {

if elementName == "PrintLetterBarcodeData" {

if let barcode = BarcodeData(dictionary: attributeDict) {
barcodes.append(barcode)
}
}
}
}

Usage:

let xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><PrintLetterBarcodeData uid=\"685860050795\" name=\"Sangeetha D\" gender=\"F\" yob=\"1989\" co=\"W/O: Dhanansekaran\" house=\"632\" street=\"saradhambal nagar\" lm=\"agaramel\" vtc=\"Nazarathpettai\" po=\"Nazarethpettai\" dist=\"Tiruvallur\" subdist=\"Poonamallee\" state=\"Tamil Nadu\" pc=\"600123\" dob=\"03/06/1989\"/>"

let parser = MyParser(xml: xmlString)
let barcodes = parser.parseXML() // array of barcodes
barcodes.first // your barcode

Handling XML data with Alamofire in Swift

If I did not misunderstand your description, I think you would like to get the XML data and parse it, right? Regarding to this, you may handle with wrong variables in the response callback. You should println(data) to check the XML document.

For parsing XML data, you could consider SWXMLHash. The Alamofire request could look like:

Alamofire.request(.GET, "http://my-web-service-domain.com", parameters: nil)
.response { (request, response, data, error) in
println(data) // if you want to check XML data in debug window.
var xml = SWXMLHash.parse(data!)
println(xml["UserDTO"]["FilmID"].element?.text) // output the FilmID element.
}

Further information about XML management, please check SWXMLHash.

Something like Callback in Swift

Delegates are the other way of doing it, closures also preferred though



Related Topics



Leave a reply



Submit