I am trying to parse an RSS XML feed. I have figured out how to parse what's in the tags for the individual stories, but I cannot figure out how to get the name of the entire feed (for example "CNN's News Feed"). I think it's in and I've tried a ton of things but I can't figure it out. Below is part of my parsing code that I think what seemed like the most sense, but didn't work. Can anyone help?
Thanks!!
GL
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"] || [elementName isEqualToString:#"channel"]) {
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"channel"]) {
// save values to an item, then store that item into the array...
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[feedsArray addObject:[item copy]];
}
if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[stories addObject:[item copy]];
NSLog(#"adding story: %#", currentTitle);
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
} else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
}
}
The feed name is always included in the name of title by " - " at the end. Now if you want to get the feed name you can do it like.
NSDictionary *feedDict = [feedArray objectAtIndex:indexPath.row];
UILabel *lbl = (UILabel *)[cell.contentView viewWithTag:1];
NSArray *tempArr = [[NSArray alloc] initWithArray:[[feedDict valueForKey:#"title"] componentsSeparatedByString:#" - "]];
[lbl setText:[tempArr objectAtIndex:0]];
So you will see the name of feed in the lable.
Hope this helps.
Thanks,
Madhup
The feeds title lays outside items and channels so you should also trigger for a title in didStartElement. You also might need to make some logic to differentiate between titles within items and channels and the global title.
Let's have a try to fix it...(also noticed some possible memory leaks)
Not tested
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
if (currentElement)
[currentElement release];
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"] ||
[elementName isEqualToString:#"channel"]) {
if (item)
[item release];
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
} else if (!item && [elementName isEqualToString:#"title"]) {
[currentElement release];
currentElement = [#"<GlobalTitle>" copy];
}
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"channel"]) {
// save values to an item, then store that item into the array...
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[feedsArray addObject:item]; // item will be retained by array
[item release];
[currentTitle release]; // these are also retained by the dictionary
[currentLink release];
[currentSummary release];
[currentDate release];
item = nil;
currentTitle = nil;
currentLink = nil;
currentSummary = nil;
currentDate = nil;
}
if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[stories addObject:item]; // item will be retained by array
[item release];
[currentTitle release]; // these are also retained by the dictionary
[currentLink release];
[currentSummary release];
[currentDate release];
item = nil;
currentTitle = nil;
currentLink = nil;
currentSummary = nil;
currentDate = nil;
NSLog(#"adding story: %#", currentTitle);
}
}
- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string {
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
} else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
} else if ([currentElement isEqualToString:#"<GlobalTitle>"]) {
self.feedTitle = string; // The feeds title is saved here
}
}
I've released an open source RSS/Atom Parser for iPhone and it makes reading and parsing web feeds extremely easy.
You can set it to read just the feed info (title, summary, etc) if you want. Checkout the documentation and play around with the demo app. Hope this helps!
Related
I would like to pass the nsdictionary I am creating into an nsmutablearray but I'm not sure when or how to do it in the nsxmlparser delegates.
this is what I have done so far
#pragma mark - Parsing lifecycle
- (void)startTheParsingProcess:(NSData *)parserData
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:parserData]; //parserData passed to NSXMLParser delegate which starts the parsing process
[parser setDelegate:self];
[parser parse]; // starts the event-driven parsing operation.
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"item"]) {
valueDictionary = [[NSMutableDictionary alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
NSMutableString *dicString = [[NSMutableString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
currentElement = dicString;
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"title"]) {
titleString = currentElement;
[self.valueDictionary setObject:titleString forKey:#"title"];
NSLog(#"%#", [valueDictionary objectForKey:#"title"]);
NSLog(#" ");
currentElement = nil;
}
if ([elementName isEqualToString:#"description"])
{
descriptionString = currentElement;
[self.valueDictionary setObject:descriptionString forKey:#"description"];
NSLog(#"%#", [valueDictionary objectForKey:#"description"]);
NSLog(#" ");
currentElement = nil;
}
In -parser:didEndElement:namespaceURI:qualifiedName:, listen for the end of the item element, then add valueDictionary to a mutable array instance on your class.
if ([elementName isEqualToString:#"item"])
{
[self.mutableArrayOfDictionaries addObject:self.valueDictionary];
}
if ([elementName isEqualToString:#"title"]) {
titleString = currentElement;
[self.valueDictionary setObject:titleString forKey:#"title"];
NSLog(#"%#", [valueDictionary objectForKey:#"title"]);
NSLog(#" ");
currentElement = nil;
}
if ([elementName isEqualToString:#"description"])
{
descriptionString = currentElement;
[self.valueDictionary setObject:descriptionString forKey:#"description"];
NSLog(#"%#", [valueDictionary objectForKey:#"description"]);
NSLog(#" ");
currentElement = nil;
}
I have developed one application to fetch RSS feed. I am getting this error code 5 for some URLs where as som others are working fine.
I know this error means the xml is invalid. But for my app, I have not written any xml files by my own.
Please tell me the probable reasons for this and let me know the solution
import "RootViewController.h"
#implementation RootViewController
(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if ([stories count] == 0) {
path = #"http://172.19.58.108:8080/jwplayer/JSP/Videolist.jsp";
[self parseXMLFileAtURL:path];
}
}
-(void)parseXMLFileAtURL:(NSString *)URL{
stories = [[NSMutableArray alloc]init];
NSURL *xmlURL = [NSURL URLWithString:URL];
rssParser = [[NSXMLParser alloc]initWithContentsOfURL:xmlURL];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
-(void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(#"Found file and started parsing");
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSString *errorString = [NSString stringWithFormat:#"Unable to download story feed from website (Error Code %i)", [parseError code]];
NSLog(#"Error parsing xml: %#", errorString);
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc]init];
currentTitle = [[NSMutableString alloc]init];
currentDate = [[NSMutableString alloc]init];
currentSummary = [[NSMutableString alloc]init];
currentLink = [[NSMutableString alloc]init];
}
}
-(void)parser: (NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentDate forKey:#"date"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentLink forKey:#"link"];
[stories addObject:[item copy]];
NSLog(#"adding story: %#", currentTitle);
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
}
else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
}
else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
}
else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
}
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
NSLog(#"all done");
NSLog(#"stories array has %d items", [stories count]);
[newsTable reloadData];
}
Please check your library class for Rss feed parsing. Use standard library class, change the the code accordingly.
I am trying to extract the title from this xml:
<entry>
...
<title type="html">Some title</title>
<published>2011-02-07T00:04:16Z</published>
<updated>2011-02-07T00:04:16Z</updated>
...
</entry>
in the NSXMLParsing's didStartElement code:
if ([elementName isEqualToString:#"entry"])
{
item = [[NSMutableDictionary alloc] init];
}
if([elementName isEqualToString:#"title"])
{
currentElement = [elementName copy];
currentTitle = [[NSMutableString alloc] init];
}
in foundCharacters:
if ([currentElement isEqualToString:#"title"])
{
[currentTitle appendString:string];
}
in didEndElement:
if ([elementName isEqualToString:#"entry"])
{
[item setObject:currentTitle forKey:#"title"];
[currentElement release];
currentElement = nil;
[item release];
item = nil;
}
The problem is that for some reason when it gets to the didEndElement the currentTitle has got the three node's content, so its:
Some
title2011-02-07T00:04:16Z2011-02-07T00:04:16Z
I don't get why its picking up the published and updated node and appending them to the title string.
You set currentElement to #"title" in didStartElement: but you never unset it. The first element in this particular XML file is title, so you set currentElement and for every foundCharacters: thereafter you append them. Change didStartElement: to:
currentElement = [elementName copy];
if ([elementName isEqualToString:#"entry"])
{
item = [[NSMutableDictionary alloc] init];
}
if([elementName isEqualToString:#"title"])
{
currentTitle = [[NSMutableString alloc] init];
}
You have to add to didEndElement:
if ([elementName isEqualToString:#"title"])
{
[currentElement release];
currentElement = nil;
}
define
NSMutableString *strFoundCharacters; in class method set property and synthesize it.
then in
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *) string {
NSString *strAppend = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([strAppend length] > 0) {
[self.strFoundCharacters appendString:string];
}
}
make nil to strfoundcharacter in
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"title"] ) {
self.currentTitle = self.strFoundCharacters;
}
[self.strFoundCharacters setString:#""];
}
i think it will work
I am new to iphone development .I am trying to sort a NSMutable array with reference to the date which is saved as object for the key "pubDate".After parsing the url i am saving the date as date format in an array"myPubDate".
(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
} else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
NSDateFormatter *df =[[NSDateFormatter alloc] init];
[df setFormatterBehavior:NSDateFormatterBehavior10_4];
[df setDateFormat:#"EEE, dd MMM yyyy"];
myPubDate = [df dateFromString:currentDate];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"description"];
[item setObject:myPubDateforKey:#"pubDate"]
[item setObject:currentImage forKey:#"imagePath"];
NSLog(#"Befor if condition");
[stories addObject:[item copy]];
}
recent = [stories copy];}
For sorting
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"pubDate" ascending:NO];
[recent sortUsingDescriptor:[NSArray arrayWithObjects:descriptor, nil]];
recent1 = [recent sortedArrayUsingDescriptors:descriptor];
[descriptor release];
I am geeting an error in the console as
[NSCFArray sortUsingDescriptor:]: unrecognized selector sent to instance 0x4ed10c0
Where do i go wrong? please help me out.Thanks.
Your problem appears to be a typo: sortUsingDescriptor: is not the same as sortUsingDescriptors:
I'm parsing an RSS feed with NSXMLParser and it's working fine for the title and other strings but one of the elements is an image thats like
<!CDATA <a href="http:image..etc>
How do I add that as my cell image in my table view? Would I define that as an image type?
This is what i'm using to do my parsing:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
//NSLog(#"found this element: %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
// clear out our story item caches...
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [ [NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"item"]) {
// save values to an item, then store that item into the array...
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"description"];
[item setObject:currentDate forKey:#"date"];
[stories addObject:[item copy]];
NSLog(#"adding story: %#", currentTitle);
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
} else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
}
}
You can use
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
}
The point of CDATA is that anything within it is not treated as part of the XML document.
So if you have tags in CDATA the parser will ignore them.
I'm guessing this CDATA is in the description element. So you'll need to extract the tags from the "description" element, either manually or via another instance of a parser.