Last active
December 14, 2015 18:59
-
-
Save mrtj/5132831 to your computer and use it in GitHub Desktop.
Simple DOM based XML parser #cocoa #xml #parser #utils #dom
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@interface TJXMLElement : NSObject | |
@property (nonatomic, readonly) NSString* name; | |
@property (nonatomic, readonly) NSDictionary* attributes; | |
@property (nonatomic, retain) NSMutableArray* children; | |
@property (nonatomic, retain) NSMutableString* text; | |
- (id) initWithName:(NSString*)name withAttributes:(NSDictionary*)attributes; | |
- (TJXMLElement*) childWithName:(NSString*)name; | |
- (NSArray*) childrenWithName:(NSString*)name; | |
@end | |
@interface TJXMLParser : NSObject <NSXMLParserDelegate> { | |
@private | |
NSXMLParser* _parser; | |
NSMutableArray* _parentList; | |
} | |
- (id) initWithContentsOfURL:(NSURL *)url; | |
- (id) initWithData:(NSData *)data; | |
- (TJXMLElement*) parse; | |
@property (nonatomic, retain) TJXMLElement* currentElement; | |
@property (nonatomic, retain) TJXMLElement* rootElement; | |
@property (nonatomic, retain) NSError* parseError; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "TJXMLParser.h" | |
@implementation TJXMLElement | |
@synthesize name = _name; | |
@synthesize attributes = _attributes; | |
@synthesize children = _children; | |
@synthesize text = _text; | |
- (id) initWithName:(NSString*)name withAttributes:(NSDictionary*)attributes | |
{ | |
self = [super init]; | |
if (self != nil) { | |
_name = [name retain]; | |
_attributes = [attributes retain]; | |
_children = [[NSMutableArray alloc] init]; | |
_text = [[NSMutableString alloc] init]; | |
} | |
return self; | |
} | |
- (void) dealloc | |
{ | |
[_name release]; _name = nil; | |
[_attributes release]; _attributes = nil; | |
self.children = nil; | |
self.text = nil; | |
[super dealloc]; | |
} | |
- (NSString *)description | |
{ | |
NSMutableString* desc = [[[NSMutableString alloc] initWithString:[super description]] autorelease]; | |
[desc appendFormat:@"\nName: %@\nAttributes: %@\nText: %@\nChildren: %d item(s)\n", | |
self.name, | |
[self.attributes count] > 0 ? [self.attributes description] : @"nil", | |
[self.text length] > 0 ? self.text : @"nil", | |
[self.children count]]; | |
return desc; | |
} | |
- (TJXMLElement*) childWithName:(NSString*)name | |
{ | |
for (TJXMLElement* child in self.children) { | |
if ([name isEqualToString:child.name]) | |
return child; | |
} | |
return nil; | |
} | |
- (NSArray*) childrenWithName:(NSString*)name | |
{ | |
NSMutableArray* results = [NSMutableArray array]; | |
for (TJXMLElement* child in self.children) { | |
if ([name isEqualToString:child.name]) | |
[results addObject:child]; | |
} | |
return results; | |
} | |
@end | |
@interface TJXMLParser () | |
- (void) construct; | |
@end | |
@implementation TJXMLParser | |
@synthesize currentElement = _currentElement; | |
@synthesize rootElement = _rootElement; | |
@synthesize parseError = _parseError; | |
#pragma mark Init & dealloc | |
- (id) initWithContentsOfURL:(NSURL *)url | |
{ | |
self = [super init]; | |
if (self != nil) { | |
_parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; | |
[self construct]; | |
} | |
return self; | |
} | |
- (id) initWithData:(NSData *)data | |
{ | |
self = [super init]; | |
if (self != nil) { | |
_parser = [[NSXMLParser alloc] initWithData:data]; | |
[self construct]; | |
} | |
return self; | |
} | |
- (void) construct | |
{ | |
_parser.delegate = self; | |
_parentList = [[NSMutableArray alloc] init]; | |
} | |
- (void) dealloc | |
{ | |
[_parser release]; _parser = nil; | |
[_parentList release]; _parentList = nil; | |
self.currentElement = nil; | |
self.rootElement = nil; | |
self.parseError = nil; | |
[super dealloc]; | |
} | |
#pragma mark Parsing | |
- (TJXMLElement*) parse | |
{ | |
BOOL result = [_parser parse]; | |
if (result) { | |
return [[self.rootElement retain] autorelease]; | |
} else { | |
return nil; | |
} | |
} | |
#pragma mark NSXMLParserDelegate implementation | |
- (void)parserDidStartDocument:(NSXMLParser *)parser | |
{ | |
self.currentElement = nil; | |
self.rootElement = nil; | |
self.parseError = nil; | |
} | |
- (void)parser:(NSXMLParser *)parser | |
didStartElement:(NSString *)elementName | |
namespaceURI:(NSString *)namespaceURI | |
qualifiedName:(NSString *)qualifiedName | |
attributes:(NSDictionary *)attributeDict | |
{ | |
TJXMLElement* newElement = [[[TJXMLElement alloc] initWithName:elementName withAttributes:attributeDict] autorelease]; | |
if (self.currentElement) { | |
TJXMLElement* parentElement = self.currentElement; | |
[_parentList addObject:parentElement]; | |
[parentElement.children addObject:newElement]; | |
} else { | |
self.rootElement = newElement; | |
} | |
self.currentElement = newElement; | |
} | |
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string | |
{ | |
[self.currentElement.text appendString:string]; | |
} | |
- (void)parser:(NSXMLParser *)parser | |
didEndElement:(NSString *)elementName | |
namespaceURI:(NSString *)namespaceURI | |
qualifiedName:(NSString *)qName | |
{ | |
if (![elementName isEqualToString:self.currentElement.name]) { | |
// this is just to be sure, the parser would report an error before | |
[parser abortParsing]; | |
} | |
self.currentElement = [_parentList lastObject]; | |
[_parentList removeLastObject]; | |
} | |
- (void)parserDidEndDocument:(NSXMLParser *)parser | |
{ | |
if (self.currentElement != nil || [_parentList count] > 0) { | |
// this is just to be sure, the parser would report an error before | |
[parser abortParsing]; | |
} | |
} | |
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError | |
{ | |
self.parseError = parseError; | |
self.rootElement = nil; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment