Home > API General, iPhone/IPad, Version 3.1 Services > Using SWS on iPhone/iPad – Part 2 Parsing the XML response

Using SWS on iPhone/iPad – Part 2 Parsing the XML response


SAX vs. DOM

As we begin, I want to explain the most important difference between XML parsers, whether the parser is a SAX or a DOM parser.
  • A SAX parser is one where your code is notified as the parser walks through the XML tree, and you are responsible for keeping track of state and constructing any objects you might want to keep track of the data as the parser marches through.
  • A DOM parser reads the entire document and builds up an in-memory representation that you can query for different elements. Often, you can even construct XPath queries to pull out particular pieces.
Alright, now let’s discuss some of the libraries!

XML Parsers for the iPhone

In the iphone SDK the two choices are:
  • NSXMLParser is a SAX parser included by default with the iPhone SDK. It’s written in Objective-C and is quite straightforward to use, but perhaps not quite as easy as the DOM model.  It is the fastest parser in terms of parsing xml from start to finish.
  • libxml2 is an Open Source library that is included by default with the iPhone SDK. It is a C-based API, so is a bit more work to use than NSXML. The library supports both DOM and SAX processing. The libxml2 SAX processor is especially cool, as it has a unique feature of being able to parse the data as it’s being read. For example, you could be reading a large XML document from the network and displaying data that you’re reading for it to the user while you’re still downloading. Therefore, while this parser is slower than NSXMLParser from start to finish, the user experience is improved in the case of large xml documents.
If you’re wondering about memory usage, it’s a wash if you’re comparing SAX parsers.  If you implement DOM parser you will incur a greater memory usage.  There are other 3rd party libraries
which provide other DOM capabilities such as XPath functionality.  If you get into parsing complex xml structures these may be a good consideration. For our purposes we will use NSXMLParser.  I’ve found it to be the path of least resistance and it really wants to be friendly so we’ll play along.

The XML

As we are calling the site list method we will be getting back xml that follows the format documented at: http://host05slc.centershift.com/iService/iService1.asmx?op=GetSiteList
Here’s the response format:
xml version=”1.0″ encoding=”utf-8″?>
<soap:Body>
<GetSiteListResponse xmlns=”http://centershift.com/”&gt;

<GetSiteListResult>

<Facility>

<SiteName>string</SiteName>

<SiteId>string

<DistanceTo>string</DistanceTo>

</Facility>

<Facility>

<SiteName>string</SiteName>

<SiteId>string</SiteId>

<DistanceTo>string</DistanceTo>

</Facility>

</GetSiteListResult>

</GetSiteListResponse>

</soap:Body>
</soap:Envelope>
We want to parse through all the ‘Facility’ elements and grab the SiteName and SiteId to display them in a list.  To launch the parsing process we will want to add some code to the connectionDidFinishLoading method.
– (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//Manipulate data here and release Data and Connection
NSLog(@”Succeeded!
Received %d bytes of data\n”,[webData length]);
NSString *theXml = [[NSString alloc]initWithBytes:[webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
[theXml release];
// Parse received xml from web service
// XMLParse declared in the header
myParser= [[NSXMLParser alloc] initWithData: webData];
[myParser setDelegate:self];
// Depending on the XML document you’re parsing, you may want to enable these features of NSXMLParser.
[myParser setShouldProcessNamespaces:NO];
[myParser setShouldReportNamespacePrefixes:NO];
[myParser setShouldResolveExternalEntities:NO];
[myParser parse];
// release the connection, and the data object
[connection release];
[webData release];
}
Now it’s time to delve into the parser object methods.  First let’s deal with handling errors thrown during the parse process with the parseErrorOccurred method.
– (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSString * errorString = [NSString stringWithFormat:@”Unable to download feed from web service (Error code %i )”, [parseError code]];
NSLog(@”error parsing XML: %@”, errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@”Error loading content” message:errorString delegate:self
cancelButtonTitle:@”OK” otherButtonTitles:nil];
[errorAlert show];
}
At this point in the didStartElement method we will do our work to clear out the item cache and initialize a new one when we find the start of the ‘Facility’ element.
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName

 

namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict

 

{
currentElement=[elementName copy];
if
([elementName isEqualToString:@”Facility”])
{
[currentSite release];
currentSite = [[Site alloc] init];
}}
As the parser parses the Facility element we will append the strings to the two items in our ‘currentSite’ object, namely ‘siteName’ and ‘siteId’.
– (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// save the characters for the current item…
if
([currentElement isEqualToString:@”SiteName”])
{
currentSite.siteName = [currentSite.siteName stringByAppendingString:string];
}
else if
([currentElement isEqualToString:@”SiteId”])
{
currentSite.siteId = [currentSite.siteId stringByAppendingString:string];
}}
The next method lets us deal with whatever we want to do once the parser finds the end element.  In this case we will add the object ‘currentSite’ to our collection or array of objects  ‘allSites’.
– (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if
([elementName isEqualToString:@”Facility”])
{
// save values to an item, then store that item into the array…
[allSites addObject:currentSite];
}}
Lastly, when the parser reaches the end of the xml document we’ll want to perform whatever garbage collection we need to do.  Also, here I allocate a new array of the Sitelist and  load the data into a table which is displayed in the view.  It’s also a good point to stop the animation of the busy Signal so the user has a good experience.
– (void)parserDidEndDocument:(NSXMLParser *)parser
{
// set mySites to allSites
[mySites release];
mySites = [[NSArray alloc] initWithArray:allSites];
[sitelistTable reloadData];
// Stop Indicator
[busySignal stopAnimating];
}
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s