Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions Classes/MWFeedInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,19 @@

@interface MWFeedInfo : NSObject <NSCoding> {

NSString *title; // Feed title
NSString *link; // Feed link
NSString *summary; // Feed summary / description
NSURL *url; // Feed url

NSString *title; // Feed title
NSString *link; // Feed link
NSString *summary; // Feed summary / description
NSURL *url; // Feed url

// Custom attributes:
// - NSDictionary with the keys related to custom attributes defined on parser
NSDictionary *customAttributes;
}

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *link;
@property (nonatomic, copy) NSString *summary;
@property (nonatomic, copy) NSURL *url;

@property (nonatomic, copy) NSDictionary *customAttributes;
@end
4 changes: 3 additions & 1 deletion Classes/MWFeedInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

@implementation MWFeedInfo

@synthesize title, link, summary, url;
@synthesize title, link, summary, url, customAttributes;

#pragma mark NSObject

Expand All @@ -54,6 +54,7 @@ - (id)initWithCoder:(NSCoder *)decoder {
link = [decoder decodeObjectForKey:@"link"];
summary = [decoder decodeObjectForKey:@"summary"];
url = [decoder decodeObjectForKey:@"url"];
customAttributes = [decoder decodeObjectForKey:@"customAttributes"];
}
return self;
}
Expand All @@ -63,6 +64,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder {
if (link) [encoder encodeObject:link forKey:@"link"];
if (summary) [encoder encodeObject:summary forKey:@"summary"];
if (url) [encoder encodeObject:url forKey:@"url"];
if (customAttributes) [encoder encodeObject:customAttributes forKey:@"customAttributes"];
}

@end
5 changes: 5 additions & 0 deletions Classes/MWFeedItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
// type: what its type is, a standard MIME type (NSString)
NSArray *enclosures;


// Custom attributes:
// - NSDictionary with the keys related to custom attributes defined on parser
NSDictionary *customAttributes;
}

@property (nonatomic, copy) NSString *identifier;
Expand All @@ -58,5 +62,6 @@
@property (nonatomic, copy) NSString *content;
@property (nonatomic, copy) NSString *author;
@property (nonatomic, copy) NSArray *enclosures;
@property (nonatomic, copy) NSDictionary *customAttributes;

@end
6 changes: 5 additions & 1 deletion Classes/MWFeedItem.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

@implementation MWFeedItem

@synthesize identifier, title, link, date, updated, summary, content, author, enclosures;
@synthesize identifier, title, link, date, updated, summary, content, author, enclosures, customAttributes;

#pragma mark NSObject

Expand All @@ -60,6 +60,8 @@ - (id)initWithCoder:(NSCoder *)decoder {
content = [decoder decodeObjectForKey:@"content"];
author = [decoder decodeObjectForKey:@"author"];
enclosures = [decoder decodeObjectForKey:@"enclosures"];
customAttributes = [decoder decodeObjectForKey:@"customAttributes"];

}
return self;
}
Expand All @@ -74,6 +76,8 @@ - (void)encodeWithCoder:(NSCoder *)encoder {
if (content) [encoder encodeObject:content forKey:@"content"];
if (author) [encoder encodeObject:author forKey:@"author"];
if (enclosures) [encoder encodeObject:enclosures forKey:@"enclosures"];
if (customAttributes) [encoder encodeObject:customAttributes forKey:@"customAttributes"];

}

@end
10 changes: 9 additions & 1 deletion Classes/MWFeedParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ typedef enum { FeedTypeUnknown, FeedTypeRSS, FeedTypeRSS1, FeedTypeAtom } FeedTy
NSXMLParser *feedParser;
FeedType feedType;
NSDateFormatter *dateFormatterRFC822, *dateFormatterRFC3339;

NSArray *customFeedChannelKeys;
NSArray *customFeedItemKeys;

// Parsing State
NSURL *url;
BOOL aborted; // Whether parse stopped due to abort
Expand Down Expand Up @@ -117,6 +119,12 @@ typedef enum { FeedTypeUnknown, FeedTypeRSS, FeedTypeRSS1, FeedTypeAtom } FeedTy
// Set whether to download asynchronously or synchronously
@property (nonatomic) ConnectionType connectionType;

// Custom attributes to find in the feed channel
@property (nonatomic) NSArray *customFeedChannelKeys;

// Custom attributes to find in the feed item
@property (nonatomic) NSArray *customFeedItemKeys;

// Whether parsing was stopped
@property (nonatomic, readonly, getter=isStopped) BOOL stopped;

Expand Down
49 changes: 48 additions & 1 deletion Classes/MWFeedParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ @implementation MWFeedParser
@synthesize feedParseType, feedParser, currentPath, currentText, currentElementAttributes, item, info;
@synthesize pathOfElementWithXHTMLType;
@synthesize stopped, failed, parsing;
@synthesize customFeedChannelKeys, customFeedItemKeys;

#pragma mark -
#pragma mark NSObject
Expand Down Expand Up @@ -196,6 +197,7 @@ - (void)startParsingData:(NSData *)data textEncodingName:(NSString *)textEncodin
MWFeedInfo *i = [[MWFeedInfo alloc] init];
i.url = self.url;
self.info = i;
self.currentCustomPropertiesOfChannel = [NSMutableDictionary dictionary];

// Check whether it's UTF-8
if (![[textEncodingName lowercaseString] isEqualToString:@"utf-8"]) {
Expand Down Expand Up @@ -515,7 +517,7 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName nam
// New item
MWFeedItem *newItem = [[MWFeedItem alloc] init];
self.item = newItem;

self.currentCustomPropertiesOfItem = [NSMutableDictionary dictionary];
// Return
return;

Expand Down Expand Up @@ -583,6 +585,34 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
// Remove newlines and whitespace from currentText
NSString *processedText = [currentText stringByRemovingNewLinesAndWhitespace];

__weak typeof(self)selfB = self;

void (^findCustomChannelKeysWithBasePath)(NSString *) = ^ (NSString *path){
[selfB.customFeedChannelKeys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) {
NSString *searchPath = [NSString stringWithFormat:path, key];
if ([currentPath isEqualToString:searchPath]) {
if (processedText.length > 0) {
selfB.currentCustomPropertiesOfChannel[key] = processedText;
} else if (currentElementAttributes.count) {
selfB.currentCustomPropertiesOfChannel[key] = currentElementAttributes;
}
}
}];
};

void (^findCustomItemKeysWithBasePath)(NSString *) = ^ (NSString *path){
[selfB.customFeedItemKeys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) {
NSString *searchPath = [NSString stringWithFormat:path, key];
if ([currentPath isEqualToString:searchPath]) {
if (processedText.length > 0) {
selfB.currentCustomPropertiesOfItem[key] = processedText;
} else if (currentElementAttributes.count) {
selfB.currentCustomPropertiesOfItem[key] = currentElementAttributes;
}
}
}];
};

// Process
switch (feedType) {
case FeedTypeRSS: {
Expand All @@ -603,13 +633,15 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
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 (self.customFeedItemKeys.count) { findCustomItemKeysWithBasePath(@"/rss/channel/item/%@"); }
}

// Info
if (!processed && feedParseType != ParseTypeItemsOnly) {
if ([currentPath isEqualToString:@"/rss/channel/title"]) { if (processedText.length > 0) info.title = processedText; processed = YES; }
else if ([currentPath isEqualToString:@"/rss/channel/description"]) { if (processedText.length > 0) info.summary = processedText; processed = YES; }
else if ([currentPath isEqualToString:@"/rss/channel/link"]) { if (processedText.length > 0) info.link = processedText; processed = YES; }
else if (self.customFeedChannelKeys.count) { findCustomChannelKeysWithBasePath(@"/rss/channel/%@"); }
}

break;
Expand All @@ -630,13 +662,15 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
else if ([currentPath isEqualToString:@"/rdf:RDF/item/dc:creator"]) { if (processedText.length > 0) item.author = 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 (self.customFeedItemKeys.count) { findCustomItemKeysWithBasePath(@"/rdf:RDF/item/%@"); }
}

// Info
if (!processed && feedParseType != ParseTypeItemsOnly) {
if ([currentPath isEqualToString:@"/rdf:RDF/channel/title"]) { if (processedText.length > 0) info.title = processedText; processed = YES; }
else if ([currentPath isEqualToString:@"/rdf:RDF/channel/description"]) { if (processedText.length > 0) info.summary = processedText; processed = YES; }
else if ([currentPath isEqualToString:@"/rdf:RDF/channel/link"]) { if (processedText.length > 0) info.link = processedText; processed = YES; }
else if (self.customFeedChannelKeys.count) { findCustomChannelKeysWithBasePath(@"/rdf:RDF/channel/%@"); }
}

break;
Expand All @@ -658,13 +692,15 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
else if ([currentPath isEqualToString:@"/feed/entry/dc:creator"]) { if (processedText.length > 0) item.author = 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 (self.customFeedItemKeys.count) { findCustomItemKeysWithBasePath(@"/feed/entry/%@"); }
}

// Info
if (!processed && feedParseType != ParseTypeItemsOnly) {
if ([currentPath isEqualToString:@"/feed/title"]) { if (processedText.length > 0) info.title = processedText; processed = YES; }
else if ([currentPath isEqualToString:@"/feed/description"]) { if (processedText.length > 0) info.summary = processedText; processed = YES; }
else if ([currentPath isEqualToString:@"/feed/link"]) { [self processAtomLink:currentElementAttributes andAddToMWObject:info]; processed = YES;}
else if (self.customFeedChannelKeys.count) { findCustomChannelKeysWithBasePath(@"/feed/%@"); }
}

break;
Expand All @@ -681,6 +717,10 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
if (((feedType == FeedTypeRSS || feedType == FeedTypeRSS1) && [qName isEqualToString:@"item"]) ||
(feedType == FeedTypeAtom && [qName isEqualToString:@"entry"])) {

if(self.currentCustomPropertiesOfItem.count) {
item.customAttributes = self.currentCustomPropertiesOfItem;
}

// Dispatch item to delegate
[self dispatchFeedItemToDelegate];

Expand All @@ -693,6 +733,11 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
(feedType == FeedTypeRSS1 && [qName isEqualToString:@"rdf:RDF"]) ||
(feedType == FeedTypeAtom && [qName isEqualToString:@"feed"])) {


if(self.currentCustomPropertiesOfChannel.count) {
info.customAttributes = self.currentCustomPropertiesOfChannel;
}

// Document ending so if we havent sent off feed info yet, do so
if (info && feedParseType != ParseTypeItemsOnly) [self dispatchFeedInfoToDelegate];

Expand Down Expand Up @@ -804,6 +849,7 @@ - (void)dispatchFeedInfoToDelegate {

// Finish
self.info = nil;
self.currentCustomPropertiesOfChannel = nil;

}
}
Expand All @@ -824,6 +870,7 @@ - (void)dispatchFeedItemToDelegate {

// Finish
self.item = nil;
self.currentCustomPropertiesOfItem = nil;

}
}
Expand Down
3 changes: 3 additions & 0 deletions Classes/MWFeedParser_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
@property (nonatomic, strong) MWFeedInfo *info;
@property (nonatomic, copy) NSString *pathOfElementWithXHTMLType;

@property (nonatomic, strong) NSMutableDictionary *currentCustomPropertiesOfChannel;
@property (nonatomic, strong) NSMutableDictionary *currentCustomPropertiesOfItem;

#pragma mark Private Methods

// Parsing Methods
Expand Down
1 change: 1 addition & 0 deletions MWFeedParser.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Pod::Spec.new do |s|
s.source = {
:git => 'https://github.com/mwaterfall/MWFeedParser.git',
:tag => '1.0.1'
:tag => '1.0.1b'
}
s.platform = :ios, '5.1.1'
s.requires_arc = true
Expand Down
8 changes: 3 additions & 5 deletions MWFeedParser.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@
4CC89602119F0CDE00ED61B6 /* MWFeedParser */ = {
isa = PBXGroup;
children = (
4CC89603119F0CED00ED61B6 /* MWFeedParser.h */,
4CAA79C911A406890009078E /* MWFeedParser_Private.h */,
4CC89603119F0CED00ED61B6 /* MWFeedParser.h */,
4CC89604119F0CED00ED61B6 /* MWFeedParser.m */,
4CC89605119F0CED00ED61B6 /* MWFeedInfo.h */,
4CC89606119F0CED00ED61B6 /* MWFeedInfo.m */,
Expand Down Expand Up @@ -320,8 +320,7 @@
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
CLANG_ENABLE_OBJC_ARC = NO;
CODE_SIGN_IDENTITY = "";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
Expand All @@ -336,8 +335,7 @@
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
CLANG_ENABLE_OBJC_ARC = NO;
CODE_SIGN_IDENTITY = "";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
Expand Down