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

Aquí está mi intento:

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

Cualquier ayuda sería muy apreciada!

¡Gracias de antemano!

0
Mukesh 15 mar. 2021 a las 09:45

1 respuesta

La mejor respuesta

No está del todo claro a partir de su pregunta cuál es su objetivo, pero supongo que es extraer los atributos de los elementos result contenidos en el elemento CreditCheckMSResult.

Los valores son atributos del elemento result, no hijos. Entonces, cuando obtiene el comienzo del elemento result en didStartElement, los valores que desea están en el diccionario attributes que se pasa a esa función.

Un diccionario rara vez es un buen modelo de datos final. En este caso, le sugiero que cree una matriz de estructuras para contener sus datos.

struct CreditCheckResult {
    let message: String
    let ref: String
    let network: String
}

El atributo xmlns es para detallar el espacio de nombres XML que corresponde al elemento, si lo hay. No querrás almacenar esto.

Ya que no está interesado en los hijos del elemento result (no tiene ninguno). Prácticamente solo necesitas los métodos de delegado didStart.

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 = []
    }

}
1
Paulw11 15 mar. 2021 a las 07:29