2011年2月27日 星期日

HTML 資訊汲取(下篇) - TagSoup 輸出 namespace 問題的解決方案

Namespace 問題

在上一篇文章『HTML 資訊汲取(中篇) - Default namespace 問題』中提到:在 XPath 中,沒有所謂 default namespace (預設命名空間)。若 XPath 路徑未使用 prefix (前置字符) 指明 namespace,則其對應的 namespace 為 empty namespace (空命名空間)。因此,若在 XML 文件中定義了 default namespace,則所有的標籤必定都歸屬於某個不為空的 namespace。此時,未指明 namespace 的 XPath 路徑,將對應不到任何元素。

另一方面,TagSoup 處理過的 HTML 文件,有三個與 namespace 有關的問題:

  1. TagSoup 處理過的 HTML 文件,一律輸出為 XHTML 格式,並且定義了 xmlns="http://www.w3.org/1999/xhtml" 這個 default namespace,以及xmlns:html="http://www.w3.org/1999/xhtml" 這個以 html 為 prefix 的 namespace。而其餘的 namespace 的定義,都將被移除。
  2. 由於 TagSoup 處理過的 HTML 文件,含有 default namespace 的定義,使用 XPath 選取元素時,一定要在路徑的標籤或屬性前,加上 html 這個 prefix,才能對應到元素。
  3. TagSoup 處理過的 HTML 文件,其元素標籤若含有 prefix 定義,即使 prefix 是 html,都會被修改並對應到 urn:x-prefix:html 這樣的 URI(參考 TagSoup 原始碼中 Parser 類別的 foreign() 函數、ElementType 類別的 namespace() 函數以及 change log),因而使該標籤對應不到原本正確的 namespace 的 URI。導致使用了該 prefix 的 XPath 路徑,也對應不到正確的標籤。(原本應該能正確對應的,這一點可以經由使用 JDOM 內建的 XML 解析器的實驗證明。)

思考可能的解決方案

內建的 XML 解析器不會有 namespace 的問題,但是無法處理 non-well-formed HTML。顯然此路不通…。

TagSoup 可以處理 non-well-formed HTML,但是會有 namseapce 問題。該是時候放棄 TagSoup,另找一個 HTML 解析器了嗎?還是如果我們可以配合 TagSoup 輸出的 namespace 定義,在 XPath 中一律使用 html prefix;或是,相反地,讓 TagSoup 不輸出 namespace 。是否就可以解決問題呢?(雖然邏輯上還存在著一個完美的可能性,就是讓 TagSoup 不輸出 default namespace,也同時能保留外部 namespace 的定義,不過這並不容易達到。這已牽涉到 TagSoup 的設計架構了,除非大幅修改 TagSoup 的架構,讓它正確處理外部 namespace 的定義。但是這已經超出本文的目的了。)

2011年2月22日 星期二

HTML 資訊汲取(中篇) - Default namespace 問題

在上一篇文章『HTML 資訊汲取(上篇) - 使用 JDOM 、 TagSoup 及 XPath』裡,我提到了如何利用 JDOM 搭配 TagSoup,並使用 XPath 簡單地汲取資訊。其實,在上一篇的範例裡,我刻意避開了兩個困擾許多人的問題:namespace(命名空間)問題以及TagSoup 的輸出問題

Namespace 問題

再看一下上一篇出現的新聞標題:

<span class="titletext">曾雅妮的魔幻數字與粉紅色</span>

假設,除了 span 之外,還有其他標籤,譬如 h4,也具有 titletext 類別,但是只有 span 是我們要的新聞標題。在這樣的情況下,為了僅選擇 sapn 標籤,我們應該將原來的 XPath:

//*[contains(@class,'titletext')]

改成這樣:

//span[contains(@class,'titletext')]

將此 XPath 套用到上一篇的程式中,執行看看。

def xpath = XPath.newInstance( "//span[contains(@class,'titletext')]" )
def result = xpath.selectNodes( doc )
result.each { println it.text }

看看輸出結果。看到了嗎?沒有任何輸出!

2011年2月15日 星期二

HTML 資訊汲取(上篇) - 使用 JDOM 、 TagSoup 及 XPath

簡介

本文將以實際範例介紹如何以 JDOM 搭配 TagSoup ,將 HTML 解析為 DOM 文件物件模型,並使用 XPath 汲取資訊,或者將文件輸出為 XHTML 格式。

資訊汲取

Internet 上蘊藏著豐富的內容,供人們分享訊息、傳承知識。但是在 Semantic Web 普及之前,除非資料來源網站主動提供資料存取 API,否則,要擷取既有 Internet 上的資訊,還是只能從解析 HTML 著手。

雜亂無章的 HTML (Malformed and faulty HTML)

但是眾所週知,即使存在著如 XHTML 標準規範,網路上還是充斥著各種不合乎標準的 HTML 網頁。這個現象,甚至還有個專用名詞,叫做 Tag soup