Reputation: 2189
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<CreditCheckMSResponse xmlns="https://ebs.gsm.co.za/">
<CreditCheckMSResult>
<result message="Success" ref="505790" network="CellC" xmlns="" />
</CreditCheckMSResult>
</CreditCheckMSResponse>
</soap:Body>
</soap:Envelope>
Here is my attempt:
let parser = XMLParser(data: data)
parser.delegate = self
if parser.parse() {
print(self.results ?? "No results")
}
let recordKey = "result"
let dictionaryKeys = Set<String>(["message", "ref", "network", "xmlns"])
// 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 = [String : String]()
} else if dictionaryKeys.contains(elementName) {
currentValue = String()
}
}
// 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
}
}
Any help would be greatly appreciated!
Thank you in the advance!
Upvotes: 0
Views: 890
Reputation: 115076
It isn't entirely clear from your question what your goal is, but I assume it is to extract the attributes of the result
elements contained in the CreditCheckMSResult
element.
The values are attributes of the result
element, not children. So, when you get the start of the result
element in didStartElement
, the values you want are in the attributes
dictionary that is passed to that function.
A dictionary is rarely a good final data model. In this case I would suggest that you create an array of structs to contain your data.
struct CreditCheckResult {
let message: String
let ref: String
let network: String
}
The xmlns
attribute is to detail the XML namespace that apples to the element, if there is one. You wouldn't want to store this.
Since you aren't interested in the children of the result
element (it doesn't have any). You pretty much only need the didStart
delegate methods.
let recordKey = "result"
let results = [CreditCheckResult]?
extension ViewController: XMLParserDelegate {
func parserDidStartDocument(_ parser: XMLParser) {
results = []
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
// We only care about "result" elements
guard elementName == recordKey else {
return
}
guard let message = attributes["message"],
let ref = attributes["ref"],
let network = attributes["network"] else {
print("Malformed result element = required attribute missing")
return
}
self.results?.append(CreditCheckResult(message: message, ref: ref, network:network))
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
results = []
}
}
Upvotes: 1