I'm doing a test where I'm building a news feed iOS app, using rss feeds like this one: http://www.20minutos.es/iphoneapp/feeds/home/
I'm almost done, but I can't find the link to the thumbnail. I'm doing the parsing like this and I can find some enclosure, enclosure2x, thumbnail, thumbnail2x, but they're all empty strings:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
title = [[NSMutableString alloc] init];
link = [[NSMutableString alloc] init];
image = [[NSMutableString alloc] init];
image2x = [[NSMutableString alloc] init];
comments = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[item setObject:image forKey:#"image"];
[item setObject:image2x forKey:#"image2x"];
[item setObject:comments forKey:#"comments"];
[feeds addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([element isEqualToString:#"title"]) {
[title appendString:string];
} else if ([element isEqualToString:#"link"]) {
[link appendString:string];
} else if ([element isEqualToString:#"veinteminutos:numComments"]) {
[comments appendString:[string stringByReplacingOccurrencesOfString:#" " withString:#""]];
}
//NSLog(#"string: %# \nelement: %# \n\n\n", string, element);
}
It's my first time parsing rss feeds, so I don't really know what to look for in there.
Thanks
You should parse out the media:thumbnail and media:thumbnail2x nodes in the parser:didStartElement:namespaceURI:qualifiedName:attributes: delegate method and extract the thumbnail URLs from the attributeDict dictionary:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
title = [[NSMutableString alloc] init];
link = [[NSMutableString alloc] init];
image = [[NSMutableString alloc] init];
image2x = [[NSMutableString alloc] init];
comments = [[NSMutableString alloc] init];
} else if ([element isEqualToString:#"media:thumbnail"]) {
image = [attributeDict objectForKey:#"url"];
} else if ([element isEqualToString:#"media:thumbnail2x"]) {
image2x = [attributeDict objectForKey:#"url"];
}
}
You can do the same for the enclosures, should you need them.
Related
I have written the below code to parse RSS feeds. but i keep getting EXC_BAD_ACCESS in foundCharacter method when it tries to compare element with #"title".Any idea where am i going wrong?
NSMutableDictionary * item;
NSMutableString * title;
NSMutableString * link;
NSString *element;
NSMutableArray *feeds;
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc]init];
title = [[NSMutableString alloc]init];
link = [[NSMutableString alloc] init];
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[feeds addObject:[item copy]];
NSLog(#"feeds :: %#",feeds);
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([element isEqualToString:#"title"]) {
[title appendString:string];`enter code here`
}else if ([element isEqualToString:#"link"]){
[link appendString:string];
}
}
I think the mistake is in this line:
element = elementName;
You have to init the variable element. So write this one:
element = [[NSString alloc] initWithString:elementName];
Then it should work.
Iv'e set my h as the delegate and I'm calling the "setDelegate:self" method on my xml parser.
here is my code.
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
elementName = element;
if ([elementName isEqualToString:#"offer"]) {
offersDictionary = [[NSMutableDictionary alloc] init];
offerTitle = [[NSMutableString alloc] init];
offerDay = [[NSMutableString alloc] init];
offerDet = [[NSMutableString alloc] init];
NSLog(#"PARSER didStartElement method!");
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([element isEqualToString:#"offerTitle"]) {
[offerTitle appendString:string];
}
if ([element isEqualToString:#"day"]) {
[offerDay appendString:string];
}
if ([element isEqualToString:#"offerDetail"]) {
[offerDet appendString:string];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"offer"]) {
[offersDictionary setObject:offerTitle forKey:#"offerTitle"]; NSLog(#"offerTitle:%#",offerTitle);
[offersDictionary setObject:offerDet forKey:#"offerDetail"]; NSLog(#"offerDet:%#",offerDet);
[offersDictionary setObject:offerDay forKey:#"day"]; NSLog(#"OfferDay:%#",offerDay);
NSLog(#"DidEndELEMENT");
//[offersArray addObject:[offersDictionary copy]];
}
}
I've set "NSlog" in my didStartElement and in my didEndElement methods, but I only get output from the didEndElement.
I'm calling the "parse" method of the NSXML from the viewDidLoad method.
here is my viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
//alloc and init the array
offersArray = [[NSMutableArray alloc] init];
//create NSUrl with the xml file
NSURL *xmlUrl = [NSURL URLWithString:#"http://mydomain.org/dir/dir/file.xml"];
//alloc and init the xml parser with the data of the file
xmlParser = [[NSXMLParser alloc]initWithContentsOfURL:xmlUrl];
//set some methods on the xml parser
[xmlParser setDelegate:self];
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
//create a 'success gate' of the 'parse' method
BOOL xmlParseSuccess = [xmlParser parse];
if (xmlParseSuccess) {
NSLog(#"Successed Parsing! array Has %lu elements.", (unsigned long)offersArray.count);
} else if (!xmlParseSuccess) {
NSLog(#"Error Parsing!");
}
// Do any additional setup after loading the view.
}
Why is the didStartElement method not being called?
Here is your issue:
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
/*
Your setting elementName to element. So whatever the
value of 'element' is, it will compare to #"offer".
It seems that the value of 'element' is not equal
to #"offer". You should not be Comment this line out
and it should work fine.
*/
elementName = element;
if ([elementName isEqualToString:#"offer"]) {
offersDictionary = [[NSMutableDictionary alloc] init];
offerTitle = [[NSMutableString alloc] init];
offerDay = [[NSMutableString alloc] init];
offerDet = [[NSMutableString alloc] init];
NSLog(#"PARSER didStartElement method!");
}
}
I am making an app for my site, which I need to include images in the table view.
RSS picture I'm trying to find:
<description>
<![CDATA[
<img width="1100" height="1010" src="http://www.x86cam.com/wp-content/uploads/2013/11/twilight_sparkle_with_the_twicane_by_diamondsword11-d6vn28u.png" class="attachment- wp-post-image" alt="twilight_sparkle_with_the_twicane_by_diamondsword11-d6vn28u" style="display: none" />I will not give any links, but I just need to warn y’all. Watch out for spoilers all over sites. Source: Here
]]>
</description>
I don't know how I would find the image tag in this.
#pragma mark - parsing of RssFeed Values
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc]init];
title = [[NSMutableString alloc]init];
link = [[NSMutableString alloc] init];
desc = [[NSMutableString alloc] init];
image = [[NSMutableString alloc] init];
pubDate = [[NSMutableString alloc] init];
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[item setObject:desc forKey:#"description"];
[item setObject:pubDate forKey:#"pubDate"];
[feeds addObject:[item copy]];
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([element isEqualToString:#"title"]) {
[title appendString:string];
}else if ([element isEqualToString:#"link"]){
[link appendString:string];
}else if ([element isEqualToString:#"description"]){
[desc appendString:string];
}else if ([element isEqualToString:#"pubDate"]){
[pubDate appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.tableView reloadData];
}
I would like the app to parse the XML and find the <img> tag in the <description> and then get the src=""
Anyone willing and able to help me on this?
The image link your are looking to extract is inside a CDATA block, but rss parser ignores CDATA block.
If you need to extract the string from CDATA, you could use this block in foundCDATA:
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
NSMutableString *cdstring = [[NSMutableString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
}
now the mutablestring "cdstring" will be containing:
"img width="1100" height="1010" src="http://www.x86cam.com/wp-content/uploads/2013/11/twilight_sparkle_with_the_twicane_by_diamondsword11-d6vn28u.png" class="attachment- wp-post-image" alt="twilight_sparkle_with_the_twicane_by_diamondsword11-d6vn28u" style="display: none" />I will not give any links, but I just need to warn y’all. Watch out for spoilers all over sites. Source: Here"
now just search for src=" using stringcontainsstring and extract the link
-cheers :)
P.S: if you can ask the provider of rss feed to give it in normal block without CDATA, you can extract the link easily by using following method:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
// In this method parameter 'attributeDict' will return you all the sub attributes of main attribute.
// In your case its 'url' of Picture.
// I hope this will help you. Check this out.
if ([element isEqualToString:#"img"]){
[attributeDict valueForKey:<#"src">]
}
Hope it helps
I'm trying to obtain the url contained in media:content tag of the Yahoo RSS feed. The code for didStartElement(), foundCharacters() and didEndElement() is given below:
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:kChannelElementName]) {
Channel = [[channel alloc] init];
dict=[[NSMutableDictionary alloc] init];
[Channel setItemCollectionArray:[[NSMutableArray alloc] init]];
return ;
}
if ([elementName isEqualToString:kItemElementName]) {
itemCollection=[[ItemDataCollection alloc] init];
return ;
}
if ([elementName isEqualToString:kTitleElementName]) {
return ;
}
if([elementName isEqualToString:kItemDescription]){
return ;
}
if ([elementName isEqualToString:kItemImage]) {
NSString *urlString = attributeDict[#"url"];
if(urlString){
[dict setObject:urlString forKey:#"img"];
}
return ;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (currentElementData == nil) {
self.currentElementData = [[NSMutableString alloc] init];
}
[currentElementData appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:kChannelElementName]) {
[channelCollection addObject:Channel];
NSLog(#"channel are***********%#",channelCollection);
for(ItemDataCollection *mydata in Channel.itemCollectionArray){
NSLog(#"___%# <><><><><> desc \n %# <><><><><><> img \n %#",mydata.title,mydata.itemDescription,mydata.titleImage);
}
Channel =nil;
}
else if ([elementName isEqualToString:kItemElementName]) {
[[Channel itemCollectionArray] addObject:itemCollection];
itemCollection=nil;
}
else if ([elementName isEqualToString:kTitleElementName]) {
if(itemCollection==nil){
Channel.title=currentElementData;
}
else{
itemCollection.title=currentElementData;
}
}
else if ([elementName isEqualToString:kPubDate]) {
Channel.pubDate=currentElementData;
}
else if ([elementName isEqualToString: kItemDescription]) {
if(itemCollection!=nil){
itemCollection.itemDescription=currentElementData;
}
}
else if([elementName isEqualToString:#"media:content"]){
if(itemCollection!=nil){
itemCollection.titleImage = currentElementData;
}
}
// [currentElementData release];
self.currentElementData = nil;
}
I'm printing the parsed data as log. The image is showing as null. Everything else eg;title and description is getting obtained properly. How can I fix it? Probably something needs to be done in the didEndElement method. But I don't know what. I've been racking my brains over this since yesterday. Please help!!
I made some changes in didStartElement():
if ([elementName isEqualToString:kItemImage]) {
NSString *urlString = attributeDict[#"url"];
if(urlString){
[dict setObject:urlString forKey:#"img"];
NSLog(#"%#",urlString);
mString = [NSString stringWithFormat:urlString];
and some change in didEndElement():
else if([currentElementData rangeOfString:#"media:content"].location){
if(itemCollection!=nil){
// [currentElementData appendString:dict];
itemCollection.titleImage = mString;
}
}
mString has been declared as a mutable string. Images are getting parsed now. Their urls are getting displayed in the log. The problem is that now, the last image is repeated twice.. It is probably because the last feed does not have an image, so it is using the previous one. How to fix that? I mean, there can be multiple feeds without images. in that case, it should actually display null rather than the url of the previous image.
I don`t know well about Yahoo rss feed but i hope it will help you.....
Just tryout this....
- (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];
currentImage = [[NSMutableString alloc] init];
}
else if([elementName isEqualToString:#"media:content"]) {
currentImage = [attributeDict objectForKey:#"img src"];
NSLog(#"Url:%#", currentImage);
}
}
}
I am using NSXMLParser to parse my XML with the following structure:
<characters>
<character>
<literal>本</literal>
<codepoint>
<cp_value cp_type="ucs">672c</cp_value>
<cp_value cp_type="jis208">43-60</cp_value>
</codepoint>
</character>
</characters>
I want to use the cp_value element's attribute_value as a key and the element value (e.g. 672c) as the value and place this key-value pair in my NSMutableDictionary *_codepoint. After parsing, I want the result (in the console) to look like this:
_codepoint: {
"ucs"=672c;
"jis208"=43-60;
}
As I have implemented the parser (code follows), I am getting this back in the console:
2013-01-22 22:12:46.199 MyApp[13391:c07] _codepoint: {
ucs = "\n \n ";
}
2013-01-22 22:12:46.201 MyApp[13391:c07] _codepoint: {
jis208 = "\n \n 672c\n ";
}
First - the values and keys are out-of-sync and second, the value for the jis208 element is not getting read-in. Second, I'm not sure what these \n and whitespaces are. Can anybody please give some advice?
The code I have written is:
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"characters"]) {
appDelegate.characters = [[NSMutableArray alloc] init];
} else if ([elementName isEqualToString:#"character"]) {
aCharacter = [[Character alloc] init];
} else if ([elementName isEqualToString:#"cp_value"]) {
if (!_codepoint) _codepoint = [[NSMutableDictionary alloc] init];
[_codepoint setValue:currentElementValue forKey:[attributeDict valueForKey:[[attributeDict allKeys] lastObject]]];
NSLog(#"_codepoint: %#", _codepoint);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentElementValue) {
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
[currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"characters"]
// cp_values will be copied from a local NSMutableDictionary *_codepoint
|| [elementName isEqualToString:#"codepoint"]
) return;
if ([elementName isEqualToString:#"character"]) {
[appDelegate.characters addObject:aCharacter];
[aCharacter release];
} else if ([elementName isEqualToString:#"cp_value"]){
[aCharacter.codepoint addObject:_codepoint];
}
}
Thank you very much for looking.
problem is that you are adding currentElementValue to _codepoint before reading actual value into currentElementValue i.e you are adding it in when cp_value is started. you should add currentElementValue to _codepoint in didEndElement: delegate method.Then you'll get expected result.Modify your code like this:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"characters"]) {
appDelegate.characters = [[NSMutableArray alloc] init];
} else if ([elementName isEqualToString:#"character"]) {
aCharacter = [[Character alloc] init];
} else if ([elementName isEqualToString:#"cp_value"]) {
if (!_codepoint) _codepoint = [[NSMutableDictionary alloc] init];
currentAttributeKey = [[NSMutableString alloc]initWithString:[attributeDict valueForKey:[[attributeDict allKeys] lastObject]]];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentElementValue) {
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
[currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"characters"] || [elementName isEqualToString:#"codepoint"])
return;
if ([elementName isEqualToString:#"character"]) {
[appDelegate.characters addObject:aCharacter];
[aCharacter release];
} else if ([elementName isEqualToString:#"cp_value"]){
[_codepoint setValue:[[currentElementValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:#""] forKey:currentAttributeKey];
currentElementValue = [[NSMutableString alloc]init];
NSLog(#"_codepoint: %#", _codepoint);
[aCharacter.codepoint addObject:_codepoint];
}
}
where currentAttributeKey is NSMutableString that will store the attributes.In your case ucs and jis208