Objective-C: Use NSXMLParser

xcode Almost any time you’ll need to pull some data from the web. Using Objective-C you have at your disposal a pretty good XML parser – the event-based version. What really means is that instead of building in-memory tree with the structure of the XML you’ll have some events raised when the parser encounters a special token – the most usual ones are tag start, tag end and found comments. The parsing goes node by node and is not nesting-sensitive. As soon as the parser returns you a node, you don’t know where in the structure you are currently anymore. As long as you have a clearly defined structure where each element is always present, you could do this using a counter. However, as soon as you have multiple nodes with no defined count, you have a problem.

The usage is simple and straight-forward. For simplicity, we assume that we have only have one level of children under the root node, but this can be easily extended to many levels.  We’ll see some code and after that the detailed explanations:

- (void)parseJourneyData:(NSData *)data parseError:(NSError **)err {     
// create and allocate the parser - it must be initiated with the XML data that we received or loaded     
NSXMLParser *xmlParser= [[NSXMLParser alloc] initWithData:data];
  self.arrResult= [[NSMutableArray alloc] init];
  // Create the array for holding the resulted data
  [xmlParser setDelegate:self];
  // The parser calls will be redirected to methods in this class
  [xmlParser setShouldProcessNamespaces:NO];
  // We are not interested in namespaces
  [xmlParser setShouldReportNamespacePrefixes:NO];
  // neither in prefixes
  [xmlParser setShouldResolveExternalEntities:NO];
  // just data, no other stuff
  [xmlParserparse];
  // Parse that data.. here the parsing begins and the delegated methods will get called
  //the parsing process ended and we check for errors
  if (err && [xmlParser parserError]) {
	*err = [xmlParser parserError];     
  }  
  [xmlParser release];
  //cleaning the remainders
  }     

The next step is to implement the  delegate methods. The easiest way to find them is to start the help system of XCode – while in IDE, keep the Alt key pressed until the cursor transforms into an cross and then double click on the element for which help is required, in our case NSXMLParser. In the window that appears, you’ll find easily the methods declarations as follows and you’ll notice that they are pretty descriptive by themselfs:

- (void)parser:(NSXMLParser *)parser
    idStartElement:(NSString *)elementName
    namespaceURI:(NSString *)namespaceURI
    qualifiedName:(NSString *)qName
    attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser
	foundCharacters:(NSString *)string;
- (void)parser:(NSXMLParser *)parser
	idEndElement:(NSString *)elementName
    namespaceURI:(NSString *)namespaceURI
    qualifiedName:(NSString *)qName;

Now let’s fill them with some code:

- (void)parser:(NSXMLParser *)parser
 didStartElement:(NSString *)elementName
 namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
 attributes:(NSDictionary *)attributeDict {
    if (qName) {
       elementName = qName;
    }     
    // alloc the current property
    self.currentProperty = [NSMutableString string];
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string     {
    if (self.currentProperty) {
      [currentProperty appendString:string];
    }
}     

- (void)parser:(NSXMLParser *)parser 
  didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
  qualifiedName:(NSString *)qName {
    if (qName) {
      elementName = qName;
    }
    [arrResult addObject:self.currentProperty];
    // We reset the currentProperty, for the next textnodes..
    self.currentProperty = nil;
}

That’s pretty much it. Happy coding!