How to i parse elements with [CDATA] tags - nsxmlparser

I'm trying to pull images from my tag using NSScanner, but my tag has a [CDATA] block that makes my NSXLM parser ignore everything inside that tag. How can i parse the data inside my tag, heres a sample of the rss feed , and a sample of the parser code.
<item>
<title>Kendrick Lamar & Lady Gaga in Chi-Town</title>
<link>http://www.motahiphop.com/rap-pix/36-rap-pix/2346-kendrick-lamar-lady-gaga-in-chi-town</link>
<guid isPermaLink="true">http://www.motahiphop.com/rap-pix/36-rap-pix/2346-kendrick-lamar-lady-gaga-in-chi-town</guid>
<description><![CDATA[<p style="text-align: center;"><img src="http://www.motahiphop.com/images/lady-gaga-kendrick-lamar.jpg" width="500" alt="Kendrick Lamar with Lady Gaga at Pitchfork festival" /></p>
After tweeting that she was a Kendrick Lamar fan last week. Lady Gaga caught up with the Compton MC back stage at Chicago's Pitchform Music festival.]]>
gqwebsites#gmail.com (Super User)
Featured
Rap Pix
Rap Pix
Mon, 16 Jul 2012 13:18:45 -0400
Parser code snippet:
if ([elementName isEqualToString:#"item"])
{
elements[#"title"] = title;
elements[#"date"] = date;
elements[#"summary"] = summary;
elements[#"link"] = link;
elements[#"description"] = description;
//NSLog(#"%#", description);
[posts addObject:elements];
}

after some research I found the answer on another post, I used this method
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
NSString *description = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
NSString *storyImageURL = [self getFirstImageUrl:description];
NSLog(#"%#",storyImageURL);
I added the NSLog at the end so you can NSLog the results and check that the data is being pulled. works like a charm

Related

GCD-created thread throws abort after completing block message

I developed a simple RSS fetcher application that parses an XML RSS feed from a programmer-provided website and displays the articles in the Master View Controller and the UIWebView in a Detail View Controller. I custom set-up a personal server to render the RSS article selected in the master table view (for certain reasons) as a PDF. However, this obviously takes some time on the server end, unless the selected table view cell has already been rendered as a PDF on the server end. My server and blog don't talk to one another (and can't, for other reasons), so I can't pre-render the PDFs as I create the blog posts. The PDF render must be done from the application itself.
I decided to use Grand Central Dispatch to create a separate thread to talk to the server and render the PDFs before the user can select an arbitrary cell to see the post. Here is the code I used to create the queue.
dispatch_queue_t networkQueue = dispatch_queue_create("com.company.networkQueue", NULL);
...and the code I used to create the new thread...
dispatch_async(networkQueue, ^{ [self cachePDFRequests]; });
...here is my cachePDFRequests method that is called in the block request...
- (void) cachePDFRequests {
NSURL *myURL;
NSString *cacheUrl;
NSURLRequest *request;
for (int i = 0; i <= feeds.count; i++) {
cacheUrl = [feeds[i] objectForKey:#"link"];
cacheUrl = [cacheUrl stringByReplacingOccurrencesOfString:#" " withString:#""];
cacheUrl = [cacheUrl stringByReplacingOccurrencesOfString:#"\n" withString:#""];
NSString *fullUrl = [NSString stringWithFormat:#"http://myserver.com/render.php?url=%#", cacheUrl];
myURL = [NSURL URLWithString:fullUrl];
request = [NSURLRequest requestWithURL:myURL];
[cacheView loadRequest:request];
}
}
Note: cacheView is a UIWebView that is not on any UI...it is just an ivar of my Master VC class.
So, when I run the dispatch_async() function in -[viewDidLoad], it runs the -[cachePDFRequests] method and the for() loop inside of it, then throws SIGABRT on my newly-created thread. Please ask any questions as necessary. Let me know if I need to include any code that I haven't already provided.
Here is a picture of the SIGABRT error that appears whenever I run the GCD thread:
Thanks in advance!
P.S. I used to run cacheView = [[UIWebView alloc] init]; in an if() loop if the cacheView was set to nil...that used to throw the SIGABRT error. Now, it has no references to code in my Master View Controller after I removed that line.
EDIT: Here is the code for what the feeds mutable array is containing:
- (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]];
}
It looks like you are accessing feeds out of bounds. NSArray will throw an exception if you try to access it with an index that is outside of its bounds, and that is exactly what the backtrace indicates. This is the correct way to loop over an array with indices starting with 0:
for (int i = 0; i < feeds.count; i++) // Notice that it uses < instead of <= as comparator
As a side note, there is no such thing as an if() loop.

Using NSScanner

I am trying to scan a text, but I do not understand how it works, could anybody help me??
<a class="lightbox" title ="elecciones mexico 2012" href="http://www.myWebpage.com/wp-content/uploads/2012/07/elecciones-mexico-2012.jpg"><img src="http://www.myWebpage.com/wp-content/uploads/2012/07/elecciones-mexico-2012.jpg" alt="" title="elecciones mexico 2012" width="643" height="391" class="aligncenter size-full wp-image-66795" /></a></p>
<p>I need this text</p>
<p> And this text.</p>
<p> Also this text! </p>
<p> I dont want this text </p>]]>
So that my final string would be something like:
I need this text
And this text
Also this text!
Thanks in advance
Wasting your shot. That's why NSXMLParser is there.
#interface TextParser: NSObject {
NSMutableString *text;
}
- (id)init
{
if ((self = [super init]))
{
text = [[NSMutableString alloc] init];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[string dataUsingEncoding:NSUTF8Stringaencoding];
parser.delegate = self;
[parser parse];
// here text will contain all the text contained by the XML tags
}
return self;
}
- (void)parser:(NSXMLParser *)p foundCharacters:(NSString *)chars
{
[text appendString:chars];
}
Well, the NSScanner that I know (MacOS) isn't particulary suitable for the kind of parsing you are looking for. It just goes through a string and returns "tokens" like numbers or strings defined by the set of characters they are made of. This is not particulary useful to process the tags in your string example, unless you are willing to accept a high chance of errors.
In that case, you could probably do something like "read a string composed of anything but <" and attach that to the result string, then "read a string composed of anything but >" and discard that and so on, until you have reached the end. Depending on what you are actually trying to parse this may or may not work; it's definitely not "the way" to get the plain text from HTML.
It's not XML either (the tags don't match), so using NSXML probably isn't an option either...

Unable to get data from a div tag using HTML parsing (hpple) in iPhone

I am trying to parse the below link using hpple:
http://www.decanter.com/news/wine-news/529748/mimimum-pricing-opponents-slam-cameron-speech
Code:
- (void)parseURL:(NSURL *)url {
NSData *htmlData = [NSData dataWithContentsOfURL:url];
TFHpple *xpathParser = [[TFHpple alloc] initWithHTMLData:htmlData];
NSArray *elements = [xpathParser searchWithXPathQuery:#"<div class=\"body\" id=\"article-529748-body\">"];
NSLog(#"elements %#",elements);
TFHppleElement *element = [elements objectAtIndex:0];
NSString *myTitle = [element content];
[xpathParser release];
}
but it is crashing. Crash Report:
XPath error : Invalid expression
<div class="body" id="article-529748-body">
^
XPath error : Invalid expression
<div class="body" id="article-529748-body">
^
How to solve this issue? why my elements array is empty? Am I parsing in a wrong way? I want to get the information available in that div tag.
Check that your elements array is not empty
- (void)parseURL:(NSURL *)url {
NSData *htmlData = [NSData dataWithContentsOfURL:url];
TFHpple *xpathParser = [[TFHpple alloc] initWithHTMLData:htmlData];
NSArray *elements = [xpathParser searchWithXPathQuery:#"<div class=\"body\" id=\"article-529748-body\">"];
NSLog(#"elements %#",elements);
if([elements count]){
TFHppleElement *element = [elements objectAtIndex:0];
}
NSString *myTitle = [element content];
[xpathParser release];
}
Try changing this:
NSArray *elements = [xpathParser searchWithXPathQuery:#"<div class=\"body\" id=\"article-529748-body\">"];
To:
NSArray *elements = [xpathParser searchWithXPathQuery:#"//div [#class='body'] [#id=\'article-529748-body\']"];
Writing this (2 years later!) in case it's useful to someone else with a similar problem.
In order to parse the html within the div, you need to
use syntax similar (single-quotes don't need to be escaped) to that quoted by JamMySon on this page
remember that [element content] only gives you the content( if any) for that node , NOT its children.
Because of this you may need to use recursion to walk though the div's node-tree.
Code (ARC):
- (void) decanterHpple{
NSURL *url = [NSURL URLWithString:#"http://www.decanter.com/news/wine-news/529748/mimimum-pricing-opponents-slam-cameron-speech"];
NSData *htmlData = [NSData dataWithContentsOfURL:url];
TFHpple *pageParser = [TFHpple hppleWithHTMLData:htmlData];
NSString *queryString = #"//div[#id='article-529748-body']";//1.works with unescaped single-quotes(') AND 2.No need for class='' when using id=''
NSArray *elements = [pageParser searchWithXPathQuery:queryString];
//old code ~ slightly amended
if([elements count]){
TFHppleElement *element = [elements objectAtIndex:0];
NSString *myTitle = [element content];
NSLog(#"myTitle:%#",myTitle );
}
//new code
NSString *theText = [self stringFromWalkThruNodes:elements];
NSLog(#"theText:%#",theText );
}
using this recursive method:
- (NSString*) stringFromWalkThruNodes:(NSArray*) nodes {
static int level = 0;//level is only useful for keeping track of recursion when stepping through with a breakpoint
level++;//put breakpoint here...
NSString *text = #"";
for (TFHppleElement *element in nodes){
if (element.content) {
text = [text stringByAppendingString:element.content];
}
if (element.children) {
NSString *innerText = [self stringFromWalkThruNodes:element.children];
text = [text stringByAppendingString:innerText];
}
}
level--;
return text;
}
This gives the output:
2014-10-22 19:44:07.996 Decanted[10148:a0b] myTitle:(null)
2014-10-22 19:44:07.997 Decanted[10148:a0b] theText:
On a visit to a hospital in north-east England, Mr Cameron is to call for the drinks industry to do more to tackle a problem which
costs the National Health Service £2.7bn a year.A ban on the sale of
alcohol below cost price - less than the tax paid on it - is set to be
introduced in England and Wales from 6 April, but ministers are
expected to push for a higher minimum price for drink.Opponents of a
minimum unit price say it is unfair because it penalises all drinkers,
not just binge or problem drinkers.Responding to the Prime Minister’s
comments, Wine and Spirit Trade Association spokesman Gavin Partington
reiterated the drinks indusry’s commitment ‘to helping the Government
tackle alcohol misuse, alongside other stakeholders.‘This is why we
are working hard through the Public Health Responsibility Deal on a
range of initiatives to promote responsible drinking.’These
initiatives, Partington said, include the expansion of Community
Alcohol Partnerships across the UK and a national campaign by
retailers to raise consumer awareness about the units of alcohol in
alcoholic drinks.Partington said, ‘Unlike these measures, minimum unit
pricing is a blunt tool which would both fail to address the problem
of alcohol misuse and punish the vast majority of responsible
consumers. As Government ministers acknowledge, it is also probably
illegal'.Decanter is also against the scheme, calling it
‘fundamentally flawed.’‘The real problem,’ editor Guy Woodward has
said, ‘lies with supermarkets who use wine as a loss-leader, slashing
margins, bullying suppliers and dragging down prices in order to
attract customers…Selling wine at a loss helps neither consumers nor
the trade.’Other opponents of the scheme include the British Beer and
Pub Association, which told the BBC there was ‘a danger it would be
done through higher taxation, which would be hugely damaging to
pub-goers, community pubs and brewers, costing thousands of vital
jobs.’It is thought any move toward minimum pricing could also be
illegal under European competition law, which is aimed at pushing down
prices for consumers and allowing firms to operate in a free
market.
PS. Only started playing with Hpple this p.m. after reading the aforementioned Wenderlich tutorial; I'm sure someone more experienced may come up with a more elegant solution!

NSXMLParser works not correct with symbols like “

I have some problems with parsing of xml in my iPhone Application. Here is some part of xml code that I want to parse with standard NSXMLParser parser.
<item>
<title>AMNews: Facebook & Twitter Updates Might Lead To Burglary, Oldham School Violates DPA, Amazon Cloud “Burstsâ€</title>
<link>http://www.itproportal.com/2011/04/22/amnews-facebook-twitter-updates-might-lead-to-burglary-oldham-school-violates-dpa-amazon-cloud-bursts/</link>
<description>People announcing their holiday plans on social networking platforms like Facebook and Twitter are putting themselves at risks from thieves and burglars. A new study ha</description>
<author>ravimandalia#itproportal.com (Ravi Mandalia)</author>
<pubDate>Fri, 22 Apr 2011 08:19:36 +0100</pubDate>
<guid>http://cdn.itproportal.com/photos/facebook-logo-4_thumb80x80.png</guid>
</item>
How you can see in
<title>AMNews: Facebook & Twitter Updates Might Lead To Burglary, Oldham School Violates DPA, Amazon Cloud “Burstsâ€</title>
title tag some strange symbols appear "“" "â". In function
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
I am trying to get title and save it, but my parser works wrong. Parser take only text after "“" symbol !!!
What can I do and can anybody tell me what happens with parse ? Thanks a lot !!!
Can you show us your implementation of -parser:foundCharacters:? How do you store string?
I have also once used an NSXMLParser with special characters in the XML file, and it worked without problems.
Here is implementation of -parser:foundCharacters:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
//in case of unusable tags
if (currentArticle == nil) {
return;
}
// Get Title.
if ([currentElement isEqualToString:#"title"]) {
[self.currentArticle setTheTitle:string];
// Get Description.
} else if ([currentElement isEqualToString:#"description"]) {
string = [string stringByReplacingOccurrencesOfString: #"\n" withString: #"" ];
[self.currentArticle setTheSummary:string];
} else if ([currentElement isEqualToString:#"link"]) {
[self.currentArticle setTheMainLink:string];
} else if([currentElement isEqualToString:#"guid"]){
[self.currentArticle setTheImageLink:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[self.currentArticle setThePubDate:string];
} else if([currentElement isEqualToString:#"author"]){
[self.currentArticle setTheAuthor:string];
}
}
I have notice that parser get title two times at first time from the begin to the “ and second time from “ to end. Like in my feed there are two title tags.

iPhone: what's the best way to display a "report'?

I have an app where I need to display a report of six (6) columns and a variable number of rows (lines).
What's the best approach to do this? I tried UITextView but there is no way to set the font size to make the data fit on each line.
I usually use UIWebViews for this.
A dozen lines to create a html table out of a NSArray and some nice CSS.
Edit: I can show you an example I wrote in the last 5 minutes. There's not much to it if you have a basic understanding of html. Of course you could take it much further than that.
And even if you don't know anything about html I'm sure you can learn the basics for some simple table display within a couple of hours.
- (NSString *)htmlTableRowFromArray:(NSArray *)array withOpenTag:(NSString *)openTag andCloseTag:(NSString *)closeTag {
NSMutableString *rowHtmlStr = [NSMutableString string];
for (NSString *str in array) {
[rowHtmlStr appendFormat:#"%# %# %#\n", openTag, str, closeTag];
}
return rowHtmlStr;
}
- (void)displayReport {
NSArray *dataArray = ...;
NSArray *myHeader = ...;
NSMutableString *htmlStr = [NSMutableString stringWithString:#"<html><head><title>MyTable</title></head><body>"];
// the table starts here
[htmlStr appendString:#"<table width=\"100%\" style=\"background-color:#CCC\" border=\"1\" cellpadding=\"4\" cellspacing=\"0\">"];
// this will create a table header
[htmlStr appendFormat:#"<tr>%#</tr>", [self htmlTableRowFromArray:myHeader withOpenTag:#"<th>" andCloseTag:#"</th>"]];
for (NSArray *line in dataArray) {
// one row for each array in the data
[htmlStr appendFormat:#"<tr>%#</tr>", [self htmlTableRowFromArray:line withOpenTag:#"<td>" andCloseTag:#"</td>"]];
}
// table ends
[htmlStr appendString:#"</table>"];
[htmlStr appendString:#"</body></html>"];
[webView loadHTMLString:htmlStr baseURL:nil];
}
the table should look like this. Imho not that bad for the amount of work.