Tutorial :Best approach for XML parsing on the iPhone



Question:

I've familiarized myself with the NSXMLParser from the iPhone SDK but I find the event-driven nature of it awkward for my purposes. I just want to extract some element values but this concept of having to handle the startElement, foundCharacters, and endElement seems like more work than it really should be. Am I just looking at this the wrong way or is there a simpler tree/DOM-based way of working with XML in the iPhone SDK?

If the advice is to just work with NSXMLParser, are there certain design patterns I can use to keep my code from having 5 levels of nested ifs in the startElement method?


Solution:1

If you're on the iPhone, using tree-based parsing can be a prohibitive memory hog. Trust me, I've been there, and I've tried many different approaches over the last five months of development of my main iPhone application. Tree-based parsing works fine until you download someone's comment stream containing 400 very long comments, clocking in at about 600KB of raw data. Quite aside from the size of the resultant XML tree, the memory allocated internally while creating that tree can be enormous.

I wound up creating a variant of NSXMLParser which pulls data in from a supplied NSInputStream rather than using a single chunk of data, and which passes only 1KB at a time into libxml for handling (NSXMLParser uses libxml too, but passes 100% of the data in one go).

The source code is available on github (look in the StreamingXMLParser folder). You'll also find a delegate superclass in there; for most parsing needs you can subclass AQXMLParserDelegate and implement -start[Element]WithAttributes: (NSDictionary *) attrs and -end[Element] in your subclass. These methods will be called for you as start & end tags are discovered, and inside the end tag you can use self.characters to access the content characters or CDATA of the element.

For more on the relative memory footprints of the different parsers (albeit on the Mac, not the iPhone) see my original blog post here and the followup on NSXMLDocument here.


Solution:2

Consider the following code snippet, that uses libxml2, Matt Gallagher's libxml2 wrappers and Ben Copsey's ASIHTTPRequest to parse an XML document.

The nodes instance of type NSArray* will contain NSDictionary* objects that you can parse recursively to get the data you want.

Or, if you know the scheme of your XML document, you can write an XPath query to get you to a nodeContent or nodeAttribute value directly.

ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://stackoverflow.com/"];  [request start];  NSError *error = [request error];  if (!error) {      NSData *response = [request responseData];      NSLog(@"Root node: %@", [[self query:@"//" withResponse:response] description]);  }  else       @throw [NSException exceptionWithName:@"kHTTPRequestFailed" reason:@"Request failed!" userInfo:nil];  [request release];    ...    - (id) query:(NSString *)xpathQuery withResponse:(NSData *)respData {      NSArray *nodes = PerformXMLXPathQuery(respData, xpathQuery);      if (nodes != nil)          return nodes;      return nil;  }  


Solution:3

Repurposing the code from Seismic XML provides a very good API that creates NSObject subclasses from XML.

If the advice is to just work with NSXMLParser, are there certain design patterns I can use to keep my code from having 5 levels of nested ifs in the startElement method?

I depends on what you are trying to do. You could put your element names in a dictionary and take action based on the relevant object in a dictionary - this is effectively what SeismicXML does.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »