How to Parse XML Files in Xcode

Use Xcode to ingest, parse and act on content from a remote XML file

Closeup side view of mid 20's blond black woman doing her software development project. She's sitting in front of a desktop computer and sipping a coffee while working on a computer.

gilaxia/Getty Images

Although a built-in XML parser adds real value to a new desktop or mobile application, coding that functionality typically requires a lot of development time and beta testing. Apple's Xcode program includes an XML parser that bypasses most of this manual work.

An XML file can contain anything from basic data about your app to an RSS feed for a website. They can also be a great way of updating information within your app remotely, thus bypassing the need to submit a new binary to Apple simply to add a new item to a list.

The built-in Xcode process contains steps for initializing the variables to be used, starting the XML parser process, feeding that process a file, assessing individual elements and the characters (value) within those element, recognizing the end of an individual element, and terminating the parsing process.

Using the XML Parser

To illustrate the details, we'll parsing an example file from the internet by passing it a particular web address (URL).

Start with building the header file. This is an example of a very basic header file for a Detail View Controller with the minimum requirements for parsing our file:

@interface RootViewController : UITableViewController {
DetailViewController *detailViewController;
NSXMLParser *rssParser;
NSMutableArray *articles;
NSMutableDictionary *item;
NSString *currentElement;
NSMutableString *ElementValue;
BOOL errorParsing;
}
@property (nonatomic, retain) IBOutlet DetailViewController *detailViewController;
- (void)parseXMLFileAtURL:(NSString *)URL;
The parseXMLFileAtURL function starts the process. When it finishes, the NSMutableArray "articles" hold the data. The array consists of mutable dictionaries with keys related to the field names in the XML file.

Next, initialize the process:

- (void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(@"File found and parsing started");
}

This function runs at the start of the process. There is no need to put anything in this function, but if you want to perform a task when the file starts to be parsed, this is where you would put your code.

Next, instruct the program to download something:

- (void)parseXMLFileAtURL:(NSString *)URL
{
NSString *agentString = @"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:URL]];
[request setValue:agentString forHTTPHeaderField:@"User-Agent"];
xmlFile = [ NSURLConnection sendSynchronousRequest:request returningResponse: nil error: nil ];
articles = [[NSMutableArray alloc] init];
errorParsing=NO;
rssParser = [[NSXMLParser alloc] initWithData:xmlFile];
[rssParser setDelegate:self];
// You may need to turn some of these on depending on the type of XML file you are parsing
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}

This function instructs the engine to download a file at a particular web address (URL) and start the process for parsing it. We're telling the remote server that we are a Safari running on Mac just in case the server tries to redirect the iPhone/iPad to a mobile version.
The options at the end are specific to certain XML files. Most RSS files and generic XML files won't need them turned on.

Perform some basic error checking on the result:

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString *errorString = [NSString stringWithFormat:@"Error code %i", [parseError code]];
NSLog(@"Error parsing XML: %@", errorString);
errorParsing=YES;
}
This error-checking routing sets a binary value if it encounters an error. You may need something more specific here depending on what you are doing. If you simply need to run some code after processing in the case of error, the errorParsing binary variable can be called at that time.

Next, the program breaks down the retrieved content and analyzes it:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
ElementValue = [[NSMutableString alloc] init];
if ([elementName isEqualToString:@"item"]) {
item = [[NSMutableDictionary alloc] init];
}
}
The meat of the XML parser contains three functions, one that runs at the beginning of an individual element, one that runs during the middle of parsing the element, and one that runs at the end of the element.
For this example, we'll parse a file similar to RSS files that break down elements into groups under the heading of items within the XML file. At the start of the processing, we are checking for the element name "item" and allocating our item dictionary when a new group is detected. Otherwise, we initialize our variable for the value:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
[ElementValue appendString:string];
}

When we find characters, we simply add them to our variable ElementValue:

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:@"item"]) {
[articles addObject:[item copy]];
} else {
[item setObject:ElementValue forKey:elementName];
}
}

When the program finishes processing an element, it must do one of two things:

  • If the end element is item, we've finished our group, so we'll add our dictionary to our array of articles.
  • If the element is not item, we'll set the value in our dictionary with a key that matches the element's name. (This means we don't need an individual variable for each field within the XML file. We can process them a little more dynamically.)

This is the last function needed for our parsing routine—it ends the document. Put any final code here or specify an error-correcting subroutine:.

- (void)parserDidEndDocument:(NSXMLParser *)parser {
if (errorParsing == NO)
{
NSLog(@"XML processing done!");
} else {
NSLog(@"Error occurred during XML processing");
}
}

One thing many apps might want to do here is to save the data or XML file to a file on the device. That way, if the device isn't connected to the internet the next time the app loads, it can still get at this information.

Of course, we can't forget the most important part: telling your application to parse the file (and giving it a web address to find it at!). To start the process, add this line of code to the appropriate place where you want to do the XML processing:

          [self parseXMLFileAtURL:@"http://www.webaddress.com/file.xml"];