-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRSSChannel.m
172 lines (138 loc) · 5.6 KB
/
RSSChannel.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//
// RSSChannel.m
// Nerdfeed
//
// Created by THOMAS PENG on 6/18/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "RSSChannel.h"
#import "RSSItem.h"
@implementation RSSChannel
@synthesize items, title, infoString, parentParserDelegate;
- (id)init
{
self = [super init];
if (self) {
// Create the container for the RSSItems this channel has; we'll
// create the RSSItem class shortly.
items = [[NSMutableArray alloc] init];
}
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(@"\t%@ found a %@ element", self, elementName);
if ([elementName isEqual:@"title"]) {
currentString = [[NSMutableString alloc] init];
[self setTitle:currentString];
} else if ([elementName isEqual:@"description"]) {
currentString = [[NSMutableString alloc] init];
[self setInfoString:currentString];
} else if ([elementName isEqual:@"item"] || [elementName isEqual:@"entry"]) {
// When we find an item, create an instance of RSSItem
RSSItem *entry = [[RSSItem alloc] init];
// Set up its parent as ourselves so we can regain control of the parser
[entry setParentParserDelegate:self];
// Turn the parser to the RSSItem
[parser setDelegate:entry];
// Add the item to our array and release our hold on it
[items addObject:entry];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currentString appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// If we were in an element that we were collecting the string for,
// this appropriately releases our hold on it and the permanent ivar keeps
// ownership of it. If we weren't parsing such an element, currentString is
// nil already.
currentString = nil;
// If the element that ended was the channel, give up control to
// who gave us control in the first place
if ([elementName isEqual:@"channel"]) {
[parser setDelegate:parentParserDelegate];
[self trimItemTitles];
}
}
- (void)trimItemTitles
{
// Create a regular expression with the pattern: Author
NSRegularExpression *reg = [[NSRegularExpression alloc] initWithPattern:@".* :: (.*) :: .*" options:0 error:nil];
// Loop through every title of the items in channel
for (RSSItem *i in items) {
NSString *itemTitle = [i title];
// Find matches in the title string. The range
// argument specifies how much of the title to search;
// in this case, all of it.
NSArray *matches = [reg matchesInString:itemTitle options:0 range:NSMakeRange(0, [itemTitle length])];
// If there was a match...
if ([matches count] > 0) {
// Print the location of the match in the string and the string
NSTextCheckingResult *result = [matches objectAtIndex:0];
NSRange r = [result range];
NSLog(@"Match at {%d, %d} for %@!", r.location, r.length, itemTitle);
// One capture group, so two ranges, let's verify
if ([result numberOfRanges] == 2) {
// Pull out the 2nd range, which will be the capture grou
NSRange r = [result rangeAtIndex:1];
// Set the title of the item to the string within the capture group
[i setTitle:[itemTitle substringWithRange:r]];
}
}
}
}
- (void)readFromJSONDictionary:(NSDictionary *)d
{
// The top-level object contains a "feed" object, which is the channel.
NSDictionary *feed = [d objectForKey:@"feed"];
// The feed has a title property, make this the title of our channel.
[self setTitle:[feed objectForKey:@"title"]];
// The feed also has an array of entries, for each one, make a new RSSItem.
NSArray *entries = [feed objectForKey:@"entry"];
for (NSDictionary *entry in entries) {
RSSItem *i = [[RSSItem alloc] init];
// Pass the entry dictionary to the item so it can grab its ivars
[i readFromJSONDictionary:entry];
[items addObject:i];
}
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:items forKey:@"items"];
[aCoder encodeObject:title forKey:@"title"];
[aCoder encodeObject:infoString forKey:@"infoString"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
items = [aDecoder decodeObjectForKey:@"items"];
[self setInfoString:[aDecoder decodeObjectForKey:@"infoString"]];
[self setTitle:[aDecoder decodeObjectForKey:@"title"]];
}
return self;
}
- (void)addItemsFromChannel:(RSSChannel *)otherChannel
{
for (RSSItem *i in [otherChannel items]) {
// If self's items does not contain this item, add it
if (![[self items] containsObject:i])
[[self items] addObject:i];
}
// Sort the array of items by publication date
[[self items] sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [[obj2 publicationDate] compare:[obj1 publicationDate]];
}];
}
- (id)copyWithZone:(NSZone *)zone
{
RSSChannel *c = [[[self class] alloc] init];
[c setTitle:[self title]];
[c setInfoString:[self infoString]];
c->items = [items mutableCopy];
return c;
}
@end