title: objective c - HTML to NSAttributedString
body: <p>I have written a function that converts HTML text to <code>NSAttributedString</code>. It is working fine. However, I have noticed that some tags when nested inside another tag, their fonts get overwritten.</p>
  
  <p>Here's my code.</p>
  
  <pre><code>+(NSMutableAttributedString*) replaceHTMLTags : (NSString*) text : (NSString*) fontName : (CGFloat) fontSize
  {
      UIFont* font = [UIFont fontWithName:fontName size:fontSize];
      NSMutableParagraphStyle* paragraphStyle = [[NSMutableParagraphStyle alloc]init];
      paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
      paragraphStyle.alignment = NSTextAlignmentJustified;
  
      text = [text stringByReplacingOccurrencesOfString:@"&lt;br&gt;" withString:@"\n"];
      NSMutableAttributedString* finalText = [[NSMutableAttributedString alloc]initWithString:text];
  
      [finalText setAttributes:@{NSFontAttributeName:font} range:NSMakeRange(0, [finalText string].length)];
  
      finalText = [self recurseFunc:finalText :@"" : font : paragraphStyle];
      return finalText;
  }
  
  +(NSMutableAttributedString*) recurseFunc : (NSMutableAttributedString*) text : (NSString*) tag : (UIFont*) font : (NSMutableParagraphStyle*) paragraphStyle
  {
      NSMutableAttributedString* finalText = text;
  
      NSRange newOpenTagRange;
      //RECURSE IF THERE ARE MORE TAGS
      while((newOpenTagRange = [[text string] rangeOfString:@"&lt;[^&gt;]+&gt;" options:NSRegularExpressionSearch]).location != NSNotFound)
      {
          NSString* openTagName = [[text string] substringWithRange:newOpenTagRange];
          NSString* closeTagName = [self getCloseTagName: openTagName];
          NSRange newCloseTagRange = [[text string ]rangeOfString:closeTagName];
  
          if(newCloseTagRange.location != NSNotFound)
          {
              NSString* textWithTags = [[text string] substringWithRange:NSMakeRange(newOpenTagRange.location, newCloseTagRange.location - newOpenTagRange.location + newCloseTagRange.length)];
              NSString* newPlainText = [textWithTags stringByReplacingOccurrencesOfString:openTagName withString:@""];
              newPlainText = [newPlainText stringByReplacingOccurrencesOfString:closeTagName withString:@""];
  
              NSMutableAttributedString* newText = [[NSMutableAttributedString alloc]initWithString:newPlainText attributes:@{NSFontAttributeName:font,  NSParagraphStyleAttributeName:paragraphStyle}];
  
              newText = [self recurseFunc:newText :openTagName : font : paragraphStyle];
              [finalText replaceCharactersInRange:NSMakeRange(newOpenTagRange.location, newCloseTagRange.location - newOpenTagRange.location + newCloseTagRange.length) withAttributedString:newText];
          }
          else
          {
              NSLog(@"Cannot find closing tag for tag %@", openTagName);
          }
      }
  
      //FORMAT HTML TAGS
      if([tag containsString:@"&lt;p"])
      {
          [finalText.mutableString appendString:@"\n\n"];
      }
  
      else if ([tag isEqualToString:@"&lt;i&gt;"])
      {
          UIFont* italicFont = [UIFont fontWithName:@"Arial-ItalicMT" size:DEFAULT_FONT_SIZE];
          [finalText addAttribute:NSFontAttributeName value:italicFont range:NSMakeRange(0, [finalText string].length)];
      }
      else if ([tag isEqualToString:@"&lt;b&gt;"])
      {
          UIFont* boldFont = [UIFont fontWithName:@"Arial-BoldMT" size:DEFAULT_FONT_SIZE];
          [finalText addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(0, [finalText string].length)];
  
      }
      else if([tag isEqualToString:@"&lt;ul&gt;"])
      {
          NSMutableParagraphStyle* tempStyle = [[NSMutableParagraphStyle alloc]init];
          tempStyle.headIndent = 30;
          tempStyle.firstLineHeadIndent = 10;
          tempStyle.lineBreakMode = NSLineBreakByWordWrapping;
          tempStyle.alignment = NSTextAlignmentJustified;
  
          NSString* temp = [[finalText string]stringByReplacingOccurrencesOfString:@"###" withString:@"•\t"];
          temp = [NSString stringWithFormat:@"\n%@", temp];
          [finalText setAttributedString:[[NSAttributedString alloc] initWithString:temp]];
  
          [finalText addAttribute:NSParagraphStyleAttributeName value:tempStyle range:NSMakeRange(0, [finalText string].length)];
  
  
      }
      else if ([tag isEqualToString:@"&lt;li&gt;"])
      {
          NSMutableAttributedString* tempAS = [[NSMutableAttributedString alloc]initWithString:@"###$$$\n"];
          NSRange r = [[tempAS string]rangeOfString:@"$$$"];
          [tempAS replaceCharactersInRange:r withAttributedString:finalText];
          [finalText setAttributedString:tempAS];
  
      }
      return finalText;
  }
  </code></pre>
  
  <p>This does exactly what it is supposed to do, except for one specific case.</p>
  
  <p>For instance, if I have a <code>&lt;b&gt;</code> or an <code>&lt;i&gt;</code> tag inside a <code>&lt;ul&gt;&lt;li&gt;</code> tag, the <code>&lt;b&gt;</code> or <code>&lt;i&gt;</code> don't get rendered.</p>