mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-05 17:40:47 +08:00
254 lines
7.0 KiB
Objective-C
254 lines
7.0 KiB
Objective-C
//
|
|
// XMLReader.m
|
|
//
|
|
|
|
#import "XMLReader.h"
|
|
|
|
NSString *const kXMLReaderTextNodeKey = @"text";
|
|
NSString *const kXMLReaderAttributePrefix = @"";
|
|
|
|
@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];
|
|
[reader release];
|
|
|
|
return rootDictionary;
|
|
}
|
|
|
|
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
|
|
{
|
|
NSData *data = [string 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;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[dictionaryStack release];
|
|
[textInProgress release];
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
- (NSDictionary *)objectWithData:(NSData *)data
|
|
{
|
|
// Clear out any old data
|
|
[dictionaryStack release];
|
|
[textInProgress release];
|
|
|
|
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];
|
|
[parser release];
|
|
|
|
// 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:@"%@%@", kXMLReaderAttributePrefix, 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];
|
|
}
|
|
}
|
|
|
|
// Reset the text
|
|
[textInProgress release];
|
|
textInProgress = [[NSMutableString alloc] init];
|
|
}
|
|
}
|
|
|
|
- (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 |