web-dev-qa-db-fra.com

Analyser XML dans Swift 4

Je suis nouveau dans l'analyse XML dans Swift et j'ai trouvé ce code sur Analyse XML à partir d'une URL dans Swift mais je reçois une erreur EXC_BAD_INSTRUCTION lorsque j'essaie d'exécuter le code. La description de l'erreur se lit comme suit: fatal error: unexpectedly found nil while unwrapping an Optional value

Ceci est mon simple fichier XML:

<xml>
    <book>
        <title>Book Title</title>
        <author>Book Author</author>
    </book>
</xml>

Le code suivant crée un objet XMLParser et analyse le fichier XML situé dans mes documents.

// get xml file path from Documents and parse

let filePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last?.appendingPathComponent("example.xml")

let parser = XMLParser(contentsOf: filePath!)
parser?.delegate = self

if (parser?.parse())! {
    print(self.results)
}

Ici, j'implémente les méthodes XMLParserDelegate et définit mes dictionnaires:

// a few constants that identify what element names we're looking for inside the XML

let recordKey = "book"
let dictionaryKeys = ["title","author"]

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

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

}

L'erreur est détectée dans la méthode didEndElement lorsque la variable currentDictionary est ajoutée au dictionnaire results.

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {

    if elementName == recordKey {

        results.append(currentDictionary)    // Line with Error
        currentDictionary = nil

    } else if dictionaryKeys.contains(elementName) {

        currentDictionary[elementName] = currentValue
        currentValue = nil

    }
}

S'il vous plaît aidez-moi à résoudre ce problème. J'utilise exactement le même code fourni sur L'analyse XML à partir d'une URL dans Swift et ils ne semblent pas avoir de problèmes. Est-ce que je fais quelque chose de mal?

2
Ricky

Votre code ne s'initialise jamais réellement results. La première fois que vous essayez de l'utiliser, vous essayez de forcer le retrait d'une valeur optionnelle nil. C'est mauvais. Et il n’ya aucune raison de le déclarer facultatif implicitement non enveloppé.

Vous devez changer:

var results: [[String: String]]!

à:

var results = [[String: String]]()

Vous devrez également supprimer la ligne:

results = nil

à partir de votre méthode parser(_:parseErrorOccurred:).

Si vous préférez que results soit facultatif, vous pouvez apporter les modifications suivantes à votre code:

Remplacez la déclaration de results par:

var results: [[String: String]]? = [[String: String]]()

Changement:

results.append(currentDictionary)

à:

results?.append(currentDictionary)

Et vous laissez la ligne results = nil dans parser(_:parseErrorOccurred:).

2
rmaddy

rmaddy a correctement diagnostiqué le problème (+1). La results n'a jamais été initialisée.

Je suggérerais de laisser votre code en grande partie tel quel, mais d'ajouter simplement une méthode parserDidStartDocument qui initialise results comme suit:

func parserDidStartDocument(_ parser: XMLParser) {
    results = [[:]]
}
0
Rob