Home > Enterprise >  How to use multiple xmlparsers in swift at the same time?
How to use multiple xmlparsers in swift at the same time?

Time:11-14

In Swift. When I use xmlparser to render data for ONE intance it works fine, but if I try to render two different xml data sets it is not working. As I understand the xmlparser is synchronious so this will mess things up for the second xmlparser call. So how can I render xml data for two different datasets at the same time (or after each other)?

This is how I render one of my datasets which works fine. I include XMLParserDelegate:

var xmlParser: XMLParser!

self.xmlParser = XMLParser(data: HelperController.sharedInstance.XMLDataObject!)
self.xmlParser.delegate = self
self.xmlParser.parse()

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
    eName = elementName
    if elementName == "someName" { 
        //do something
    }
}

func parser(_ parser: XMLParser, foundCharacters string: String) {
    let data = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased()
    //var jalla = NSString.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased()
    if (!data.isEmpty) {
        //do something 
    }
}

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    eName = ""
    if elementName == "someName" {
      //do something
    } 
}

But I need to render another XMLDataObject. How can I do this? If I add the second xmlparsing to a new class and initialize it from there it will not enter didStartElement (since the first xmlParser is currently busy I guess).

CodePudding user response:

@Larme

I have tried a lot of different ways to add the second parser. The way I try it now is that I have the second parser in separate class like this:

class SomeClassViewController: UIViewController, XMLParserDelegate {

var xmlParserSecondParser: XMLParser!
var eName: String = String()

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

func initializeSecondParser(){
    self.xmlParserSecondParser = XMLParser(data: 
                   HelperController.sharedInstance.XMLDataObjectSecond!)
    self.xmlParserSecondParser.delegate = self
    self.xmlParserSecondParser.parse()
    
    func parser(_ parser: XMLParser, didStartElement elementName: 
      String, namespaceURI: String?, qualifiedName qName: String?, 
      attributes attributeDict: [String : String]) {
         eName = elementName
         if elementName == "someName" { 
           //do something
         }
    }

    func parser(_ parser: XMLParser, foundCharacters string: String) {
       let data = string.trimmingCharacters(in: 
       CharacterSet.whitespacesAndNewlines).uppercased()
         if (!data.isEmpty) {
          //do something 
         }
    }

   func parser(_ parser: XMLParser, didEndElement elementName: String, 
       namespaceURI: String?, qualifiedName qName: String?) {
          eName = ""
          if elementName == "someName" {
            //do something
          } 
   }
}

}

When I run the first parser I also call initializeSecondParser() but that does'nt work since didStartElement is never called.

let someClassViewController = SomeClassViewController();
someClassViewController.initializeSecondParser();

I have also tried to make the second call async but no luck:

DispatchQueue.main.async {
  let someClassViewController = SomeClassViewController();
  someClassViewController.initializeSecondParser();
}

CodePudding user response:

You need to separate correctly your parsers:

struct CustomParser: XMLParserDelegate {
    let xmlParser: XMLParser
    let ename: String = ""
    init(with data: Data) {
        xmlParser = XMLParser(data: data)
        xmlParser.delegate = self
    }
    
    // Here its returning the value you want
    var parsedResponse: ParsedResponse?
    func parse() -> ParsedResponse? {
        xmlParser.parse()
        return parsedResponse
    }
    // ParserDelegates
    func parser(_ parser: XMLParser, foundCharacters string: String) {
        ...
    }
    func parser(_ parser: XMLParser, didEndElement elementName: String, 
       namespaceURI: String?, qualifiedName qName: String?) {
        ...
    }
    ...
}



let parser1 = CustomParser(with: HelperController.sharedInstance.XMLDataObjectFirst!)
let parsed1 = parser1.parse()

let parser2 = CustomParser(with: HelperController.sharedInstance.XMLDataObjectSecond!)
let parsed2 = parser2.parse()

That's the way I'd recommend, since you separate correctly your parsing from UIViewController. You won't have big UIViewController that do the XML parsing, and much more...

You can use 2 parser still, but with little you've shown, it could be harder, is to check which parser it is in the delegate method, and act accordingly, but that's adds complexity and prone to error (forget something somewhere and break then everything):

var firstParser: XMLParser!
var firstEName: String = String()
var secondParser: XMLParser!
var secondEName: String = String()

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {

    if parser == firstParser {
        firstEName = elementName
        if elementName == "someName" { 
           //do something
        }
    } else if parser == secondParser {
        secondEName = elementName
        if elementName == "someName" { 
           //do something
        }
    } else {
        //It's another parser, what to do?
    }
}

And do that check for each delegate method. So if you forget to do the check in one of the method, you might have weird results...

  • Related