Parsing XML in iOS Using NSXMLParser
We are going to populate a table view controller using a simple XML file from the web. The code examples in this article will be written using Swift. I assume that you have already setup the TableViewController to read the input and populate the table. We will be concentrating on parsing the XML file in this article.
To parse an XML file in iOS we can make use of the NSXMLParser class from the foundation framework. We will be working with an XML data that represents food menu so lets say that our table view controller class is called FoodTableViewController.
The first thing that we have to do is download the XML data from the web. The NSURLSession class and related classes provide an API for downloading content.
The above code makes a http GET request to the link present in the link variable. Since the link represents a static XML file that is hosted on the server the response of the request will be the XML data. The link could also be an API that returns the data in XML format.
Once the XML data is downloaded it is made available in data variable ( which is of type NSData? ) of the completion handler. The entire process of making and sending the request and waiting for the response is performed in the background thread by the networking API so that the UI remains responsive. The callback handler that we provide to the dataTaskWithUrl method of the defaultSession object is also called from the background thread only after the data becomes available, therefore we must remember that any code that we write inside of the completion handler does not run in the main thread.
To understand more about the above code, I would suggest you to read the following. They will give you a lot more insight on how we can use the NSURLSession class, which is a complete suite of networking API methods for uploading and downloading content via HTTP.
This refreshData method is called from the viewDidLoad method on the table view controller to make sure the we start the process as soon as the view is loaded into the memory.
Like how every other functionality is built in iOS the XML parsing is also done through the delegation pattern. We create an instance of NSXMLParser class to help with the parsing. The parser will call certain methods on its delegate as it parses the XML document. Lets assign the FoodTableViewController class as the delegate for the parser. The NSXMLParserDelegate protocol defines the optional methods implemented by delegates of NSXMLParser objects.
We will be using 4 delegate methods to parse the file. The 4 delegate methods we will be focusing are:
This method is called by the parser object on its delegate whenever it encounters an opening XML tag.
This method is called by the parser object on its delegate whenever it is reading data between an opening tag and closing tag. The data between a tag may be read all at once or it may be read in pieces.
This method is called by the parser object on its delegate whenever it encounters a closing XML tag.
This method is called by the parser object on its delegate when it has completed parsing the entire document.
Consider the following XML data.
If we implement the delegate methods as shown above then the output that we get is.
We will be using the following XML file for our demo.
Lets define a few variable in Swift that can help us with the parsing. We create a food structure that represents a single food item. In swift if we don’t provide an initializer for a structure it automatically provides a member wise initializer that we can use to create an instance.
We are interested only in the data within each of the food item. If we have lets say the
The currentlyParsingElement variable holds the name of the tag that we are currently parsing, i.e if we encounter a opening
currentlyParsingElement = "name"
As you can see in the code above in the didStartElement method we clear out any existing data from the corresponding temporary variable and mark the element that is being currently parsed. We have the currentlyParsingElement variable because without it the foundCharacters method does not know for which tag the data that we are currently parsing belongs to. And in the foundCharacters method all that we do is append the data that we are parsing to the corresponding temporary variable ( we are appending because the data may not be parsed in a single go, it may be parsed in chunks ). In the dodEndElement method we clear out the currenlyParsingElement. If we don’t clear out the currentlyParsingElement then the data inside the non interested tags will also get appended. Lets say we don’t clear out the currenlyParsingElement variable which is set to “name”, then lets say now if we encounter a disinterested tad
Once the XML document has been finished parsing, the parser object calls the parserDidEndDocument and we ask the table view to reload the data. You should remember that we called the parse method on the parser to start the parsing from the callback once the XML data has been downloaded. That callback is executed in the background thread when the XML downloading process is complete. Therefore all the parsing ( the method calls by parser on the delegate ) also happens in the background thread, i.e why we make sure that reloading the table data happens in the main thread, because any UI updates or changes that we make should always happen on the main thread.
Once the list is populated with data. It would look like the following.