使用 XmlPullParser (三)

我们现在有了许多的基础的 parser function 了,我们直接来看怎麽样组合这些 function 来 parse 一些东西吧!以 library 里面的 Android parser 为例,我们的目标是拿到 RSS 2.0 标准格式里的 channel 资料。首先,我们先定义 channel 长的样子包在一个 data class 里面,而这个 data class 叫做 RssStandardChannelData ,完整的 data class 可以参考这个连结,这边就不把完整程序码贴上来了。Channel 里面又有包含一些资料,我们就可以定义在另一个 data class 里面,像是 category 、 item 和 cloud 等等。

接着,我们就可以来写 channel 的 parser function 。

@Throws(IOException::class, XmlPullParserException::class)
private fun XmlPullParser.readRssStandardChannel(): RssStandardChannelData {
    require(XmlPullParser.START_TAG, null, CHANNEL)

		// 1
    var title: String? = null
    var image: Image? = null
    val categories = mutableListOf<Category>()
    var cloud: Cloud? = null
    var textInput: TextInput? = null
    var skipHours: List<Int>? = null
    val items = mutableListOf<RssStandardItemData>()
		// 省略其他变数宣告

		// 2
    while (next() != XmlPullParser.END_TAG) {
        if (eventType != XmlPullParser.START_TAG) continue

				// 3
        when (name) {
            TITLE -> title = readString(TITLE)
            IMAGE -> image = readImage()
            CATEGORY -> categories.add(readCategory())
            CLOUD -> cloud = readCloud()
            TTL -> ttl = readString(TTL)?.toIntOrNull()
            RATING -> rating = readString(RATING)
            TEXT_INPUT -> textInput = readTextInput()
            SKIP_HOURS -> skipHours = readSkipHours()
            ITEM -> items.add(readRssStandardItem())
						// 省略其他处理
            else -> skip()
        }
    }
    require(XmlPullParser.END_TAG, null, CHANNEL)
		// 4
    return RssStandardChannelData(...)
}

在这个 function 里,我把他分成四个部分来讲解,分别对应上方程序码注解上的数字:

  1. 这边宣告一些 channel 里面有的变数,全部都是 nullable type ,因为实际的 XML 里面,不一定会包含每个值或属性。另外,在前几篇有提到 event-based 的机制本身不支援跨层去存取 tag ,所以这边我们把它们的值存在外面的变数,等到全部数值都处理完毕之後再放到 data class 里面回传。
  2. 把 channel tag 内的 event 一个一个拉出来。
  3. 按照 tag 的名称分别做对应的处理,如果是只有取单一值,可以用 readString 之後再转成想要的型别。如果 tag 还有另一个 tag ,可以再额外定义一个 data class 来代表该子 tag 。如果 tag 名称不在处理的范围,则可以呼叫 skip 去跳过该 tag 。在处理的过程中,有呼叫一些其他的 function ,像是 readCategory readTextInput readSkipHours 和 readRssStandardItem 等,它们内部处理的逻辑是和 readRssStandardChannel 相同,这些 function 可以在这边找到。
  4. 最後,把所有的变数收集起来放到 data class 里面去产出资料,这边因为变数太多,忽略了一些变数。完整版的程序码可以到这里看。

现在,我们掌握了使用原生的 XmlPullParser 的方法,可以组合出我们想要的资料 parser ,但别高兴得太早!上一段程序码是不是看起来有哪边怪怪的?假设我们有很多种的资料型态和 tag 要取资料,那我们不就要每一种都写一个 function 去处理?如果我们有方法可以去产生这些程序码,我们不用自己手动写。这个就是我们的 annotation processor 可以办得到的事,下篇开始会讲 annotation 和 annotation processor !


<<:  Day11- pandas(6)DataFrame有效率的检视资料方法

>>:  个人管理 - 技术提升

Day 28 JavaScript < 简单介绍>

1.JS是什麽? Java Script 是一种运行在客户端的脚本语言 (script就是脚本的意思...

Day 13:摆放控制项(二)

上一篇的未完成品: 先前按钮的宽度为固定值,所以不会依据视窗的宽度排排站好。修改如下: 按钮的间距保...

【DAY 22】为什麽每天可以有这麽多问题? Microsoft Power Virtual Agents 智慧虚拟助理帮帮我~

哈罗大家好~ 昨天介绍了 Microsoft Power Virtual Agents 智慧虚拟助理...

Day 12 JavaScript var vs let (2)

今天介绍 JS 内 var 与 let 的後两点差异。 执行环境 Execution Context...

DAY4.看了两个YT的影片

今天到嘉义开店 从高雄坐火车到嘉义 在坐火车的一个小时 把外国教python flask的影片看完 ...