Retrieve contents from HTML which is a NSString - html

This is my NSString :
NSString timeString = #"<h5 style="direction:ltr"><span data-version-created-date="20180326T120530.000+0000" class="releasedDate">26-Mar-2018 12:05:30</span></h5>";
I want to retrieve only "26-Mar-2018 12:05:30" which is in the span tag.
How do i do that in Objective C?
Please note : The given HTML is in NSString format.

Try this
- (NSString *)stringByStrippingHTML : (NSString*) s {
NSRange r;
while ((r = [s rangeOfString:#"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
s = [s stringByReplacingCharactersInRange:r withString:#""];
return s;
}

This will work by stripping out bracketed (<>) expressions. Slashes have been added () to timeString to make it proper NSString*. The stripping is repeated four times, bt should probably be looped with condition.
NSString * timeString = #"<h5 style=\"direction:ltr\"><span data-version-created-date=\"20180326T120530.000+0000\" class=\"releasedDate\">26-Mar-2018 12:05:30</span></h5>";
NSRange openRange = [timeString rangeOfString:#"<"];
NSRange closeRange = [timeString rangeOfString:#">"];
NSRange enclosedRange = NSMakeRange(openRange.location, closeRange.location-openRange.location+1);
timeString = [timeString stringByReplacingCharactersInRange:enclosedRange withString:#""];
openRange = [timeString rangeOfString:#"<"];
closeRange = [timeString rangeOfString:#">"];
enclosedRange = NSMakeRange(openRange.location, closeRange.location-openRange.location+1);
timeString = [timeString stringByReplacingCharactersInRange:enclosedRange withString:#""];
openRange = [timeString rangeOfString:#"<"];
closeRange = [timeString rangeOfString:#">"];
enclosedRange = NSMakeRange(openRange.location, closeRange.location-openRange.location+1);
timeString = [timeString stringByReplacingCharactersInRange:enclosedRange withString:#""];
openRange = [timeString rangeOfString:#"<"];
closeRange = [timeString rangeOfString:#">"];
enclosedRange = NSMakeRange(openRange.location, closeRange.location-openRange.location+1);
timeString = [timeString stringByReplacingCharactersInRange:enclosedRange withString:#""];
NSLog(#"timeString = %#", timeString);

This worked with me
NSString *timeString = #"<h5 style=\"direction:ltr\"><span data-version-created-date=\"20180326T120530.000+0000\" class=\"releasedDate\">26-Mar-2018 12:05:30</span></h5>";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#">\\d.+\\d<"
options:NSRegularExpressionCaseInsensitive
error:NULL];
[regex enumerateMatchesInString:timeString options:0 range:NSMakeRange(0, [timeString length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
// your code to handle matches here
NSString *subString = [timeString substringWithRange:match.range];
NSLog(#"%#",[subString substringWithRange:NSMakeRange(1, subString.length - 2)]);
}];

If you want to make sure you get the date between the span tags, it would be best to be more explicit than either stripping out all the HTML tags and assuming the only thing left is the date, or assuming there is only one span tag in the whole HTML text. It may work for now, but that will likely break in the future if the HTML ever changes.
NSString * timeString = #"<h5 style=\"direction:ltr\"><span data-version-created-date=\"20180326T120530.000+0000\" class=\"releasedDate\">26-Mar-2018 12:05:30</span><span class=\"someOtherClass\">garbageData</span></h5>";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"<span.*class=\"releasedDate\"[^>]*>(.*)</span.*>"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSTextCheckingResult *textCheckingResult = [regex firstMatchInString:timeString options:0 range:NSMakeRange(0, timeString.length)];
NSString *releaseDateString = [timeString substringWithRange:[textCheckingResult rangeAtIndex:1]];
if( ! [releaseDateString isEqualToString:#""] )
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MMM-yyyy' 'HH:mm:ss"];
NSDate *releaseDate = [dateFormatter dateFromString:releaseDateString];
NSLog( #"%# - %#", releaseDateString, releaseDate );
}
Note that this works even if there are other spans in the HTML text. It specifically pulls out the one with a class "releasedDate".

Related

NSString remove html tags, keep <Text in angle brackets>

How do I remove html tags from NSString, but keep any <Text in angle brackets>?
Like <p>123 <Hello> abc</p> -> 123 <Hello> abc
I have tried all kinds of regexp, scanner and XML Parser solutions, but they remove <Text in angle brackets> as well as tags.
The only solution that fit me was to use an NSAttributedString with options
NSAttributedString *str = [[NSAttributedString alloc] initWithData:utf8Data
options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)}
documentAttributes:nil
error:nil];
NSString *result = [str string];
but this approach employs WebKit and consumes too much memory for my task.
So, how do I strip tags from NSString, keeping <Text in angle brackets> without using any kind of WebKit/UIWebView and so on?
I asked a similar questionma while ago, may be some of the answers can help you out.
If you do need the full HTML parser and just want to strip HTML tags out, a NSString category might be useful (this one is a modified category by mwaterfal):
- (NSString *)stringByStrippingTags {
// Find first & and short-cut if we can
NSUInteger ampIndex = [self rangeOfString:#"<" options:NSLiteralSearch].location;
if (ampIndex == NSNotFound) {
return [NSString stringWithString:self]; // return copy of string as no tags found
}
// Scan and find all tags
NSScanner *scanner = [NSScanner scannerWithString:self];
[scanner setCharactersToBeSkipped:nil];
NSMutableSet *tags = [[NSMutableSet alloc] init];
NSString *tag;
do {
// Scan up to <
tag = nil;
[scanner scanUpToString:#"<" intoString:NULL];
[scanner scanUpToString:#">" intoString:&tag];
if (tag) {
NSString *t = [[NSString alloc] initWithFormat:#"%#>", tag];
[tags addObject:t];
}
} while (![scanner isAtEnd]);
NSMutableString *result = [[NSMutableString alloc] initWithString:self];
NSString *finalString;
NSString *replacement;
for (NSString *t in tags) {
replacement = #" ";
if ([t isEqualToString:#"<a>"] ||
[t isEqualToString:#"</a>"] ||
[t isEqualToString:#"<span>"] ||
[t isEqualToString:#"</span>"] ||
[t isEqualToString:#"<strong>"] ||
[t isEqualToString:#"</strong>"] ||
[t isEqualToString:#"<em>"] ||
[t isEqualToString:#"</em>"]) {
replacement = #"";
}
[result replaceOccurrencesOfString:t
withString:replacement
options:NSLiteralSearch
range:NSMakeRange(0, result.length)];
}
// Remove multi-spaces and line breaks
return = [result stringByRemovingNewLinesAndWhitespace];
}

export data in html table format in ios7 and make email body

I am new in iphone application development. In my application i am using two different NSMutable array's. Both have dictionary with 4 fields like name, address etc at each index. Now my problem is I want to export that data in HTML table format and make email body. So please, can any one help me.
thank you
For example items are:
NSMutableArray *arrItem = [NSMutableArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"sam",#"name",#"london",#"address",nil], nil];
Now create html string like this :
NSString *strHTML = #"<!DOCTYPE html>"
#"<html><body>"
#"<table border=\"1\" style=\"width:300px\">"; //change width according to your requirement
for (NSDictionary *dict in arrItem) {
NSString *strName = [dict objectForKey:#"name"];
NSString *strAddress = [dict objectForKey:#"address"];
strHTML = [strHTML stringByAppendingString:#"<tr>"];
//add table column value
strHTML = [strHTML stringByAppendingString:[NSString stringWithFormat:#"<td>%#</td>",strName]];
strHTML = [strHTML stringByAppendingString:[NSString stringWithFormat:#"<td>%#</td>",strAddress]];
strHTML = [strHTML stringByAppendingString:#"</tr>"];
}
strHTML = [strHTML stringByAppendingString:#"</table>"
#"</body>"
#"</html>"];
Use hmtl string in MailcompserViewController :
[controller setMessageBody:strHTML isHTML:YES];
EDIT : formatted
MailcompserViewController *controller = [[MailcompserViewController alloc] init];//Allocating mailComposer
NSString *eMailBody=#""; //Value for row
for (int i=0; i<[arrMailList count]; i++) { //Get all the row value
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
MailData *data = [arrMailList objectAtIndex:i]; //Get array value in NSObject class
NSDate *date = [dateFormat dateFromString:data.date];
NSDateFormatter *dateFormat1 = [[NSDateFormatter alloc] init];
[dateFormat1 setDateFormat:#"EEEE, dd MMMM yyyy"]; //Date NSDateFormatter
NSString *strDate = [dateFormat1 stringFromDate:date];
NSString *numbers = [data.setName stringByTrimmingCharactersInSet:[NSCharacterSet letterCharacterSet]];
eMailBody = [eMailBody stringByAppendingFormat:#"<tr><td width=\"200px\">%#</td><td >%#</td><td >%#</td><td >%#</td><td>%#</td><td >%#</td></tr>",strDate,data.Name,data.email,data.address,data.phoneNumber];//Create row
}
NSString *html = [NSString stringWithFormat:#"<html><style>body{font-family:Helvetica;font-size:14px;}th{fontcolor:#ffffff;font-size:16px;font-weight:BOLD;}</style><body><table cellpadding=5px border=1px bordercolor=#000000><tr bgcolor=#cccccc><th width=200>Date</th><th>Workout Name</th><th>Excercise Name</th><th>Set</th><th>Weight</th><th>Reps</th>%#</table></body></html>",eMailBody]; //Add row in table view
[controller setMessageBody:html isHTML:YES];
[self presentViewController:controller animated:YES completion:nil];
var str = "\n"
str=str.stringByAppendingString("<tr><th>")
str=str.stringByAppendingString("Task")
str=str.stringByAppendingString("</th>")
str=str.stringByAppendingString("<th>")
str=str.stringByAppendingString("SpareParts")
str=str.stringByAppendingString("</th>")
str=str.stringByAppendingString("<th>")
str=str.stringByAppendingString("Labour")
str=str.stringByAppendingString("</th></tr>\n")
var i:Int=0
for i=0;i<carImageList.count;i++
{
str=str.stringByAppendingString("<tr><td>")
str=str.stringByAppendingString(carImageList[i] as! String)
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString(carImageList[i] as! String)
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString(carImageList[i] as! String)
str=str.stringByAppendingString("</td></tr>\n")
}
//SubTotal
str=str.stringByAppendingString("<tr><td>")
str=str.stringByAppendingString("Sub Total")
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString("100")
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString("100")
str=str.stringByAppendingString("</td></tr>\n")
//Total
str=str.stringByAppendingString("<tr><td>")
str=str.stringByAppendingString("Total")
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td colSpan='2'>")
str=str.stringByAppendingString("300")
str=str.stringByAppendingString("</td></tr>\n")
str=str.stringByAppendingString("</table></body></html>\n")
NSLog("TEST %#",str)
mailComposerVC.setMessageBody(str, isHTML: true)

Three20 Navigation: View don't show

I rework my app to use Three20 and I wanna use Three20 navigation now.
Here is my code, that works perfectly before:
ENSListViewController *vc = [ENSListViewController alloc];
NSArray *ensArray;
NSDictionary *dic;
NSInteger folder_id;
NSString* folder_type;
NSString* barTitle;
NSString* folderName;
if (indexPath.section == 0)
{
ensArray = [ensFolderList objectForKey:#"an"];
dic = [ensArray objectAtIndex:indexPath.row];
folder_type = #"an";
barTitle = [NSString stringWithFormat:#"%#", [dic objectForKey:#"name"]];
folder_id = [[dic objectForKey:#"ordner_id"] intValue];
folderName = [dic objectForKey:#"name"];
}
else
{
ensArray = [ensFolderList objectForKey:#"von"];
dic = [ensArray objectAtIndex:indexPath.row];
folder_type = #"von";
barTitle = [NSString stringWithFormat:#"%#", [dic objectForKey:#"name"]];
folder_id = [[dic objectForKey:#"ordner_id"] intValue];
folderName = [dic objectForKey:#"name"];
}
vc.folder_id = folder_id;
vc.folder_type = folder_type;
vc.barTitle = barTitle;
vc.folderName = folderName;
[vc initWithNibName:#"ENSListViewController" bundle:nil];
[self.view addSubview:vc.view];
It works perfectly.
It allocs a ViewController, sets a lot of data in the ViewController (Properties) and then show the view.
Here is my code now:
NSArray *ensArray;
NSDictionary *dic;
NSInteger folder_id;
NSString* folder_type;
NSString* barTitle;
NSString* folderName;
if (indexPath.section == 0)
{
ensArray = [ensFolderList objectForKey:#"an"];
dic = [ensArray objectAtIndex:indexPath.row];
folder_type = #"an";
barTitle = [NSString stringWithFormat:#"%#", [dic objectForKey:#"name"]];
folder_id = [[dic objectForKey:#"ordner_id"] intValue];
folderName = [dic objectForKey:#"name"];
}
else
{
ensArray = [ensFolderList objectForKey:#"von"];
dic = [ensArray objectAtIndex:indexPath.row];
folder_type = #"von";
barTitle = [NSString stringWithFormat:#"%#", [dic objectForKey:#"name"]];
folder_id = [[dic objectForKey:#"ordner_id"] intValue];
folderName = [dic objectForKey:#"name"];
}
/*
vc.folder_id = folder_id;
vc.folder_type = folder_type;
vc.barTitle = barTitle;
vc.folderName = folderName;
[vc initWithNibName:#"ENSListViewController" bundle:nil];
//[self.view addSubview:vc.view];
*/
NSString *url = [NSString stringWithFormat:#"tt://ensList/%#/%#/%d/%#/%#/%#", #"ENSListViewController", nil, folder_id, folder_type, barTitle, folderName];
TTURLAction *action = [TTURLAction actionWithURLPath:url];
[[TTNavigator navigator] openURLAction:action];
Here is my Navigator:
navigator = [TTNavigator navigator]; // create the navigator
navigator.persistenceMode = TTNavigatorPersistenceModeAll; // and he will save the data :)
TTURLMap* map = navigator.URLMap;
[map from: #"tt://ens"
toSharedViewController: [ENSOverviewViewController class]];
[map from: #"tt://ensList/(initWithNibName:)/(bundle:)/(folderId:)/(folderType:)/(barTitle:)/(folderName:)" toViewController:[ENSListViewController class]
transition:3];
And here is my new Constructor method:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[self LoadENSList];
}
return self;
}
- (void) initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil folderId:(NSInteger)folder_id2 folderType:(NSString*)folder_type2 barTitle:(NSString*)barTitle2 folderName:(NSString*)folderName2
{
self.folder_id = folder_id2;
self.folder_type = folder_type2;
self.barTitle = barTitle2;
self.folderName = folderName2;
[self initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}
So, if you read it up to here: big thanks!
Now my problem is: The view doesn't open. Nothing happens.
I think there is a mistake in my self made constructor, the order of calling my constructor or something like this. Im on it since 2 hours but can't find the error.
I know Three20 is much undocumented and I am not expacting a fast answer, but if anyone have an idea: please comment or answer.
Found the solution:
1) I forget the return-value in my constructur.
After adding this (changing (void) to (id) and add "return self") it goes on...
2) After he changes in 1) the system crashes because initWithNibName throws an NSInvalidArgument error.
After changing this to init, it works perfectly

Searching for keywords in HTML

The iOS app I'm writing displays an HTML page, and I would like to add a search feature where the user can search for instances of a keyword and highlight them.
What's the best way to do this?
NSString *filePath = PATH_OF_HTML_FILE;
NSError *err = nil;
NSString *pageHTML = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&err];
if(err)
{
pageHTML = [NSString stringWithContentsOfFile:filePath encoding:NSASCIIStringEncoding error:&err];
}
if([searchTxtField.text length])
{
NSRange range1 = [pageHTML rangeOfString:searchTxtField.text options:NSCaseInsensitiveSearch];
if(range1.location != NSNotFound)
{
NSString *highlightedString = [pageHTML substringWithRange:range1];
pageHTML = [pageHTML stringByReplacingOccurrencesOfString:highlightedString withString:[NSString stringWithFormat:#"<span style=\"background-color:yellow; color:red;\">%#</span>",highlightedString] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pageHTML length]) ];
[webView loadHTMLString:pageHTML baseURL:[NSURL fileURLWithPath:filePath]];
}
}

MFMailComposeViewController csv attachment not being attached, but showing inline instead

I am having a problem with sending csv attachments via MFMailComposeViewController.
Sometimes they come through just fine, but for other users they don't come through as attachments, but rather as text inline in the email (with <br/> instead of line returns.) It's very strange. Anybody know what I'm doing wrong?
Here is a snippet of my code:
MFMailComposeViewController *mailComposeViewController = [[MFMailComposeViewController alloc] init];
mailComposeViewController.mailComposeDelegate = self;
NSString *csv = #"foo,bar,blah,hello";
NSData *csvData = [csv dataUsingEncoding:NSUTF8StringEncoding];
[mailComposeViewController addAttachmentData:csvData mimeType:#"text/csv" fileName:#"testing.csv"];
[mailComposeViewController setSubject:#"testing sending csv attachment"];
[mailComposeViewController setMessageBody:#"csv file should be attached" isHTML:NO];
[self presentModalViewController:mailComposeViewController animated:YES];
-(IBAction)btnPressed:(id)sender {
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *docDir = [arrayPaths objectAtIndex:0];
NSString *Path = [docDir stringByAppendingString:#"/CSVFile.csv"];
NSData *csvData = [NSData dataWithContentsOfFile:Path];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"For csv file..."];
[controller setMessageBody:#"...csv file is hear.." isHTML:NO];
[controller addAttachmentData:csvData mimeType:#"text/csv" fileName:#"CSVFile.csv"];
[self presentModalViewController:controller animated:YES];
[controller release];
}
Hi I put sample code for Creating CSV file and attach it with mail but make sure you have to add MessageUI.Framework and import its related header "MessageUI/MessageUI.h"
"MessageUI/MFMailComposeViewController.h" and deligate "MFMailComposeViewControllerDelegate"...I hope this wl useful for others
- (void)viewDidLoad {
arrCsv=[[NSArray alloc]initWithObjects:#"Hello",#"Hi",#"traun",#"fine",nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:#"%#/try.csv", documentsDirectory];
[[arrCsv componentsJoinedByString:#","] writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
-(ibAction)btnMail {
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *docDir = [arrayPaths objectAtIndex:0];
NSString *Path = [docDir stringByAppendingString:#"/CSVFile.csv"];
NSData *csvData = [NSData dataWithContentsOfFile:Path];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"For csv file..."];
[controller setMessageBody:#"...csv file is hear.." isHTML:NO];
[controller addAttachmentData:csvData mimeType:#"text/csv" fileName:#"CSVFile.csv"];
[self presentModalViewController:controller animated:YES];
[controller release];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{ message.hidden = NO;
switch (result)
{
case MFMailComposeResultCancelled:
message.text = #"Result: canceled";
break;
case MFMailComposeResultSaved:
message.text = #"Result: saved";
break;
case MFMailComposeResultSent:
message.text = #"Result: sent";
break;
case MFMailComposeResultFailed:
message.text = #"Result: failed";
break;
default:
message.text = #"Result: not sent";
break;
}
[self dismissModalViewControllerAnimated:YES];
}
set the mime type as "application/octet-stream" and that should do the trick to remove inline attachments (I still named the extension of my file i.e. pdf)
I believe the second parameter to setMessageBody:isHTML: must be YES for attachments to not show up inline.
Even if you set isHTML param to YES, your message body can be sent as plain/text if the message body can be represented as such. And attachments in plain/text messages are not always recognized correctly by some email clients (Outlook).
In my case adding a link in the message body helped. Formatting text as bold with HTML tags works too. Tricky!
Tested on iPod 1G 3.1.3.
This may not be the case here, but one thing to watch out for is that:
[NSString dataUsingEncoding:]
returns a valid but empty NSData object if the conversion to the specified encoding is not possible. Better to use the full version:
[NSString dataUsingEncoding: s allowLossyConversion: YES]
Or check the length of the returned data. It appears that zero-length data attachments are trimmed somewhere in the mail process.