I would like to look through the elements of a file and when one specific element comes out, output the contents in between the tag.
I tried to follow the example in the
If you click the "Next" link on that page and go onto "Handling XML Elements and Attributes" it will give you an example of how to code the delegates.
Apple provides a Mac example in ImageMap.
There's no difference between NSXMLParser
on Mac and iPhone, so reading an iPhone example shouldn't be a problem.
This is based on something I originally wrote for Cut out a part of a long NSString. I copied the NSXMLParserDelegate code from that iOS project into an OS X project. It gets the text from a specific object in a web page.
.h file:
@interface so7576593AppDelegate : NSObject <NSApplicationDelegate, NSXMLParserDelegate> {
NSWindow *window;
IBOutlet NSTextField *textField;
NSMutableString *divCharacters;
BOOL captureCharacters;
}
@property (assign) IBOutlet NSWindow *window;
@end
.m file:
#import "so7576593AppDelegate.h"
@implementation so7576593AppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
captureCharacters = NO;
NSURL *theURL = [NSURL URLWithString:@"http://maxnerios.yolasite.com/"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:theURL];
[parser setDelegate:self];
[parser parse];
[parser release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqual:@"div"] && [[attributeDict objectForKey:@"id"] isEqual:@"I3_sys_txt"]) {
captureCharacters = YES;
divCharacters = [[NSMutableString alloc] initWithCapacity:500];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (captureCharacters) {
//from parser:foundCharacters: docs:
//The parser object may send the delegate several parser:foundCharacters: messages to report the characters of an element.
//Because string may be only part of the total character content for the current element, you should append it to the current
//accumulation of characters until the element changes.
[divCharacters appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (captureCharacters) {
captureCharacters = NO;
[textField setStringValue:divCharacters];
[divCharacters release];
}
}
@end
Here is an example of using an NSXMLParser
in a custom class that takes in a string of the tag to look for and the xml NSData:
JHXMLParser.h:
@protocol JHXMLParserDelegate <NSObject>
@optional
- (void)acceptParsedData:(NSMutableArray *)parsedData withIdent:(NSString *)ident;
- (void)acceptParsedDebugData:(NSMutableArray *)parsedData withIdent:(NSString *)ident;
@end
@class JHKeyValuePair;
@interface JHXMLParser : NSObject <NSXMLParserDelegate> {
NSString *ident;
@private
id _delegate;
NSMutableArray *_parsedData;
NSString *_key;
NSData *_rawData;
NSXMLParser *_dataParser;
NSString *_previousTag;
NSString *_currentTag;
}
@property (retain, nonatomic) NSString *ident;
- (id)initWithKeyValuePair:(JHKeyValuePair *)kvPair;
- (id)initWithKey:(NSString *)Key andData:(NSData *)data;
// delegate management. The delegate is not retained.
- (id <JHXMLParserDelegate>)delegate;
- (void)setDelegate:(id <JHXMLParserDelegate>)delegate;
- (BOOL)start;
@end
And the JHXMLParser.m:
#import "JHKeyValuePair.h"
#import "JHXMLParser.h"
@implementation JHXMLParser
@synthesize ident;
- (id)init {
if ((self = [super init])) {
ident = [[NSString alloc] init];
}
return self;
}
- (id)initWithKeyValuePair:(JHKeyValuePair *)kvPair {
if ((self = [self init])) {
_key = [kvPair key];
_rawData = [kvPair value];
_dataParser = [[NSXMLParser alloc] initWithData:_rawData];
_dataParser.delegate = self;
}
return self;
}
- (id)initWithKey:(NSString *)key andData:(NSData *)data {
if ((self = [self init])) {
_key = key;
_rawData = data;
_dataParser = [[NSXMLParser alloc] initWithData:_rawData];
_dataParser.delegate = self;
}
return self;
}
- (id <JHXMLParserDelegate>)delegate {
id <JHXMLParserDelegate> d = nil;
if (_delegate) {
d = _delegate;
}
return d;
}
- (void)setDelegate:(id <JHXMLParserDelegate>)delegate {
_delegate = delegate;
}
- (BOOL)start {
return [_dataParser parse];
}
- (void)dealloc {
[_parsedData release];
[_rawData release];
[super dealloc];
}
#pragma mark - NSXMLParser Delegate
- (void)parserDidStartDocument:(NSXMLParser *)parser {
_parsedData = [[NSMutableArray alloc] init];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
_currentTag = elementName;
if ([elementName isEqualToString:_key]) {
NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init];
[_parsedData addObject:tmpDict];
[tmpDict release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (![_previousTag isEqualToString:_currentTag]) {
[[_parsedData lastObject] setObject:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
forKey:_currentTag];
} else {
[[_parsedData lastObject] setObject:[NSString stringWithFormat:@"%@%@",[[_parsedData lastObject] objectForKey:_currentTag], [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]
forKey:_currentTag];
}
if (_previousTag) {
[_previousTag release];
_previousTag = nil;
}
_previousTag = [[NSString alloc] initWithFormat:@"%@", _currentTag];
[pool drain];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (![_previousTag isEqualToString:elementName]) {
[[_parsedData lastObject] setObject:@"" forKey:elementName];
} else {
if (_previousTag) {
[_previousTag release];
_previousTag = nil;
}
_previousTag = [[NSString alloc] initWithFormat:@""];
}
[pool drain];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
if ([_delegate respondsToSelector:@selector(acceptParsedData:withIdent:)]) {
[_delegate acceptParsedData:_parsedData withIdent:ident];
} else if ([_delegate respondsToSelector:@selector(acceptParsedDebugData:withIdent:)]) {
[_delegate acceptParsedDebugData:_parsedData withIdent:ident];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
#ifdef DEBUG
DEBUGLOG(@"Parser ERROR Occurred: %@", self.ident);
DEBUGLOG(@"ERROR: %@", parseError);
#endif
if ([_delegate respondsToSelector:@selector(acceptParsedData:withIdent:)]) {
[_delegate acceptParsedData:_parsedData withIdent:ident];
} else if ([_delegate respondsToSelector:@selector(acceptParsedDebugData:withIdent:)]) {
[_delegate acceptParsedDebugData:_parsedData withIdent:ident];
}
}
@end
Used like so:
parser = [[[JHXMLParser alloc] initWithKey:@"INFO" andData:connectData] autorelease];
parser.ident = @"INFO";
parser.delegate = self;
[parser start];
Then implement the delegate method:
- (void)acceptParsedData:(NSMutableArray *)parsedData withIdent:(NSString *)ident {
// do stuff here with the parsed data
}