Search code examples
iosswiftnsxmlparser

NSXMLParser: Unexpected result with non-ASCII characters


I'm trying to download data in XML format via a REST web services. I have already created the parser with NSXMLParser and visualize the data in a TableView.

I have problems when I meet in the XML document sentences with the accent.

Among some research I found this very similar to my problem and tried to implement it:

func parse(handler: () -> Void) {
    self.handler = handler
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.countCategoryScheme = 0
        var url = NSURL(string: SomeStructure.firstLink);
        var err:NSError = NSError()
        var dataString: String = String(contentsOfURL: url!, encoding: NSUTF8StringEncoding, error: nil)!
        var data: NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let parser = NSXMLParser(data: data)
        let resulset = NSString(data: data, encoding: NSUTF8StringEncoding)
        println(resulset)
        parser.delegate = self;
        parser.parse();
        if !parser.parse() {
            self.delegate?.XMLParserError(self, error: "I Parse Error")
            println("I Parser error")
        }
    }
}

in println (resulset) I print the entire XML file correctly decoded.

The problem is when I run the parser, the accented characters are not read

This is code when i found Characters in the parser:

   func parser(parser: NSXMLParser!, foundCharacters string: String!) {
        myList[position] = string
    }

EDIT:

This is an example of my document:

<Name xml:lang="en" xmlns="">National Accounts</Name>

<Name xml:lang="it" xmlns="">Contabilità nazionale</Name>

In println () print the document correctly as described above.

Instead, when I go to save the data found carachter if "it" saves me this:

"Contabilit"


Solution

  • The parser:foundCharacters: delegate method can be called more than once for a single XML element. In your example, it would be called once with "Contabilit", and once with "à nazionale".

    Therefore you have to concatenate the found strings from didStartElement until didEndElement.

    Here is a very simply example how this can be done. Of course it gets more complicated if you have nested XML elements.

    Add a property for the current element string to your class:

    var currentElement : String?
    

    And then implement the delegate methods like this:

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) {
    
        // If a "Name" element started (which you are interested in), set
        // currentElement to an empty string, so that the found characters
        // can be collected. Otherwise set it to nil.
        if elementName == "Name" {
            currentElement = ""
        } else {
            currentElement = nil
        }
    
    }
    
    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    
        // If the "Name" element ended, get the collected string and
        // append it to your list.
        if elementName == "Name" {
            if let name = currentElement {
                println(name)
                myList.append(name)
            }
        }
        currentElement = nil
    }
    
    func parser(parser: NSXMLParser, foundCharacters string: String?) {
    
        // If currentElement is not nil, append the found characters to it:
        currentElement? += string ?? ""
    }