HTML from NSAttributedString - html

Rather than converting HTML to an attributed string, I need to convert it back to HTML. This can easily be done on Mac as can be seen here: http://www.justria.com/2011/01/18/how-to-convert-nsattributedstring-to-html-markup/
Unfortuately, the method dataFromRange:documentAttributes: is only available on Mac via the NSAttributedString AppKit Additions.
My question is how can you do this on iOS?

Not the 'easy' way, but what about iterating through the attributes of the string using:
- (void)enumerateAttributesInRange:(NSRange)enumerationRange
options:(NSAttributedStringEnumerationOptions)opts
usingBlock:(void (^)(NSDictionary *attrs, NSRange range, BOOL *stop))block
Have an NSMutableString variable to accumulate the HTML (lets call it 'html'). In the block, you would construct the HTML manually using strings. For instance if the text attributes 'attrs' specify red, bold text:
[html appendFormat:#"<span style='color:red; font-weight: bold;'>%#</span>", [originalStr substringWithRange:range]]
EDIT: Stumbled across this yesterday:
NSAttributedString+HTMLFromRange category from "UliKit"
(https://github.com/uliwitness/UliKit/blob/master/NSAttributedString+HTMLFromRange.m)
Looks like it will do what you want.

Use the below code. it works well.
NSAttributedString *s = ...;
NSDictionary *documentAttributes = #{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSData *htmlData = [s dataFromRange:NSMakeRange(0, s.length) documentAttributes:documentAttributes error:NULL];
NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];

Related

How to centre a HTML string both horizontally and vertically in a UIWebView

I get HTML string in UTF-8 Format and I need to display it in a webView. But I want the string to be centred both horizontally as well as vertically in the UIWebView
Well I tested and worked out a working solution. Well here is how I achieved the desired output. Well the function calculateHeight is written by me. I came across different solutions but none of them gave the desired solution for vertical centring. The method calculateHeight returns the total height of the NSAttributedString which would be generated on converting the HTML text to NSAttributedString. This height value is further used to centre the text vertically by providing the required padding.
//subCatTexts.text contains the HTML String
NSString *myHTML = [NSString stringWithFormat:#"<!DOCTYPE html><html><head><style>.center
{padding: %fpx 0;border: 0px solid green;text-align: center;}</style></head><body><div class=\"center\"><p>%#</p></div></body>
</html>",self.webView.frame.size.height/2.0-[self calculateHeight:subCatTexts.text],subCatTexts.text];
[_webView loadHTMLString:myHTML baseURL:nil];
The function used is defined here
- (float) calculateHeight:( NSString *)html
{
const char *c = [html cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:c length:strlen(c)];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc]
initWithData: [string dataUsingEncoding:NSUnicodeStringEncoding]
options: #{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
documentAttributes: nil
error: nil
];
//-------------Calculating the height of the attributed String-----
CGFloat width = self.view.frame.size.width; // whatever your desired width is
CGRect rect = [attributedString boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
return (rect.size.height);
}

How to apply bold for string in html format in iOS?

I want to print text in bold using string that prints in compose mail from my app
messageBody = [NSString stringWithFormat:#"<b>Background Information</b>"];
What you could do is use an NSAttributedString.
NSString *boldFontName = [[UIFont boldSystemFontOfSize:12] fontName];
NSString *yourString = ...;
NSRange boldedRange = NSMakeRange(22, 4);
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:yourString];
[attrString beginEditing];
[attrString addAttribute:kCTFontAttributeName
value:boldFontName
range:boldedRange];
[attrString endEditing];
//draw attrString here...
or
use this code
you do not want to bother with fonts (as not every variation of font contains "Bold"), here is another way to do this:
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:"Approximate Distance: 120m away"];
[attrString beginEditing];
[attrString applyFontTraits:NSBoldFontMask
range:NSMakeRange(22, 4)];
[attrString endEditing];
NSAttributedString sounds like the tool you need. In iOS 7, they added support to parse HTML strings with basic markup for styling into NSAttributedStrings. It's pretty easy:
NSMutableAttributedString *titleString = [[NSMutableAttributedString alloc] initWithData:[someHTMLString dataUsingEncoding:NSUTF8StringEncoding] options:#{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType} documentAttributes:NULL error:nil];
self.someLabel.attributedText = titleString;
If you want to add font styling, I found it's best to add a span with a font specified around the text before creating the NSMutableAttributedString.
NSString *styledTitle = [NSString stringWithFormat:#"<span style=\"font-family:'%#'; font-size:%dpx;\">%#</span>", someFont.fontName, (int)someFont.pointSize, someHTMLString];

How can I parse tables in HTML?

I'm trying to parse an HTML page with a lot of tables. I've searched the net on how to parse HTML with Objective C and I found hpple. I'd look for a tutorial which lead me to:
http://www.raywenderlich.com/14172/how-to-parse-html-on-ios
With this tutorial I tried to parse some forum news which has a lot of tables from this site (Hebrew): news forum
I tried to parse the news title, but I don't know what to write in my code. Every time I try to reach the path I get, "Nodes was nil."
The code of my latest attempt is:
NSURL *contributorsUrl = [NSURL URLWithString:#"http://rotter.net/cgi-bin/listforum.pl"];
NSData *contributorsHtmlData = [NSData dataWithContentsOfURL:contributorsUrl];
// 2
TFHpple *contributorsParser = [TFHpple hppleWithHTMLData:contributorsHtmlData];
// 3
NSString *contributorsXpathQueryString = #"//body/div/center/center/table[#cellspacing=0]/tbody/tr/td/table[#cellspacing=1]/tbody/tr[#bgcolor='#FDFDFD']/td[#align='right']/font[#class='text15bn']/font[#face='Arial']/a/b";
NSArray *contributorsNodes = [contributorsParser searchWithXPathQuery:contributorsXpathQueryString];
// 4
NSMutableArray *newContributors = [[NSMutableArray alloc] initWithCapacity:0];
for (TFHppleElement *element in contributorsNodes) {
// 5
Contributor *contributor = [[Contributor alloc] init];
[newContributors addObject:contributor];
// 6
Could somebody guide me through to getting the titles?
Not sure if that's the option for you, but if desired table have unique id's you could use a messy approach: load that html into UIWebView and get contents via – stringByEvaluatingJavaScriptFromString: like this:
// desired table container's id is "msg"
NSString* value = [webView stringByEvaluatingJavaScriptFromString:#"document.getElementById('msg').innerHTML"];

Getting the HTML tags in hpple as well as text?

The code below takes all of the text from a certain div. Is it possible for me to take all the text from the div as well as the html attributes? So it also adds all of the <p> </p>'s and <br> </br>'s to the string, myString?
//trims string from previous page
NSString *trimmedString = [stringy stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSData *data = [[NSString stringWithContentsOfURL:[NSURL URLWithString:trimmedString]] dataUsingEncoding:NSUTF8StringEncoding];
TFHpple *xpathParser = [[TFHpple alloc] initWithHTMLData:data];
NSArray *elements = [xpathParser searchWithXPathQuery:#"//div[#class='field-item even']"];
TFHppleElement *element = [elements lastObject]; //may need to change this number?!
NSString *mystring = [self getStringForTFHppleElement:element];
trimmedTextView.text = [trimmedTextView.text stringByAppendingString:mystring];
Method here:
-(NSString*) getStringForTFHppleElement:(TFHppleElement *)element
{
NSMutableString *result = [NSMutableString new];
// Iterate recursively through all children
for (TFHppleElement *child in [element children])
[result appendString:[self getStringForTFHppleElement:child]];
// Hpple creates a <text> node when it parses texts
if ([element.tagName isEqualToString:#"text"])
[result appendString:element.content];
return result;
}
Any ideas would be appreciated. Cheers.
Try this:
NSString *htmlDataString = [webView stringByEvaluatingJavaScriptFromString: #"document.documentElement.outerHTML"];
This will take all the HTML out to string. You can then parse it in your native code and find div which is your interest what you have did in above example.
You can do it as well with any DOM element in your HTML like:
NSString *htmlDataString = [webView stringByEvaluatingJavaScriptFromString: #"document.documentElement.getElemenById('mydiv')"];
which is more efficient but requires a bit of javascript skill.

iOS: Strip <img...> from NSString (a html string)

So I have an NSString which is basically an html string with all the usual html elements. The specific thing I would like to do is to just strip it from all the img tags.
The img tags may or may not have max-width, style or other attributes so I do not know their length up front. They always end with />
How could I do this?
EDIT: Based on nicolasthenoz's answer, I came up with a solution that requires less code:
NSString *HTMLTagss = #"<img[^>]*>"; //regex to remove img tag
NSString *stringWithoutImage = [htmlString stringByReplacingOccurrencesOfRegex:HTMLTagss withString:#""];
You can use the NSString method stringByReplacingOccurrencesOfString with the NSRegularExpressionSearch option:
NSString *result = [html stringByReplacingOccurrencesOfString:#"<img[^>]*>" withString:#"" options:NSCaseInsensitiveSearch | NSRegularExpressionSearch range:NSMakeRange(0, [html length])];
Or you can also use the replaceMatchesInString method of NSRegularExpression. Thus, assuming you have your html in a NSMutableString *html, you can:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"<img[^>]*>"
options:NSRegularExpressionCaseInsensitive
error:nil];
[regex replaceMatchesInString:html
options:0
range:NSMakeRange(0, html.length)
withTemplate:#""];
I'd personally lean towards one of these options over the stringByReplacingOccurrencesOfRegex method of RegexKitLite. There's no need to introduce a third-party library for something as simple as this unless there was some other compelling issue.
Use a regular expression, find the matchs in your string and remove them !
Here is how
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"<img[^>]*>"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSMutableString* mutableString = [yourStringToStripFrom mutableCopy];
NSInteger offset = 0; // keeps track of range changes in the string due to replacements.
for (NSTextCheckingResult* result in [regex matchesInString:yourStringToStripFrom
options:0
range:NSMakeRange(0, [yourStringToStripFrom length])]) {
NSRange resultRange = [result range];
resultRange.location += offset;
NSString* match = [regex replacementStringForResult:result
inString:mutableString
offset:offset
template:#"$0"];
// make the replacement
[mutableString replaceCharactersInRange:resultRange withString:#""];
// update the offset based on the replacement
offset += ([match length] - resultRange.length);
}
You can use below function in Swift 4,5:
func filterImgTag(text: String) -> String{
return text.replacingOccurrences(of: "<img[^>]*>", with: "", options: String.CompareOptions.regularExpression)
}
Hope it can help you all! comment below if it work for you. Thanks.