Skip to content

Instantly share code, notes, and snippets.

@nsdevaraj
Last active September 21, 2020 22:18
Show Gist options
  • Save nsdevaraj/4620615 to your computer and use it in GitHub Desktop.
Save nsdevaraj/4620615 to your computer and use it in GitHub Desktop.
Load Local XML info in Objective C, get the objects into a Dictionary
<Subjects>
<Subject name='Kannada' user="APPUSERIESKANNADA"/>
<Subject name='The Looney Tunes Show'>
<Topic code="looney" name="Looney" YTTV="true" />
<Topic code="619C868BD457387C" name="Baby Looney Tunes" />
<Topic code="6F2996C1B34A5FC4" name="The Looney Tunes Show" />
<Topic code="738A89379AF8DD2A" name="Bugs Bunny " />
<Topic code="A2C5018B54365C3C" name="Daffy Duck" />
<Topic code="D572048819F3CE24" name="Duck Dodgers" />
<Topic code="82C2B02BE527E534" name="Looney Tunes" />
</Subject>
</Subjects>
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController{
UITableView *tableview;
NSMutableArray *subjectsArray;
}
@property (nonatomic, retain) IBOutlet UITableView *tableView;
@end
#import "ViewController.h"
#import "XMLReader.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSError *error = nil;
NSString *path=[[NSBundle mainBundle] pathForResource:@"cartoon" ofType:@"xml"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *_xmlDictionary = [XMLReader dictionaryForXMLString:s error:&error];
subjectsArray = [[_xmlDictionary objectForKey:@"Subjects"] objectForKey:@"Subject"];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [subjectsArray count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return @"@Channels";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"StatusCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cell.textLabel.font = [UIFont systemFontOfSize:12];
cell.textLabel.numberOfLines = 2;
cell.detailTextLabel.font = [UIFont systemFontOfSize:10];
cell.selectionStyle = UITableViewCellEditingStyleNone;
}
// Get the 'status' for the relevant row
NSDictionary *status = [subjectsArray objectAtIndex: indexPath.row];
cell.textLabel.text = [status objectForKey:@"@name"];
cell.detailTextLabel.text = [status objectForKey:@"@user"];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
#import <Foundation/Foundation.h>
@interface XMLReader : NSObject <NSXMLParserDelegate>
{
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError * __autoreleasing *errorPointer;
}
+ (NSDictionary *)dictionaryForPath:(NSString *)path error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
@end
@interface NSDictionary (XMLReaderNavigation)
- (id)retrieveForPath:(NSString *)navPath;
@end
#import "XMLReader.h"
NSString *const kXMLReaderTextNodeKey = @"text";
@interface XMLReader (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
@end
@implementation NSDictionary (XMLReaderNavigation)
- (id)retrieveForPath:(NSString *)navPath
{
// Split path on dots
NSArray *pathItems = [navPath componentsSeparatedByString:@"."];
// Enumerate through array
NSEnumerator *e = [pathItems objectEnumerator];
NSString *path;
// Set first branch from self
id branch = [self objectForKey:[e nextObject]];
int count = 1;
while ((path = [e nextObject]))
{
// Check if this branch is an NSArray
if([branch isKindOfClass:[NSArray class]])
{
if ([path isEqualToString:@"last"])
{
branch = [branch lastObject];
}
else
{
if ([branch count] > [path intValue])
{
branch = [branch objectAtIndex:[path intValue]];
}
else
{
branch = nil;
}
}
}
else
{
// branch is assumed to be an NSDictionary
branch = [branch objectForKey:path];
}
count++;
}
return branch;
}
@end
@implementation XMLReader
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForPath:(NSString *)path error:(NSError **)errorPointer
{
NSString *fullpath = [[NSBundle bundleForClass:self] pathForResource:path ofType:@"xml"];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:fullpath];
NSDictionary *rootDictionary = [XMLReader dictionaryForXMLData:data error:errorPointer];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLReader *reader = [[XMLReader alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSArray* lines = [string componentsSeparatedByString:@"\n"];
NSMutableString* strData = [NSMutableString stringWithString:@""];
for (int i = 0; i < [lines count]; i++)
{
[strData appendString:[[lines objectAtIndex:i] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
NSData *data = [strData dataUsingEncoding:NSUTF8StringEncoding];
return [XMLReader dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if ((self = [super init]))
{
errorPointer = error;
}
return self;
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
// Return the stack's root dictionary on success
if (success)
{
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
// Initialize child dictionary with the attributes, prefixed with '@'
for (NSString *key in attributeDict) {
[childDict setValue:[attributeDict objectForKey:key]
forKey:[NSString stringWithFormat:@"@%@", key]];
}
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue)
{
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]])
{
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else
{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else
{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Pop the current dict
[dictionaryStack removeLastObject];
// Set the text property
if ([textInProgress length] > 0)
{
if ([dictInProgress count] > 0)
{
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
}
else
{
// Given that there will only ever be a single value in this dictionary, let's replace the dictionary with a simple string.
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
id parentObject = [parentDict objectForKey:elementName];
// Parent is an Array
if ([parentObject isKindOfClass:[NSArray class]])
{
[parentObject removeLastObject];
[parentObject addObject:textInProgress];
}
// Parent is a Dictionary
else
{
[parentDict removeObjectForKey:elementName];
[parentDict setObject:textInProgress forKey:elementName];
}
}
textInProgress = [[NSMutableString alloc] init];
}
// If there was no value for the tag, and no attribute, then remove it from the dictionary.
else if ([dictInProgress count] == 0)
{
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
[parentDict removeObjectForKey:elementName];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
if (errorPointer)
*errorPointer = parseError;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment