Parsing XML from URL in Swift

前端 未结 4 555
无人共我
无人共我 2020-11-30 05:03

I am brand new to parsing and cannot find any tutorial that isn\'t outdated and doesn\'t raise more questions. I have a simple xml file url I am trying to parse. The xml is

4条回答
  •  心在旅途
    2020-11-30 05:48

    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(["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.

提交回复
热议问题