Objective C: Parsing an XML file
Date: 2010-08-04 05:00:01

I've been wanting to try out some iPad development for a while and as a hello worldish exercise for myself I thought I'd try and work out how to parse the http://code.google.com/p/bigvisiblewall/source/browse/web/cctray.xml[cctray.xml] file from http://code.google.com/p/bigvisiblewall/[Sam Newman's bigvisiblewall].

Realising that I'm a novice on the http://www.markhneedham.com/blog/2009/07/18/book-club-the-dreyfus-model-stuart-and-hubert-dreyfus/[Dreyfus Model] when it comes to Objective C I started out by following a tutorial from http://www.iphonesdkarticles.com/2008/11/parsing-xml-files.html[iPhone SDK Articles] which explained how to do this.

The first thing I learnt is that the built in library follows an http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/XMLParsing/XMLParsing.html#//apple_ref/doc/uid/10000186-SW1[event driven approach to handling XML].

As I understand it we create a parser which steps through the XML document and then raises various events based on what it finds in the document. e.g. an event will be raised when we reach the end of an element.

Those events will then be handled by a delegate that we setup on the parser.

image::{{<siteurl>}}/uploads/2010/08/objc-xml.jpg[objc-xml.jpg,251]

I included the 'cctray.xml' file in the 'Resources' folder of my XCode project just to simplify things and this is the code that we would need to setup the parser to read the file:

[source,objc]
----

	NSString* path = [[NSBundle mainBundle] pathForResource:@"cctray" ofType:@"xml"];	
	NSURL *url = [NSURL fileURLWithPath:path];
	NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
	
	XMLParser *theDelegate = [[XMLParser alloc] initXMLParser];
	[xmlParser setDelegate:theDelegate];
	[xmlParser parse];
----

'theDelegate' needs to be an instance of an object which conforms to the http://developer.apple.com/mac/library/documentation/Cocoa/Reference/NSXMLParserDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSXMLParserDelegate[NSXMLParserDelegate protocol].

All the methods on this protocol are optional so that seems to mean that any object we passed to 'setDelegate' would be fine.

The cctray XML looks like this:

[source,text]
----

<Projects>
  <Project name="Project 1 :: Fast" activity="Sleeping" lastBuildStatus="Success" lastBuildLabel="3.0.754" lastBuildTime="2009-07-27T14:17:19" webUrl="http://localhost:8153/cruise/tab/stage/detail/enterprisecorp-3/3.0.754/build/1" />
...
</Projects>
----

Since we're mostly interested in getting the attributes of each 'Project' element we want to provide an implementation for the 'parser:didStartElement:namespaceURI:qualifiedName:attributes:' method on our 'XMLParser' object.

The 'attributes' part of this method is what we're interested in and we can extract the data we're interested in with the following code:

[source,objc]
----

...
@implementation XMLParser
...
- (XMLParser *) initXMLParser {	
	[super init];
	return self;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
	attributes:(NSDictionary *)attributeDict {
	
	if([elementName isEqualToString:@"Project"]) {		
		NSString *name = [attributeDict objectForKey:@"name"];
		NSString *lastBuildStatus = [attributeDict objectForKey:@"lastBuildStatus"];
		...
	}
}
...
@end
----

If we were interested in getting the actual body of any of the elements then we'd need to implement the 'parser:foundCharacters:' method but in this case what I want to do is much simpler so that's unnecessary.

I found the event driven approach to parsing XML quite interesting and it http://www.markhneedham.com/blog/2010/03/21/node-js-a-little-application-with-twitter-couchdb/[reminds me a bit of node.js] and its approach to dealing with web requests by raising various events. Perhaps it's just that http://en.wikipedia.org/wiki/Confirmation_bias[I've started to notice] it but the event driven approach seems to be more prevalent these days.