From f7663ef75d2ab74e9bde2baebf207325a72c932b Mon Sep 17 00:00:00 2001 From: macoss Date: Wed, 28 Dec 2011 23:18:41 -0500 Subject: [PATCH 1/3] Added the code to support parsing of other keys from feeds I have added a NSArray that is used to pass in a list of NSStrings that is to contain the xml element names of the custom elements that you would like MWFeedParser to look for and parse if it is found. If the elements are found they will be added to the customProperities NSDictionary that I have added to the MWFeedItem class. --- Classes/MWFeedItem.h | 15 ++++++++++++++- Classes/MWFeedItem.m | 5 ++++- Classes/MWFeedParser.h | 8 ++++++++ Classes/MWFeedParser.m | 34 ++++++++++++++++++++++++++++++---- Classes/MWFeedParser_Private.h | 1 + 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Classes/MWFeedItem.h b/Classes/MWFeedItem.h index 936ce60..8f8792c 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 *customProperities; @end + diff --git a/Classes/MWFeedItem.m b/Classes/MWFeedItem.m index 127a0e7..14cb65f 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, customProperities; #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:@"customProperities"] 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..a36a42c 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:@"/rss/channel/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:@"/rss/channel/item/%@", 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.customProperities = 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 From 2e29f75587d09c9944892fc802ef37f9670802bb Mon Sep 17 00:00:00 2001 From: macoss Date: Thu, 29 Dec 2011 14:44:05 -0500 Subject: [PATCH 2/3] Added documentation for parsing custom elements and fixed a spelling error Added documentation to the README and fixed a spelling error in the dictionary name. --- Classes/MWFeedItem.h | 2 +- Classes/MWFeedItem.m | 4 ++-- Classes/MWFeedParser.m | 2 +- README.markdown | 12 +++++++++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Classes/MWFeedItem.h b/Classes/MWFeedItem.h index 8f8792c..fffdf6f 100644 --- a/Classes/MWFeedItem.h +++ b/Classes/MWFeedItem.h @@ -67,7 +67,7 @@ @property (nonatomic, copy) NSString *summary; @property (nonatomic, copy) NSString *content; @property (nonatomic, copy) NSArray *enclosures; -@property (nonatomic, copy) NSDictionary *customProperities; +@property (nonatomic, copy) NSDictionary *customProperties; @end diff --git a/Classes/MWFeedItem.m b/Classes/MWFeedItem.m index 14cb65f..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, customProperities; +@synthesize identifier, title, link, date, updated, summary, content, enclosures, customProperties; #pragma mark NSObject @@ -71,7 +71,7 @@ - (id)initWithCoder:(NSCoder *)decoder { summary = [[decoder decodeObjectForKey:@"summary"] retain]; content = [[decoder decodeObjectForKey:@"content"] retain]; enclosures = [[decoder decodeObjectForKey:@"enclosures"] retain]; - customProperities = [[decoder decodeObjectForKey:@"customProperities"] retain]; + customProperities = [[decoder decodeObjectForKey:@"customProperties"] retain]; } return self; } diff --git a/Classes/MWFeedParser.m b/Classes/MWFeedParser.m index a36a42c..e44bfd5 100644 --- a/Classes/MWFeedParser.m +++ b/Classes/MWFeedParser.m @@ -710,7 +710,7 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName if (((feedType == FeedTypeRSS || feedType == FeedTypeRSS1) && [qName isEqualToString:@"item"]) || (feedType == FeedTypeAtom && [qName isEqualToString:@"entry"])) { if([tmpDictionary count]) { - item.customProperities = tmpDictionary; + item.customProperties = tmpDictionary; MWXMLLog(@"NSXMLParser: customProperity: %@ - %@", ); } [tmpDictionary release]; 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: From 8d018dd44217b8c67224ba8c6430bcf064a00002 Mon Sep 17 00:00:00 2001 From: macoss Date: Thu, 29 Dec 2011 14:59:24 -0500 Subject: [PATCH 3/3] Updated the string paths to be correct for the different types of feeds to be parsed --- Classes/MWFeedParser.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/MWFeedParser.m b/Classes/MWFeedParser.m index e44bfd5..2bea6d9 100644 --- a/Classes/MWFeedParser.m +++ b/Classes/MWFeedParser.m @@ -655,7 +655,7 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 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:@"/rss/channel/item/%@", key]; + NSString *path = [NSString stringWithFormat:@"/rdf:RDF/item/%@", key]; if ([currentPath isEqualToString: path]) { if (processedText.length > 0) [tmpDictionary setValue:processedText forKey:key]; } }]; } @@ -683,7 +683,7 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 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:@"/rss/channel/item/%@", key]; + NSString *path = [NSString stringWithFormat:@"/feed/entry/%@", key]; if ([currentPath isEqualToString: path]) { if (processedText.length > 0) [tmpDictionary setValue:processedText forKey:key]; } }]; }