使用 XmlPullParser (二)

上篇我们讲了 parser 的基本使用方式和一些前置的 function 实作,像是 parseChannelskip ,接下来我们就要来讲其他实用的取值方式。首先,我们可以拿到指定 tag 的 value ,我们需要写一个针对 XmlPullParser 来写一个 readString 的 extension function 。

@Throws(IOException::class, XmlPullParserException::class)
protected fun XmlPullParser.readString(tagName: String): String? {
	  require(XmlPullParser.START_TAG, null, tagName)
    var content: String? = null
    if (next() == XmlPullParser.TEXT) {
	    content = text
      nextTag()
      if (eventType != XmlPullParser.END_TAG) {
          skip()
          nextTag()
          content = null
      }
    }
    require(XmlPullParser.END_TAG, null, tagName)
    return content
}

我们可以取得指定 tagName 里的值,假设 tag 的名称叫做 title ,那代表的就是要拿 <title>title1</title> 里面的 title1 。在 function 的最前面和最後面,我们都要检查 event type 和现在的 tag 名称,这主要是要检查 RSS 的基本格式是不是正确的,因为有可能拿到的格式缺了前面的 <title> 或是後面的 </title> ,这都会导致我们後面的 parsing 结果不正确。在 function 的中间也要检查 event type 是否为 TEXT ,这样才是我们想要的值。

<enclosure length="24986239" type="audio/mpeg" url="http://item.enclosure.url/item.mp3" />

那如果我们是要拿 attribute 里面的值,像是上面范例的 lengthtypeurl 的话,可以怎麽做?其实他的思路跟 readString 有点像,但不需要额外爬一层 tag 。我们可以设计一个 function 让他可以拿取多个 attribute !

@Throws(IOException::class, XmlPullParserException::class)
protected fun XmlPullParser.readAttributes(
    tagName: String,
    attributes: List<String>,
    action: (String, String?) -> Unit
) {
    require(XmlPullParser.START_TAG, null, tagName)
    attributes.forEach { attr ->
        action(attr, getAttributeValue(null, attr))
    }
    nextTag()
    logD(logTag, "[readAttributes]: tag name = $tagName, attributes = $attributes")
    require(XmlPullParser.END_TAG, null, tagName)
}

可以看到 function 的参数里面有 attribute ,这个主要是让使用者指定要爬的 attribute 有哪些,像刚刚的 enclosure 里面我们就可以指定 tagName 是 enclosure ,attribute 是一个阵列,里面包含 lengthtypeurlaction 这个参数则是可以对爬到的值去做指定的动作,塞一个 lambda 进去就可以了!用法可以参考下面的程序码:

@Throws(IOException::class, XmlPullParserException::class)
protected fun XmlPullParser.readEnclosure(): Enclosure {
    var url: String? = null
    var length: Long? = null
    var type: String? = null
    readAttributes(ENCLOSURE, listOf(URL, LENGTH, TYPE)) { attr, value ->
        when (attr) {
            URL -> url = value
            LENGTH -> length = value?.toLongOrNull()
            TYPE -> type = value
        }
    }
    return Enclosure(url = url, length = length, type = type)
}

<<:  灵异现象 - 怎麽大家都能改阿

>>:  Flutter体验 Day 4-Dart CheatSheet (2)

【後转前要多久】# Day07 CSS - 打架该听谁的?CSS权重、继承

虽然这章节可能有些无聊,迟迟没进入CSS引人兴趣的地方, 但我还是想依我学习时,所想到和纳闷的事物按...

Day23 | Livewire 实作 购物网站(二): 建立商品细节页面

有了商品列表,那应该要能点进去看商品的细节吧。所以今天就是来做点进去後的商品细节页! 今日目标:商品...

从 IT 技术面细说 Search Console 的 27 组数字 KPI (5) 流量:新闻与探索

Search Console 并不是都是看到使用者主动搜寻的流量,其中探索 (Discover) 与...

Innodb资料页结构-Part1(使用者纪录、空闲空间、页面中最小与最大的纪录)

前文提到页是Innodb的基本存取单位,一般为16kb,Innodb为了实现功能其实设计了许多不同类...

Day30 - 导入 Next.js 的杂谈与系列文总结

尾声 最後一天想回归到第一天时对自己说的话「看完这些文章的读者能够对 Next.js 有更多的了解,...