Generate HTML file from NSAttributedString - html

Recently, I come into a problem in my project. I need convert NSAttributedString to HTML file. The solution Click here doesn't work for me because want to output the HTML file only with TagName and idName and ClassName, at the same time, output the CSS style file to control how the HTML file will display.
Here is my sample code, I wish you can get my intend:
- (NSDictionary *)html
{
NSTextStorage *textStorage = [self contents];
NSArray *arr = [textStorage paragraphs];
// Initialize the CSS dictionay
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
nil];
NSEnumerator *paragraphEnumerator;
paragraphEnumerator = [arr objectEnumerator];
NSAttributedString *paragraph;
NSMutableArray *paragrapHTMLStrings = [[NSMutableArray alloc] initWithCapacity:[arr count]];
NSMutableString *cssString = [[NSMutableString alloc] initWithCapacity:0];
[cssString appendString:#"div{"];
[cssString appendString:[NSString stringWithFormat:#"-webkit-column-count:%ld;", self.columnCount]];
[cssString appendString:[NSString stringWithFormat:#"width:%fpx;", self.bounds.size.width]];
[cssString appendString:[NSString stringWithFormat:#"height:%fpx;", self.bounds.size.height]];
[cssString appendString:#"}"];
[dict setObject:cssString forKey:#"css"];
while (paragraph = [paragraphEnumerator nextObject]) {
// initialize
NSUInteger length;
NSRange effectiveRange = NSMakeRange(0, 0);
id attributeValue;
length = [paragraph length];
// get the font attributes
attributeValue = [paragraph attribute:NSFontAttributeName atIndex:NSMaxRange(effectiveRange) effectiveRange:&effectiveRange];
NSLog(#"font is %#", [attributeValue fontName]);
NSLog(#"font-size is %f", [[[attributeValue fontDescriptor] objectForKey:NSFontSizeAttribute] floatValue]);
NSMutableString *htmlString = [NSMutableString stringWithFormat:#"", [attributeValue fontName],
[[[attributeValue fontDescriptor] objectForKey:NSFontSizeAttribute] floatValue]];
[htmlString appendString:[paragraph string]];
[htmlString appendString:#""];
NSLog(#"htmlString is %#", htmlString);
[paragrapHTMLStrings addObject:htmlString];
htmlString = nil;
}
NSMutableString *htmlStringOfGraphToReturn = [NSMutableString stringWithString:#""];
NSString *stringToAdd;
NSEnumerator *stringEnumerator;
stringEnumerator = [paragrapHTMLStrings objectEnumerator];
while (stringToAdd = [stringEnumerator nextObject])
{
[htmlStringOfGraphToReturn appendString:stringToAdd];
}
[htmlStringOfGraphToReturn appendString:#""];
[dict setObject:htmlStringOfGraphToReturn forKey:#"html"];
// test part
CSSSetGenerator *generater = [[CSSSetGenerator alloc] init];
NSMutableString *string = [generater outputCSSStyleContent:self];
NSLog(#"%#", string);
return dict;
}

I got the solution from Github, There's an open project named DTCoreText. I hope this might be useful for someone.

Related

How to save bold font using html in objective c?

I've typed some text in uitextview and also I've select some text and make it bold.After that I'm going to save this data into my application.Now,When I'm going to fetch that data then it will not displaying same as I've saved.
Its not save bold font.
Below is the code :
pragma mark - btnActions
-(IBAction)btnActions:(UIButton *)sender
{
[self addOrRemoveFontTraitWithName:#"Bold" andValue:UIFontDescriptorTraitBold];
}
pragma mark - Private method implementation
-(void)addOrRemoveFontTraitWithName:(NSString *)traitName andValue:(uint32_t)traitValue{
NSRange selectedRange = [txtViewNote selectedRange];
NSDictionary *currentAttributesDict = [txtViewNote.textStorage attributesAtIndex:selectedRange.location
effectiveRange:nil];
UIFont *currentFont = [currentAttributesDict objectForKey:NSFontAttributeName];
UIFontDescriptor *fontDescriptor = [currentFont fontDescriptor];
NSString *fontNameAttribute = [[fontDescriptor fontAttributes] objectForKey:UIFontDescriptorNameAttribute];
UIFontDescriptor *changedFontDescriptor;
if ([fontNameAttribute rangeOfString:traitName].location == NSNotFound) {
uint32_t existingTraitsWithNewTrait = [fontDescriptor symbolicTraits] | traitValue;
changedFontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithNewTrait];
}
else{
uint32_t existingTraitsWithoutTrait = [fontDescriptor symbolicTraits] & ~traitValue;
changedFontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithoutTrait];
}
UIFont *updatedFont = [UIFont fontWithDescriptor:changedFontDescriptor size:0.0];
NSDictionary *dict = #{NSFontAttributeName: updatedFont};
[txtViewNote.textStorage beginEditing];
[txtViewNote.textStorage setAttributes:dict range:selectedRange];
[txtViewNote.textStorage endEditing];
}
pragma mark - btnSave
-(IBAction)btnSave:(id)sender
{
NSURL *documentDirectoryURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *documentURL = [documentDirectoryURL URLByAppendingPathComponent:#"test.html"];
NSString *htmlCode = txtViewNote.text;
NSError* error;
if (![htmlCode writeToURL:documentURL atomically:YES encoding:NSUTF8StringEncoding error:&error]) {
NSLog(#"Couldn't save file because: %#", error);
}
NSString* fileToUpload = [NSString stringWithContentsOfURL:documentURL encoding:NSUTF8StringEncoding error:&error];
if (!fileToUpload) {
NSLog(#"Couldn't read file because: %#", error);
}
}
can any one html me?
The problem is you are saving the plain text of the textView instead of the attributedText.
NSString *htmlCode = txtViewNote.text;
Instead you should save the attributed text like this:
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:NSHTMLTextDocumentType,NSDocumentTypeDocumentAttribute, nil];
NSData *htmlData = [[self txtViewNote].attributedText dataFromRange:NSMakeRange(0, [self txtViewNote].attributedText.length) documentAttributes:attributes error:NULL];
NSString *htmlCode = [[NSString alloc]initWithData:htmlData encoding:NSUTF8StringEncoding];
If you want to write the htmlCode to the textView, you should:
NSMutableAttributedString *tmp = [[NSMutableAttributedString alloc] initWithData:htmlData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)} documentAttributes:nil error:nil];
[txtViewNote setAttributedText:tmp];

IOS Regular parse HTML

i want to parse html content into Dictionary
EDIT:
I need to parse just simple HTML, don't need to consider the complex situation.
WEB side: when I was in the system input information, using the HTML editor. But fix the old WEB system , need to modify the place more, so temporary use parsing HTML mode in the current version of the APP。
END:
Html just like this:
<p>hahaha</p><img src="aaaa.jpg"/>heihei<img src="bbb.jpg"/>guagua
i want the result is:
text hahaha
img aaaa.jpg
text heihei
img bbb.jpg
text guagua
my code is:
//<p>hahaha</p><img src="aaaa.jpg"/>heihei<img src="bbb.jpg"/>guagua
//for this
//NSArray = {0,1,2,3,4}
//NSDictionary{Sort-Key,V}={{0,{text,hahaha}},{1,{img,aaaa.jpg}},{2,{text,heihei}},{3, {img,bbb.jpg}},{4,{text,guagua}}}
-(NSArray*)RegularExpression:(NSString *)str dic:(NSMutableDictionary**)dic
{
if(str == nil) return nil;
NSString *pgnText = str;
NSString* tags=#"<[p|div].*?>(.*?)</[p|div].*?>";
NSString *regTags = tags;
NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regTags options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *matches = [regex matchesInString:pgnText
options:0
range:NSMakeRange(0, [pgnText length])];
NSMutableArray* arrItems = [[NSMutableArray alloc] initWithCapacity:[matches count]];
if(matches.count >0){
for (NSTextCheckingResult *match in matches) {
NSString *tagValue = [pgnText substringWithRange:[match rangeAtIndex:1]];
NSArray* arr = [self RegularExpression:tagValue dic:dic];
[arrItems addObjectsFromArray:arr];
}
}
else{
NSString* regTags2 = #".*?<img.*?src.*?=.*?[\"|”](.*?)[\"|”].*?/>";
NSRegularExpression *regex2 = [NSRegularExpression regularExpressionWithPattern:regTags2 options:NSRegularExpressionCaseInsensitive|NSRegularExpressionAnchorsMatchLines error:&error];
pgnText = str;
NSArray *matches2 = [regex2 matchesInString:pgnText
options:0
range:NSMakeRange(0, [pgnText length])];
for (NSTextCheckingResult *match in matches2) {
NSString *tagValue = [pgnText substringWithRange:[match rangeAtIndex:1]];
NSLog(#"%#",tagValue);
}
}
return [arrItems autorelease];
}
Who has done similar function?
Keys in a dictionary must be unique. You cannot have more than one "img" key.
Check out this SO question: Objective-C DOM XML parser for iPhone

Parsed results in UITableView

I am using HTMLParser by Ben Reeves. It works great but the only problem is that I couldn't put the output in UITableView. Anyone can tell me what's wrong with this code? ...................................................................................
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSError *error = nil;
NSURL *url=[[NSURL alloc] initWithString:#"http://website.com/"];
NSString *strin=[[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
HTMLParser *parser = [[HTMLParser alloc] initWithString:strin error:&error];
if (error) {
NSLog(#"Error: %#", error);
return;
}
HTMLNode *bodyNode = [parser body];
NSArray *divNodes = [bodyNode findChildTags:#"div"];
for (HTMLNode *inputNode in divNodes) {
if ([[inputNode getAttributeNamed:#"class"] isEqualToString:#"views-field-title"]) {
NSLog(#"%#", [inputNode allContents]);
listData = [[NSArray alloc] initWithObjects:[inputNode allContents], nil];
}
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
#end
You're reinitializing your array every time you find a new element. I think you need to move
listData = [[NSArray alloc] initWithObjects:[inputNode allContents], nil];
outside of your loop and change it to
listData = [[NSMutableArray alloc] init];
listData should be an NSMutableArray so you can add data to it. You'll need to change this in your variable definition too.
Then inside your loop, use [listData addObject:[inputNode allContents]];

Parsing Html url in iphone

How do I parse an html file?
I need the data in between span tag.
<div id=currency_converter_result>1 AED = <span class=bld>0.4765 ANG</span>
If you need only tag 'span' you can use NSRegularExpression such as this one
NSString *html = #"<div id=currency_converter_result>1 AED = <span class=bld>0.4765 ANG</span>";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"<span[^>]*>(.+?)</span>"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSTextCheckingResult *textCheckingResult = [regex firstMatchInString:html options:0 range:NSMakeRange(0, html.length)];
NSLog(#"found: '%#'", [html substringWithRange:[textCheckingResult rangeAtIndex:1]]);
or, I prefer to create a NSDictionary from xml or html data and work with it. You can do it with XML-to-NSDictionary library.
Check out this:
https://github.com/zootreeves/Objective-C-HMTL-Parser
Basic Usage :
NSError *error = nil;
NSString *htmlString =
#"<div id=currency_converter_result>1 AED = <span class=bld>0.4765 ANG</span>";
HTMLParser *p = [[HTMLParser alloc] initWithString:htmlString error:&error];
if (error) {
NSLog(#"Error: %#", error);
return;
}
HTMLNode *bodyNode = [p body];
NSArray *spanNodes = [bodyNode findChildTags:#"span"];
for (HTMLNode *spanNode in spanNodes) {
if ([[spanNode getAttributeNamed:#"class"] isEqualToString:#"bld"]) {
NSLog(#"%#", [spanNode rawContents]); //Answer to second question
}
}
Since XHTML is XML, you can consider using NSXMLParser:
#interface HTMLParser: NSObject <NSXMLParserDelegate> // or whichever superclass you have
{
// own declarations
NSMutableString *str;
NSXMLParser *parser;
}
// somewhere in a method of self, for example, init, or something named -(void) parseHtml
- (void) parseHtml
{
parser = [[NSXMLParser alloc] initWithData:[#"<div id=currency_converter_result>1 AED = <span class=bld>0.4765 ANG</span>" dataUsingEncoding:NSUTF8StringEncoding]];
// of course you can substitute any string you want here, for example, the result of [NSString stringWithContentsOfFile:#"inex.html"] or whatever you need.
parser.delegate = self;
[parser parse];
[parser release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"span"] && [[attributeDict objectForKey:#"class"] isEqualToString:#"bld"])
{
str = [NSMutableString string];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[str appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"span"])
{
// now str contains the value you want!
DoSomethingWith(str);
}
}
Hope this helps.

Trouble on parsing JSON and displaying it on UITableView

I have this url: http://maps.google.com.br/maps/api/directions/json?origin=porto+alegre&destination=novo+hamburgo&sensor=false
And this code:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSMutableDictionary *theDictionary = [responseString JSONValue];
NSLog(#"%#", theDictionary);
[responseString release];
if (theDictionary != nil)
{
NSArray *routesArray = [theDictionary objectForKey:#"routes"];
NSDictionary *firstRoute = [routesArray objectAtIndex:0];
NSArray *legsArray = [firstRoute objectForKey:#"legs"];
NSDictionary *firstLeg = [legsArray objectAtIndex:0];
steps = [firstLeg objectForKey:#"steps"];
}
[tableView reloadData];
}
I want to display every single #"html_instructions" on a uitableview.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.steps count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cachedCell"];
if (cell == nil)
cell = [[[UITableViewCell alloc]
initWithFrame:CGRectZero reuseIdentifier:#"cachedCell"] autorelease];
return cell;
}
What's missing in my code??? Should be some little detail... any help would be GREAT!
I would do it like this:
Create url request with your url
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
[request setURL:[NSURL URLWithString:#"http://maps.google.com.br/maps/api/directions/json?origin=porto+alegre&destination=novo+hamburgo&sensor=false"]];
then create NSData structure, that holds response to the request and I converted it to string
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; //Or async request
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
After that, you load JSON into Dictionary, then to move one level down, pass it to another dictionary (result 1)
NSError *error=nil;
result = [NSJSONSerialization JSONObjectWithData:returnData options:kNilOptions error:&error];
result1 = [result objectForKey:#"routes"];
result2 = [result1 objectForKey:#"legs"];
Then move it into NSMutableArray
jsonMutArray= [result2 objectForKey:#"steps"];
From there, you just put label into your custom cell attach it as a IBOutlet, synthetize and do in cellForRowAtIndexPath method
cell.yourLabel.text = [jsonMutArray objectForKey:#"html_instructions"];
However, keep in mind, that I'm just begginer, so this might not be the most effective way of doing it :) Good Luck!
Don't you need to be doing something like this in your CellForRowAtIndexPath ?
NSString *cellValue = **WHATEVER VALUE YOU WANT TO PUT IN**;
cell.textLabel.text = cellValue;
return cell;
I don't see you adding your data to the cell.