title: Parsing NSAttributedString to HTML on iOS 7
body: <p>I have an <code>NSAttributedString</code>  (coming from HTML) that I set for a <code>UITextView</code>. </p>
  
  <pre><code>- (void)setHtml:(NSString *)html {
  
      NSData *htmlData = [html dataUsingEncoding:NSUTF8StringEncoding];
  
      // Create the HTML string
      NSDictionary *importParams = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
      NSError *error = nil;
      self.htmlString = [[NSAttributedString alloc] initWithData:htmlData options:importParams documentAttributes:NULL error:&amp;error];
  
      self.editorView.attributedText = self.htmlString;
  
  }
  </code></pre>
  
  <p>I then let the user edit what they want, and I would like to then convert it out to HTML again, so I use an edited version of <a href="https://github.com/uliwitness/UliKit/blob/master/NSAttributedString+HTMLFromRange.m" rel="nofollow noreferrer">ULIKit htmlFromRange:</a>. Here is the relevant method from that:</p>
  
  <pre><code>-(NSString*)    HTMLFromRange: (NSRange)range
  {
      unsigned int                location = 0;
      NSRange                     effRange;
      NSMutableString*            str = [NSMutableString string];
      NSMutableString*            endStr = [NSMutableString string];
      NSDictionary*               attrs = nil;
      NSDictionary*               oldAttrs = nil;
  
      unsigned int    finalLen = range.location +range.length;
  
      // TODO: Use oldAttrs, add NSForegroundColorAttributeName and
  
      attrs = [self attributesAtIndex: location effectiveRange: &amp;effRange];
      location = effRange.location +effRange.length;
  
      NSLog(@"attributed string: %@", self);
  
      // Font/color changed?
      UIFont* fnt = [attrs objectForKey: NSFontAttributeName];
      UIColor* tcol = [attrs objectForKey: NSForegroundColorAttributeName];
      if( fnt || tcol )
      {
          [str appendString: @"&lt;font"];
          if( tcol )
          {
              [str appendFormat: @" color=\"%@\"", ColorToHTMLColor(tcol)];
          }
          [str appendString: @"&gt;"];
          [endStr insertString: @"&lt;/font&gt;" atIndex: 0];
  
          UIFontDescriptor *fontDescriptor = [fnt fontDescriptor];
          if( (fontDescriptor.symbolicTraits &amp; UIFontDescriptorTraitItalic) == UIFontDescriptorTraitItalic )
          {
                  [str appendString: @"&lt;i&gt;"];
                  [endStr insertString: @"&lt;/i&gt;" atIndex: 0];
          }
          if( (fontDescriptor.symbolicTraits &amp; UIFontDescriptorTraitBold) == UIFontDescriptorTraitBold)
          {
              [str appendString: @"&lt;b&gt;"];
              [endStr insertString: @"&lt;/b&gt;" atIndex: 0];
          }
      }
  
      //Underline
      NSNumber *underline = [attrs objectForKey:NSUnderlineStyleAttributeName];
      if(underline &amp;&amp; [underline intValue] &gt; 0) {
          [str appendString:@"&lt;u&gt;"];
          [endStr insertString:@"&lt;/u&gt;" atIndex:0];
      }
  
      // Superscript changed?
      NSNumber* supers = [attrs objectForKey: (NSString*)kCTSuperscriptAttributeName];
      if( supers &amp;&amp; supers != [oldAttrs objectForKey: (NSString*)kCTSuperscriptAttributeName] )
      {
  
          [str appendString: [supers intValue] &gt; 0 ? @"&lt;sup&gt;" : @"&lt;sub&gt;"];
          [endStr insertString: [supers intValue] &gt; 0 ? @"&lt;/sup&gt;" : @"&lt;/sub&gt;" atIndex: 0];
      }
  
      // Actual text and closing tags:
      [str appendString: [[[self string] substringWithRange:effRange] stringByInsertingHTMLEntitiesAndLineBreaks: YES]];
      [str appendString: endStr];
  
      while( location &lt; finalLen )
      {
          [endStr setString: @""];
          attrs = [self attributesAtIndex: location effectiveRange: &amp;effRange];
          location = effRange.location +effRange.length;
  
          // Font/color changed?
          UIFont* fnt = [attrs objectForKey: NSFontAttributeName];
          UIColor* tcol = [attrs objectForKey: NSForegroundColorAttributeName];
          if( fnt || tcol )
          {
              [str appendString: @"&lt;font"];
              if( tcol )
              {
                  [str appendFormat: @" color=\"%@\"", ColorToHTMLColor(tcol)];
              }
              [str appendString: @"&gt;"];
              [endStr insertString: @"&lt;/font&gt;" atIndex: 0];
  
              UIFontDescriptor *fontDescriptor = [fnt fontDescriptor];
              if( (fontDescriptor.symbolicTraits &amp; UIFontDescriptorTraitItalic) == UIFontDescriptorTraitItalic )
              {
                      [str appendString: @"&lt;i&gt;"];
                      [endStr insertString: @"&lt;/i&gt;" atIndex: 0];
              }
              if( (fontDescriptor.symbolicTraits &amp; UIFontDescriptorTraitBold) == UIFontDescriptorTraitBold )
              {
                  [str appendString: @"&lt;b&gt;"];
                  [endStr insertString: @"&lt;/b&gt;" atIndex: 0];
              }
          }
  
          //Underline
          NSNumber *underline = [attrs objectForKey:NSUnderlineStyleAttributeName];
          if(underline &amp;&amp; [underline intValue] &gt; 0) {
              [str appendString:@"&lt;u&gt;"];
              [endStr insertString:@"&lt;/u&gt;" atIndex:0];
          }
  
          // Superscript changed?
          NSNumber* supers = [attrs objectForKey: (NSString*)kCTSuperscriptAttributeName];
          if( supers &amp;&amp; supers != [oldAttrs objectForKey: (NSString*)kCTSuperscriptAttributeName] )
          {
  
              [str appendString: [supers intValue] &gt; 0 ? @"&lt;sup&gt;" : @"&lt;sub&gt;"];
              [endStr insertString: [supers intValue] &gt; 0 ? @"&lt;/sup&gt;" : @"&lt;/sub&gt;" atIndex: 0];
          }
  
  
          ///Lists.
  
          // Actual text and closing tags:
          [str appendString: [[[self string] substringWithRange:effRange] stringByInsertingHTMLEntitiesAndLineBreaks: YES]];
          [str appendString: endStr];
      }
  
      return str;
  }
  </code></pre>
  
  <p>The problem comes from lists. Specifically the <code>NSAttributedString</code> method to parse from HTML parses lists ( and  tags) into NSTextLists from what I can see in logs.  <code>NSTextList</code> is private in UIKit.  Is there a way to parse that back into a list without using apple's default parser (by adding to my htmlFromRange method above)? (See this question:  <a href="https://stackoverflow.com/questions/20309606/ios-nsattributedstring-to-html">from Nic Hubbard</a>).  </p>
  
  <p>I understand how if the user CREATES a list in my textview to use a custom attribute to fake a NSTextList and then I can easily parse that into html, but can't figure out a way to get that going with a pre-made <code>NSAttributedString</code>.</p>
  
  <p>Thanks. (I will note I put a bounty on the Nic Hubbard question that is very related if you want to answer in both places. ) </p>