Android Html解析

       在前一篇 Android SpannableString浅析中我们采用html实现了文本处理的效果。当时设置部分的代码如下:

private void setText() {
    String originText = "#重磅消息#近日谷歌放出Android N的第二个开发者预览版(Developer Preview)";

    String effect1 = "<font color='#FF0000'>#重磅消息#</font> <br> 近日谷歌放出Android " +
            "N的第二个开发者预览版<a href='http://developer.android.com/index.html'>(Developer Preview)</a>";

    String effect2 = "<font color='#303F9F'>#重磅消息#</font> 近日谷歌放出Android " +
            "N的第二个开发者预览版<a href='http://developer.android.com/index.html'>(Developer Preview)</a>";
    StringBuilder sb = new StringBuilder(originText);
    sb.append("<br><br><br><br>");
    sb.append(effect1);
    sb.append("<br><br><br><br>");
    sb.append(effect2);
    textView.setText(Html.fromHtml(sb.toString()));
    textView.setMovementMethod(LinkMovementMethod.getInstance());
}

       这里我们改变了部分文字的显示颜色,同时对另外一部分内容添加了点击事件的处理,并且加入了下划线。今天我就来看看Html代码的解析。

解析过程

       在上面的代码中我们设置的时候调用了Html.fromHtml()函数,从这个函数就可以知道这个是将一段html内容解析成TextView可以展示的内容。我们就从这开始逐步看看该类做了哪些事情?能解析的内容是什么样的?

       在调用这个函数之前,我们首先看看Html的构造函数private Html() { },可以看到被private修饰,说明在外部不能构造Html实例,我们看到代码中也没有任何返回实例的地方,因此这里的使用方式都是采取静态方法调用。

       我们来看看fromHtml()函数:

public static Spanned fromHtml(String source) {
    return fromHtml(source, null, null);
}

public static Spanned fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler) {
    Parser parser = new Parser();
    try {
        parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
    } catch (org.xml.sax.SAXNotRecognizedException e) {
        // Should not happen.
        throw new RuntimeException(e);
    } catch (org.xml.sax.SAXNotSupportedException e) {
        // Should not happen.
        throw new RuntimeException(e);
    }

    HtmlToSpannedConverter converter =
        new HtmlToSpannedConverter(source, imageGetter, tagHandler, parser);
    return converter.convert();
}

       Html.fromHtml函数继续调用了三参数的romHtml(String source, ImageGetter imageGetter,TagHandler tagHandler),参数分别为数据源,图片处理,tag处理 。首先构造了一个Parser实例,Parser在org.ccil.cowan.tagsoup包下,我本地的代码是不能导航到的,这里给该代码的一个连接Parser源码

       这里我们额外说一下TagSoup,我们来看看他的官方介绍:

This is the home page of TagSoup, a SAX-compliant parser written in Java that, instead of parsing well-formed or valid XML, parses HTML as it is found in the wild: poor, nasty and brutish, though quite often far from short. TagSoup is designed for people who have to process this stuff using some semblance of a rational application design. By providing a SAX interface, it allows standard XML tools to be applied to even the worst HTML. TagSoup also includes a command-line processor that reads HTML files and can generate either clean HTML or well-formed XML that is a close approximation to XHTML.

       对应大致的意思就是:

TagSoup是Java语言编写一个解析Html的工具,他通过SAX引擎解析结构糟糕、令人抓狂的不规范HTML文档。TagSoup可以将一个HTML文档转换为结构良好的XML文档,方便开发人员对获取的HTML文档进行解析等操作。同时TagSoup提供了命令行程序,可以运行TagSoup来对HTML文档进行解析。

       构造了Parser后调用了Parser.setProperty函数,传入了schemaProperty,这里是一个字符串,还传入了HTMLSchema对象,HTMLSchema对象罗列了HTML的所有属性节点,HTMLSchema也属于TagSoup,这里不对TagSoup做过多的介绍,知道他是干什么的就好了。

       最后构造了一个HtmlToSpannedConverter实例,传入了上面传递进来的参数,数据源,imageGetter, tagHandler, parser,最后调用了HtmlToSpannedConverter的 convert函数。这里我们看这个类名就能大致知道该类做了什么操作,主要是将Html内容转换为Span对象。这里就又回到了前一篇的内容,最终处理的都是Span类型。

       这里我们先看看HtmlToSpannedConverter的构造函数都干了什么?

public HtmlToSpannedConverter(String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler,
        Parser parser) {
    mSource = source;
    mSpannableStringBuilder = new SpannableStringBuilder();
    mImageGetter = imageGetter;
    mTagHandler = tagHandler;
    mReader = parser;
}

       可以看到将传入的参数赋值给对应的变量,同时构造了一个SpannableStringBuilder对象,该对象与StringBuilder类型,StringBuilder主要是连接字符串,减少不必要的空间浪费,SpannableStringBuilder当然就是连接SpannableString,SpannableString的主要内容看前一篇 Android SpannableString浅析,我们继续看看convert函数干了什么?

public Spanned convert() {
    mReader.setContentHandler(this);
    try {
        mReader.parse(new InputSource(new StringReader(mSource)));
    } catch (IOException e) {
        // We are reading from a string. There should not be IO problems.
        throw new RuntimeException(e);
    } catch (SAXException e) {
        // TagSoup doesn't throw parse exceptions.
        throw new RuntimeException(e);
    }

    // Fix flags and range for paragraph-type markup.
    Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class);
    for (int i = 0; i < obj.length; i++) {
        int start = mSpannableStringBuilder.getSpanStart(obj[i]);
        int end = mSpannableStringBuilder.getSpanEnd(obj[i]);

        // If the last line of the range is blank, back off by one.
        if (end - 2 >= 0) {
            if (mSpannableStringBuilder.charAt(end - 1) == '\n' &&
                mSpannableStringBuilder.charAt(end - 2) == '\n') {
                end--;
            }
        }

        if (end == start) {
            mSpannableStringBuilder.removeSpan(obj[i]);
        } else {
          
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值