使用 DOM Parser 取值

这篇会讲解怎麽样用 DOM 的 parser 把 RSS 资讯拿出来,首先我们可以先 new 一个 DocumentBuilder

val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()

接着把 XML 字串塞进去 builder 里,塞之前我们要先转成 ByteArrayInputStream ,就可以拿到一个 document 。

val document = builder.parse(xml.byteInputStream())

我们可以从 document 里面拿到指定 tag 的节点列表,下方就是拿 <channel> 底下的子节点列表。

const val CHANNEL = "channel"
val nodeList = document.getElementsByTagName(CHANNEL)

拿到节点列表之後我们就可以对节点做操作了!但这边因为 RSS 格式中预设只有一个 <channel> 所以我们可以写一个 parserChannel 的 function 。从 nodeList 拿出来的 node 要转型成 Element 才可以进行操作。这个 function 的第二个参数 action 是一个 lambda ,让使用者决定拿到 channel 的 element 後要进行的动作。

inline fun <T> parseChannel(xml: String, action: Element.() -> T): T {
      val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
      val document = builder.parse(xml.byteInputStream())
      document.documentElement.normalize()
      val nodeList = document.getElementsByTagName(CHANNEL)
      var result: T? = null

      if (nodeList?.length == 1) {
          val element = nodeList.item(0) as? Element
          element?.let {
              result = action(it)
          }
      }
      return result ?: throw IllegalArgumentException("No valid channel tag in the RSS feed.")
  }

前一篇的文章有提到 DOM parser 有个特色就是可以跨层查询,但我们怎麽指定我们要查询哪一个 tag 底下的值?其实可以透过指定 parent tag 的方式去查找。这是为了解决一个可能遇到的问题:假如我们今天要找 <channel> tag 底下的 <title> ,这个 title 可能存在於 <channel> 底下,但也可能存在於 <image> 底下。

<channel>
      <title>channel title</title>
			<image>
         <link>http://channel.image.link</link>
         <title>channel image title</title>
			</image>
</channel>

为了解决上面情境发生的问题,我可以写一个 Element 的 extension function ,让我们可以取某个 tag 的值出来,但可以指定 parent 的 tag name 。

fun Element.readString(name: String, parentTag: String? = null): String? {
      val nodeList = getElementsByTagName(name)
      if (parentTag == null) {
          return nodeList.item(0)?.textContent
      } else {
          for (i in 0 until nodeList.length) {
              val e = nodeList.item(i) as? Element ?: continue
              val parent = e.parentNode as? DeferredElementImpl
              if (parent?.tagName != parentTag) continue

              return e.textContent
          }
          return null
      }
  }

<<:  Day 08 : ML 工程师职责与分工

>>:  @Day8 | C# WixToolset + WPF 帅到不行的安装包 [自订动作]

【从零开始的Swift开发心路历程-Day15】安装RealmSwift资料库Part1

RealmSwift是一款非常好用的第三方资料库,但安装RealmSwift之前,我们必须先安装Co...

[Lesson17] MVP

MVP架构: Model — 管理资料来源。例如:SharedPreferences、Room、呼叫...

敏捷(Agile)

敏捷 敏捷心态(AGILE MINDSET) 敏捷是一种由价值观,原则和实践组成的心态。满足敏捷思维...

参与"在MCU 上全面建构AI能力" 9/10 心得

今晚参与了"MakerPro社群媒体平台"举办的 在MCU 上全面建构AI能力 ...

DevFest'21 Hsinchu & Taichung 议程录影上线啦!

今年的 DevFest Hsinchu & Taichung 已经在上周六顺利结束了!感谢 ...