简体   繁体   中英

Android HtmlCompat.toHtml(Spanned) returns improperly nested HTML tags

I have an Edittext (binding.text using view binding) that contains text styled with StyleSpans, ie bold and italics. To save the formatted text, I use HtmlCompat.toHtml(spannable) in Kotlin to convert it into HTML.

var htmlString = HtmlCompat.toHtml(SpannableString(binding.text.text), HtmlCompat.FROM_HTML_MODE_LEGACY)

However, the HTML returned is improperly nested if the text has bold and italics applied to it at the same time.

  • Hello World : outputs <p dir="ltr><b><i>Hello world</b></i></p>

As you can see, the tags applied are <b><i> </b></i> instead of <b><i> </i></b> .


When the text is not formatted, or either in bold or italics, then proper HTML is returned:

  • Hello World: outputs <p dir="ltr>Hello world</p>
  • Hello World : outputs <p dir="ltr><b>Hello world</b></p>

I suppose the function likes to put <b> and </b> first as opposed to <i> and </i> , but this causes weird results as shown. So the question: How do I get the function to return correctly formatted HTML?

You are right about the ordering, although the HTML should still display correctly in a browser. The offending code is in Html.java . Here is where the translations occur for <b></b> and <i></i> :

...
for (int j = 0; j < style.length; j++) {    
    ...
    if (style[j] instanceof StyleSpan) {
        int s = ((StyleSpan) style[j]).getStyle();
    
        if ((s & Typeface.BOLD) != 0) {
            out.append("<b>");
        }
        if ((s & Typeface.ITALIC) != 0) {
            out.append("<i>");
        }
    }

...
for (int j = style.length - 1; j >= 0; j--) {
    ,,,
    if (style[j] instanceof StyleSpan) {
        int s = ((StyleSpan) style[j]).getStyle();
    
        if ((s & Typeface.BOLD) != 0) {
            out.append("</b>");
        }
        if ((s & Typeface.ITALIC) != 0) {
            out.append("</i>");
        }
    }

style is an array of spans. This code scans forward through the spans to place the opening tags and backward to close the tags. So, it looks like if your bold span and italic spans are different spans spanning the same text, then this code will produce properly nested tags.

However, if one StyleSpan specifies both italic and bold, then the tag order will be as you report <b><i></b></i> . The code that outputs the closing tags should place <i> before b . This looks like a bug and should be reported.

I assume that you have one StyleSpan that is a bolded-italics span. The fix would be to split that span into two separate spans - a bold span and an italics span. The code should then work as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM