Parsing XML data with NSXMLParser

From Cswiki
Jump to: navigation, search

Contents

Introduction

Objective C NSXMLParser is an event driven parser. When an instance of this class pareses an XM document it notifies its delegate about the items (elements, attributes, etc) that it encounters during XML processing. It does not itself do anything with the parsed items – it expects the delegate to implement this code.

Implementation example

In this example we implement three main NSXMLPraser events:

  • NSXMLParser hits the start of an element - parser:didStartElement:namespaceURI:qualifiedName:attributes method notified
  • NSXMLParser hits an element value - parser:foundCharacters method notified
  • NSXMLParser hits the end of an element - parser:didEndElement:namespaceURI:qualifiedName method notified

XML document structure used in this example:

<users>
 <user>
  <userName>mspeller</userName>
  <firstName>Mike</firstName>
  <lastName>Speller</lastName>
 </user>
 <user>
  <userName>mgdan</userName>
  <firstName>Mila</firstName>
  <lastName>Gdan</lastName>
 </user>
...
</users>

Class to store user data

First create a class to store parsed user data:

#import <Foundation/Foundation.h>

@interface User : NSObject {
  NSString *userName;   
  NSString *firstName;      
  NSString *lastName;      
}

@property (nonatomic, retain) NSString *userName;
@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *lastName;

@end

Implementation:

#import "User.h"

@implementation User
@synthesize userName, firstName, lastName;

- (void) dealloc {
  [userName release];
  [firstName release];
  [lastName release];
  [super dealloc];
}

@end

Note : We make the class property names match the XML document element names.

Create a delegate for NSXMLParser

Let's create a delegate for the parser XMLParser.h - it implements the three events reported by NSXMLParser object:


#import <Foundation/Foundation.h>

@class User;

@interface XMLParser : NSObject {
  // an ad hoc string to hold element value
  NSMutableString *currentElementValue;
  // user object
  User *user;
  // array of user objects
  NSMutableArray *users;
}

@property (nonatomic, retain) User *user;
@property (nonatomic, retain) NSMutableArray *users;

- (XMLParser *) initXMLParser;

@end

The delegate implementation – XMLParser.m file:


#import "XMLParser.h"
#import "User.h";

@implementation XMLParser
@synthesize user, users;

- (XMLParser *) initXMLParser {
  [super init];
  // init array of user objects 
  users = [[NSMutableArray alloc] init];
  return self;
}

...

Parse the start of an element

Implement method called NSXMLParser when it hits the start of an element:

...

// XMLParser.m 
- (void)parser:(NSXMLParser *)parser 
               didStartElement:(NSString *)elementName 
               namespaceURI:(NSString *)namespaceURI 
               qualifiedName:(NSString *)qualifiedName 
	       attributes:(NSDictionary *)attributeDict {
	
  if ([elementName isEqualToString:@"user"]) {
     NSLog(@"user element found – create a new instance of User class...");
     user = [[User alloc] init];
     //We do not have any attributes in the user elements, but if
     // you do, you can extract them here: 
     // user.att = [[attributeDict objectForKey:@"<att name>"] ...];
  }
}

...

Parse an element value

Implement method called NSXMLParser when it hits an element value. In this method we capture the element value into currentElementValue ad hoc string:

...

// XMLParser.m
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
  if (!currentElementValue) {
     // init the ad hoc string with the value     
     currentElementValue = [[NSMutableString alloc] initWithString:string];
  } else {
     // append value to the ad hoc string    
    [currentElementValue appendString:string];
  }
  NSLog(@"Processing value for : %@", string);
}  

...

Parse the end of an element

Implement method called NSXMLParser when it hits the end of an element:

...

//XMLParser.m
- (void)parser:(NSXMLParser *)parser 
               didEndElement:(NSString *)elementName
               namespaceURI:(NSString *)namespaceURI 
               qualifiedName:(NSString *)qName {

  if ([elementName isEqualToString:@"users"]) {
     // We reached the end of the XML document
     return;
  }

  if ([elementName isEqualToString:@"user"]) {
     // We are done with user entry – add the parsed user 
     // object to our user array
     [users addObject:user];
     // release user object
     [user release];
     user = nil;
  } else {
     // The parser hit one of the element values. 
     // This syntax is possible because User object 
     // property names match the XML user element names   
     [user setValue:currentElementValue forKey:elementName];
  }

  [currentElementValue release];
  currentElementValue = nil;
}

// end of XMLParser.m file

NSXMLParser call example

NSData *data contains our XML document.


#import "XMLParser.h"

...

- (void) doParse:(NSData *)data {

  // create and init NSXMLParser object
  NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:data];

  // create and init our delegate
  XMLParser *parser = [[XMLParser alloc] initXMLParser];

  // set delegate
  [nsXmlParser setDelegate:parser];

  // parsing...
  BOOL success = [nsXmlParser parse];

  // test the result
  if (success) {
     NSLog(@"No errors - user count : %i", [parser [users count]]);
     // get array of users here
     //  NSMutableArray *users = [parser users];
  } else {
    NSLog(@"Error parsing document!");
  }

  [parser release];
  [nsXmlParser release];

}

...
Personal tools