Parsing XML data with NSXMLParser
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];
}
...