diff --git a/Classes/MWFeedItem.h b/Classes/MWFeedItem.h index 936ce60..fffdf6f 100644 --- a/Classes/MWFeedItem.h +++ b/Classes/MWFeedItem.h @@ -45,7 +45,18 @@ // length: how big it is in bytes (NSNumber) // type: what its type is, a standard MIME type (NSString) NSArray *enclosures; - + + // Rick Russell (@ossmac) 12/28/2011 + // + // CustomProperties: is a NSDictionary that contains any items that were + // requested in the feed request by passing in a NSArray of NSStrings with the + // keys to parse + // - NSDictionary will contain keys matching the values passed in the NSArray + // and the values will be NSStrings of the values for that key if they are + // found in the item being parsed. If the key is not found for the item in + // the XML being parsed it will be nil. + NSDictionary *customProperities; + } @property (nonatomic, copy) NSString *identifier; @@ -56,5 +67,7 @@ @property (nonatomic, copy) NSString *summary; @property (nonatomic, copy) NSString *content; @property (nonatomic, copy) NSArray *enclosures; +@property (nonatomic, copy) NSDictionary *customProperties; @end + diff --git a/Classes/MWFeedItem.m b/Classes/MWFeedItem.m index 127a0e7..936b0d4 100644 --- a/Classes/MWFeedItem.m +++ b/Classes/MWFeedItem.m @@ -33,7 +33,7 @@ @implementation MWFeedItem -@synthesize identifier, title, link, date, updated, summary, content, enclosures; +@synthesize identifier, title, link, date, updated, summary, content, enclosures, customProperties; #pragma mark NSObject @@ -55,6 +55,7 @@ - (void)dealloc { [summary release]; [content release]; [enclosures release]; + [customProperities release]; [super dealloc]; } @@ -70,6 +71,7 @@ - (id)initWithCoder:(NSCoder *)decoder { summary = [[decoder decodeObjectForKey:@"summary"] retain]; content = [[decoder decodeObjectForKey:@"content"] retain]; enclosures = [[decoder decodeObjectForKey:@"enclosures"] retain]; + customProperities = [[decoder decodeObjectForKey:@"customProperties"] retain]; } return self; } @@ -83,6 +85,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { if (summary) [encoder encodeObject:summary forKey:@"summary"]; if (content) [encoder encodeObject:content forKey:@"content"]; if (enclosures) [encoder encodeObject:enclosures forKey:@"enclosures"]; + if (customProperities) [encoder encodeObject:customProperities forKey:@"customProperities"]; } @end diff --git a/Classes/MWFeedParser.h b/Classes/MWFeedParser.h index e174c35..0fdfc64 100644 --- a/Classes/MWFeedParser.h +++ b/Classes/MWFeedParser.h @@ -83,6 +83,11 @@ typedef enum { FeedTypeUnknown, FeedTypeRSS, FeedTypeRSS1, FeedTypeAtom } FeedTy NSXMLParser *feedParser; FeedType feedType; NSDateFormatter *dateFormatterRFC822, *dateFormatterRFC3339; + + // Rick Russell (@ossmac) - 12/28/2011 + // This is an array of custom keys as NSStrings that are to be parsed + // from each item. + NSArray *customKeys; // Parsing State NSURL *url; @@ -117,6 +122,9 @@ typedef enum { FeedTypeUnknown, FeedTypeRSS, FeedTypeRSS1, FeedTypeAtom } FeedTy // Set whether to download asynchronously or synchronously @property (nonatomic) ConnectionType connectionType; +// Set with a array of NSStrings as custom keys to parse from the feed +@property (nonatomic, copy) NSArray *customKeys; + // Whether parsing was stopped @property (nonatomic, readonly, getter=isStopped) BOOL stopped; diff --git a/Classes/MWFeedParser.m b/Classes/MWFeedParser.m index 16ca275..2bea6d9 100644 --- a/Classes/MWFeedParser.m +++ b/Classes/MWFeedParser.m @@ -50,8 +50,8 @@ @implementation MWFeedParser // Properties @synthesize url, delegate; -@synthesize urlConnection, asyncData, asyncTextEncodingName, connectionType; -@synthesize feedParseType, feedParser, currentPath, currentText, currentElementAttributes, item, info; +@synthesize urlConnection, asyncData, asyncTextEncodingName, connectionType, customKeys; +@synthesize feedParseType, feedParser, currentPath, currentText, currentElementAttributes, item, info, tmpDictionary; @synthesize pathOfElementWithXHTMLType; @synthesize stopped, failed, parsing; @@ -109,6 +109,7 @@ - (void)dealloc { [item release]; [info release]; [pathOfElementWithXHTMLType release]; + [customKeys release]; [super dealloc]; } @@ -535,6 +536,7 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName nam MWFeedItem *newItem = [[MWFeedItem alloc] init]; self.item = newItem; [newItem release]; + tmpDictionary = [[NSMutableDictionary alloc] init]; // Return [pool drain]; @@ -569,6 +571,7 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName nam - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { + MWXMLLog(@"NSXMLParser: didEndElement: %@", qName); // Pool @@ -621,7 +624,13 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName else if ([currentPath isEqualToString:@"/rss/channel/item/content:encoded"]) { if (processedText.length > 0) item.content = processedText; processed = YES; } else if ([currentPath isEqualToString:@"/rss/channel/item/pubDate"]) { if (processedText.length > 0) item.date = [NSDate dateFromInternetDateTimeString:processedText formatHint:DateFormatHintRFC822]; processed = YES; } else if ([currentPath isEqualToString:@"/rss/channel/item/enclosure"]) { [self createEnclosureFromAttributes:currentElementAttributes andAddToItem:item]; processed = YES; } - else if ([currentPath isEqualToString:@"/rss/channel/item/dc:date"]) { if (processedText.length > 0) item.date = [NSDate dateFromInternetDateTimeString:processedText formatHint:DateFormatHintRFC3339]; processed = YES; } + else if ([currentPath isEqualToString:@"/rss/channel/item/dc:date"]) { if (processedText.length > 0) item.date = [NSDate dateFromInternetDateTimeString:processedText formatHint:DateFormatHintRFC3339]; processed = YES; } + else if ([customKeys count]) { + [customKeys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) { + NSString *path = [NSString stringWithFormat:@"/rss/channel/item/%@", key]; + if ([currentPath isEqualToString: path]) { if (processedText.length > 0) [tmpDictionary setValue:processedText forKey:key]; } + }]; + } } // Info @@ -644,6 +653,12 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName else if ([currentPath isEqualToString:@"/rdf:RDF/item/content:encoded"]) { if (processedText.length > 0) item.content = processedText; processed = YES; } else if ([currentPath isEqualToString:@"/rdf:RDF/item/dc:date"]) { if (processedText.length > 0) item.date = [NSDate dateFromInternetDateTimeString:processedText formatHint:DateFormatHintRFC3339]; processed = YES; } else if ([currentPath isEqualToString:@"/rdf:RDF/item/enc:enclosure"]) { [self createEnclosureFromAttributes:currentElementAttributes andAddToItem:item]; processed = YES; } + else if ([customKeys count]) { + [customKeys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) { + NSString *path = [NSString stringWithFormat:@"/rdf:RDF/item/%@", key]; + if ([currentPath isEqualToString: path]) { if (processedText.length > 0) [tmpDictionary setValue:processedText forKey:key]; } + }]; + } } // Info @@ -666,6 +681,12 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName else if ([currentPath isEqualToString:@"/feed/entry/content"]) { if (processedText.length > 0) item.content = processedText; processed = YES; } else if ([currentPath isEqualToString:@"/feed/entry/published"]) { if (processedText.length > 0) item.date = [NSDate dateFromInternetDateTimeString:processedText formatHint:DateFormatHintRFC3339]; processed = YES; } else if ([currentPath isEqualToString:@"/feed/entry/updated"]) { if (processedText.length > 0) item.updated = [NSDate dateFromInternetDateTimeString:processedText formatHint:DateFormatHintRFC3339]; processed = YES; } + else if ([customKeys count]) { + [customKeys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) { + NSString *path = [NSString stringWithFormat:@"/feed/entry/%@", key]; + if ([currentPath isEqualToString: path]) { if (processedText.length > 0) [tmpDictionary setValue:processedText forKey:key]; } + }]; + } } // Info @@ -688,7 +709,12 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName if (!processed) { if (((feedType == FeedTypeRSS || feedType == FeedTypeRSS1) && [qName isEqualToString:@"item"]) || (feedType == FeedTypeAtom && [qName isEqualToString:@"entry"])) { - + if([tmpDictionary count]) { + item.customProperties = tmpDictionary; + MWXMLLog(@"NSXMLParser: customProperity: %@ - %@", ); + } + [tmpDictionary release]; + // Dispatch item to delegate [self dispatchFeedItemToDelegate]; diff --git a/Classes/MWFeedParser_Private.h b/Classes/MWFeedParser_Private.h index c2fbdce..b8f7c72 100644 --- a/Classes/MWFeedParser_Private.h +++ b/Classes/MWFeedParser_Private.h @@ -45,6 +45,7 @@ @property (nonatomic, retain) MWFeedItem *item; @property (nonatomic, retain) MWFeedInfo *info; @property (nonatomic, copy) NSString *pathOfElementWithXHTMLType; +@property (nonatomic, retain) NSMutableDictionary *tmpDictionary; #pragma mark Private Methods diff --git a/README.markdown b/README.markdown index 6e4a426..41f32ca 100644 --- a/README.markdown +++ b/README.markdown @@ -16,6 +16,7 @@ MWFeedParser is an Objective-C framework for downloading and parsing RSS (1.* an - Content (detailed item content, if available) - Enclosures (i.e. podcasts, mp3, pdf, etc) - Identifier (an item's guid/id) +- customProperties (Dictionary containing any custom elements if the keys are requested in the customKeys configuration property. The dictionary will use the element name as the key and the values will be stored as strings in the dictionary) If you use MWFeedParser on your iPhone/iPad app then please do let me know, I'd love to check it out :) @@ -25,7 +26,7 @@ If you use MWFeedParser on your iPhone/iPad app then please do let me know, I'd limited to) that of events, news, experiences and activities, for the purpose of any concept relating to diary/journal keeping. -The full licence can be found at the end of this document. +The full license can be found at the end of this document. ## Demo / Example App @@ -56,6 +57,11 @@ Set whether the parser should connect and download the feed data synchronously o // Connection type feedParser.connectionType = ConnectionTypeSynchronously; +An array of the elements of to search for in the items in addition to the standard fields: + + // Custom Keys + feedParser.customKeys = [NSArray arrayWithObjects: @"itunes:duration", @"itunes:author",nil]; + Initiate parsing: // Begin parsing @@ -111,7 +117,7 @@ Here is a list of the available properties for feed info and item objects: - `item.content` (`NSString`) - `item.enclosures` (`NSArray` of `NSDictionary` with keys `url`, `type` and `length`) - `item.identifier` (`NSString`) - +- `item.customProperties` (`NSDictionary`) ## Using the data @@ -212,4 +218,4 @@ Contact =============== Website: -Twitter: \ No newline at end of file +Twitter: