NSXMLParser Simple Example
As part of exploring the NSXMLParser I created the following really simple code.
main.m
int main(int argc, const char * argv[]){ @autoreleasepool { NSLog(@"Main Started"); NSError *error = nil; // Load the file and check the result NSData *data = [NSData dataWithContentsOfFile:@"/Users/Tim/Documents/MusicXml/Small.xml" options:NSDataReadingUncached error:&error]; if(error) { NSLog(@"Error %@", error); return 1; } // Create a parser and point it at the NSData object containing the file we just loaded NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; // Create an instance of our parser delegate and assign it to the parser MyXmlParserDelegate *parserDelegate = [[MyXmlParserDelegate alloc] init]; [parser setDelegate:parserDelegate]; // Invoke the parser and check the result [parser parse]; error = [parser parserError]; if(error) { NSLog(@"Error %@", error); return 1; } // All done NSLog(@"Main Ended"); } return 0;}
MyXmlParserDelegate.h
#import <Foundation/Foundation.h>@interface MyXmlParserDelegate : NSObject <NSXMLParserDelegate>@end
MyXmlParserDelegate.m
#import "MyXmlParserDelegate.h"@implementation MyXmlParserDelegate- (void) parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"parserDidStartDocument");}- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { NSLog(@"didStartElement --> %@", elementName);}-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { NSLog(@"foundCharacters --> %@", string);}- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"didEndElement --> %@", elementName);}- (void) parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"parserDidEndDocument");}@end
I've posted it in the hope that it helps someone else.
Swift 4 Example - Parsing Xib-file.
import Foundationclass XMLTransformer: NSObject { private let parser: XMLParser private var stack = [Node]() private var tree: Node? init(data: Data) { parser = XMLParser(data: data) super.init() parser.delegate = self }}extension XMLTransformer { func transform() throws -> Node? { parser.parse() if let e = parser.parserError { throw e } assert(stack.isEmpty) assert(tree != nil) return tree }}extension XMLTransformer: XMLParserDelegate { func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { guard let tag = Tag(rawValue: elementName) else { return } let node = Node(tag: tag, attributes: attributeDict, nodes: []) stack.append(node) } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { guard let tag = Tag(rawValue: elementName) else { return } let lastElement = stack.removeLast() assert(lastElement.tag == tag) if let last = stack.last { last.nodes += [lastElement] } else { tree = lastElement } }}extension XMLTransformer { enum Tag: String { case document case objects case tableViewCell, tableViewCellContentView case subviews case mapView case constraints, constraint case connections, outlet }}extension XMLTransformer { class Node { let tag: Tag let attributes: [String : String] var nodes: [Node] init(tag: Tag, attributes: [String : String], nodes: [Node] = []) { self.tag = tag self.attributes = attributes self.nodes = nodes } }}
Usage:
let data = try xib(named: "MapTableViewCell")let c = XMLTransformer(data: data)let tree = try c.transform() // Here you have parsed XML in a Tree representation.
#import <Cocoa/Cocoa.h>@interface AppDelegate : NSObject <NSApplicationDelegate, NSXMLParserDelegate>@property (nonatomic, strong) NSMutableDictionary *dictXML;@property (nonatomic,strong) NSMutableArray *arrOfUpdateDictsByVersion;@property (nonatomic,strong) NSString *strElementBeingParsed;@property (nonatomic,strong) NSString *strElementFinishedParsing;@end#import "AppDelegate.h"@interface AppDelegate ()@property (weak) IBOutlet NSWindow *window;@end@implementation AppDelegate@synthesize dictXML;@synthesize arrOfUpdateDictsByVersion;@synthesize strElementBeingParsed;@synthesize strElementFinishedParsing;- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application [self initializeTheArray]; [self startParsingXML];}-(void)initializeTheArray{ self.dictXML = [[NSMutableDictionary alloc] init]; self.arrOfUpdateDictsByVersion = [[NSMutableArray alloc] init];}-(void)startParsingXML{// NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://cdn.example.com/databaseupdate.xml"]]; NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@"/Users/vkrmsinha/Desktop/xmlParse.xml"]]; [xmlparser setDelegate:self]; [xmlparser parse];}- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;{ // initial tag comes in here self.strElementBeingParsed = elementName; /*if([elementName isEqualToString:@"Version"]){ } else if ([elementName isEqualToString:@"Update"]){ }*/}- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;{ if(([string rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location != NSNotFound) && ![self.strElementBeingParsed isEqualToString:@"Update"]) return; // middle part from between the start and end tags comes here if ([self.strElementBeingParsed isEqualToString:@"Update"]){ NSMutableDictionary *dictUpdate = [NSMutableDictionary dictionary]; [self.arrOfUpdateDictsByVersion addObject:dictUpdate]; } else if ([self.strElementBeingParsed isEqualToString:@"UpdateType"]){ NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject]; NSMutableDictionary *dictUpd = [NSMutableDictionary dictionary]; [dictUpd setValue:string forKey:@"UpdateType"]; [dictUpdate setValue:dictUpd forKey:@"update"]; } else if([self.strElementBeingParsed isEqualToString:@"Version"]){ NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject]; // WARNING: ASK IF NO TWO VERSION WILL BE SAME IN FUTURE [dictUpdate setValue:string forKey:@"version"]; } else if ([self.strElementBeingParsed isEqualToString:@"FileName"]){ NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject]; NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"]; [dict setValue:string forKey:@"FileName"]; } else if ([self.strElementBeingParsed isEqualToString:@"Hash"]){ NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject]; NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"]; [dict setValue:string forKey:@"Hash"]; } else if ([self.strElementBeingParsed isEqualToString:@"DownloadURL"]){ NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject]; NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"]; [dict setValue:string forKey:@"DownloadURL"]; } else if ([self.strElementBeingParsed isEqualToString:@"Size"]){ NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject]; NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"]; [dict setValue:string forKey:@"Size"]; }}- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;{ // ending of tag comes in here self.strElementFinishedParsing = elementName; if([elementName isEqualToString:@"Update"]){ [self.arrOfUpdateDictsByVersion sortUsingDescriptors:[NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"self.version" ascending:YES], nil]]; NSLog(@"%@", [self.arrOfUpdateDictsByVersion lastObject]); } if([elementName isEqualToString:@"UpdateDetails"]){ NSMutableDictionary *dict = [NSMutableDictionary dictionary]; [dict setValue:[[self.arrOfUpdateDictsByVersion lastObject] objectForKey:@"version"] forKey:@"latestVer"]; [dict setValue:[[self.arrOfUpdateDictsByVersion firstObject] objectForKey:@"version"] forKey:@"oldestVer"]; [dict setValue:self.arrOfUpdateDictsByVersion forKey:@"arrOfUpdsByVer"]; NSLog(@"%@", dict); }}- (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application}<UpdateDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <DatabaseUpdates> <Update> <UpdateType>CompleteDatabase</UpdateType> <Version>1</Version> <FileName>1completedatabase.zip</FileName> <Hash>ad94431d2fe4cd60eb3347fadaa45d88</Hash> <DownloadURL> http://www.example.com/download/new.xml </DownloadURL> <Size>2367008</Size> </Update></DatabaseUpdates></UpdateDetails>