SXMLParser does not support reentrant parsing

I am a beginner of xcode, have some experience of other program language.


Is NSXMLParser method impossible or not appreciated for parsing several xml file ?

I created two classes to parse several xml files.


parent class

class parent : NSObject {
     var fileName:[String]! = ["aaa", "bbb", "ccc"]
     var loadingNo = 0
     func startLoading() { //1.start from this
          let parser = loadXml( fileName: fileName[ loadingNo] , parent: self)//xml is parsed by subclass "loadXml"





     }
     func endParseXml() { // 5.parse ended and load next xml file
          loadingNo++
          if (loadingNo < fileName.count) { startLoading() }
     }
}


loadXml class

class loadXml : NSObject, NSXMLParserDelegate {
     var p:parent!

     init( fileName:String, parent:charaAssets ) {
          super.init()
          self.p = parent // 2.reference of parent

          let url = NSBundle.mainBundle().URLForResource( fileName, withExtension: "xml")
          let parser = NSXMLParser(contentsOfURL: url!)!
          parser.delegate = self
          parser.parse()
      }

     func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
          // 3. parse procedure here

     }

     func parserDidEndDocument(parser: NSXMLParser) {
          p.endParseXml() //4.return to parent
     }
}


try to load next xml , then a error was shown.

'NSInternalInconsistencyException', reason: 'NSXMLParser does not support reentrant parsing.'


First I created one class to parse several xml, However the error occured, so separeted class but the error did not disappear.

I am not sure that the delegate should only one function in a program.


Or is it possible to next load xml without re-instantiation ?

I guess the very bad point of your code is this:

          p.endParseXml() //4.return to parent

This does not `return to parent`, but calls parent.startLoading() recursively.


The `parse()` method of NSXMLParser is not asynchronous, so you just need to call it repeatedly in a normal way like this:

        let fileNames: [String] = ["aaa", "bbb", "ccc"]
        for fileName in fileNames {
            let url = NSBundle.mainBundle().URLForResource(fileName, withExtension: "xml")
            let parser = NSXMLParser(contentsOfURL: url!)!
            parser.delegate = self
            parser.parse() {
        }


If you want a single class which loads and parses multiple xml files, that would be something like this:

class XMLLoader: NSObject, NSXMLParserDelegate {
    // Specify the result type for your app
    private var result: AnyObject?
    var results: [AnyObject] = []

    func startLoading() -> Bool {
        var hasErrors = false
        let fileNames: [String] = ["aaa", "bbb", "ccc"]
        for fileName in fileNames {
            let url = NSBundle.mainBundle().URLForResource(fileName, withExtension: "xml")
            let parser = NSXMLParser(contentsOfURL: url!)!
            parser.delegate = self
            NSLog("Started parsing \(fileName)")
            if parser.parse() {
                results.append(result!)
                NSLog("Ended parsing \(fileName)")
            } else {
                let errorDescription = parser.parserError?.description ?? "unknown"
                NSLog("Error occurred while parsing \(fileName): \(errorDescription)")
                hasErrors = true
            }
        }
        return hasErrors
    }

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        //...
    }
    // Various other delegate methods may be needed...
    func parserDidEndDocument(parser: NSXMLParser) {
        // Do nothing other than setting the result.
        result = "Replace this with actual result."
    }
}


ADDITION: You'd better follow the simple Swift convention: Type names start with capital letters.

Thanks a lot for teaching me not only the way to parse, but also the smart logic.

I could load several xml files just what I desired.


According to the additional advise, I could not understand the meaning...

I would appreciate a little more in detail.

According to the additional advise, I could not understand the meaning...

Sorry, it's not much related to the main topic of this thread, but we usually start type names (including class names) with capital letters in Swift.


This line:

class parent : NSObject {

should be:

class Parent : NSObject {


Or, this line:

class loadXml : NSObject, NSXMLParserDelegate {

should be:

class LoadXml : NSObject, NSXMLParserDelegate {

(Or LoadXML may be better.)


This simple change improves the readability of your code for many Swift experts. With which you can expect more developers read your code, thus more chances to get better suggestions.

Well understood, I would like to keep the rule.

Thanks a lot!

SXMLParser does not support reentrant parsing
 
 
Q