iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0

上篇我們講了 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)
}

上一篇
使用 XmlPullParser (一)
下一篇
使用 XmlPullParser (三)
系列文
如何使用 Kotlin Annotation Processor 做出自己的 Custom Data Parser Library30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言