本文示例源代碼或素材下載
前幾篇文章中,Uche Ogbuji 討論了 WordNet 2.0,普林斯頓大學的這個項目的目標是建立英文單詞及其詞法關系的數據庫。他說明了如何從單詞數據庫中提取 XML 序列。本文繼續探討這個話題,通過示例代碼說明如何通過 Web 協議來提供這些 WordNet/XML 文檔,以及如何使用 XSLT 訪問它們。
XML 是 Web 上的 SGML,各種 XML 項目基本上都以這種或那種方式與 Web 聯系。不久前,本專欄發表的“查詢 XML 格式的 WordNet”考察了 WordNet 2.0,以及如何與 XML 和 RDF 技術結合使用。如果沒有讀過這篇文章,建議您在繼續閱讀本文之前先看看。下面我們將編寫以 XML 形式從 WrodNet 中抽取詞法信息的基本代碼。我將說明如何以 Html 和 XML 的形式在 Web 上提供單詞信息。
Web 服務器代碼
本文中使用 Python 和 XSLT,當然也完全可以將這些概念應用到其他大多數編程語言。我將解釋 Python 代碼,因此只需要對這種語言有基本的了解即可。Python 支持多種編寫 Web 應用程序的方式,從超簡單的標准庫 BaseHTTPServer 模塊到 Zope 這種大型的第三方系統。這中間還有多種 Python Web 框架可供選擇。一種非常流行的選擇,也是我個人最喜歡的,是 CherryPy(請參閱 參考資料)。非常簡單,而且非常適合 Python 語言的特性。 清單 1(wnserver.py)是使用 CherryPy 根據非常簡單的 URL 方案提供單詞信息的程序。
清單 1. 提供 WordNet 信息的 CherryPy 服務器代碼(wnserver.py)
import cherrypy
from picket import Picket, PicketFilter
from wnXMLlib import *
class root:
_cpFilterList = [ PicketFilter(defaultStylesheet="vIEwWord.xslt") ]
class Wordform_handler:
def __init__(self, applyxslt=False):
self.applyxslt = applyxslt
return
@cherrypy.expose
def default(self, Word):
synsets = serialized_synsets_for_word(Word)
result = ''.join(synsets) #Concatenate strings in result list
#Wrap up the XML fragments into a full document
WordXML = '<word-senses text="'+word+'">'+result+'</Word-senses>'
if self.applyxslt:
picket = Picket()
picket.document = WordXML
return picket #apply the XSLT and return the result
return WordXML
class pointer_handler:
@cherrypy.expose
def default(self, pos, target):
synset = getSynset(pos, int(target))
synsetXML = serialize_synset(synset)
picket = Picket()
picket.document = synsetXML
return picket #apply the XSLT and return the result
cherrypy.root = root()
cherrypy.root.vIEw = Wordform_handler(applyxslt=True)
cherrypy.root.raw = Wordform_handler()
cherrypy.root.pointer = pointer_handler()
#Disable debugging messages in Web responses
cherrypy.config.update({'logDebugInfoFilter.on': False})
cherrypy.server.start()
代碼非常簡單,但是您將看到它做了非常多的工作。至少需要 Python 2.4 版本,因為使用的 油漆工(decorator)是該版本新增加的一個特性。首先看看必備的條件。導入的一個文件是 wnXMLlib.py,基本上就是上一期關於 WordNet 的文章中提供的代碼,只不過捆綁到了一個文件中,為了使用更簡單的 4Suite API 稍微作了一些修改。除了下列必備的工具外,所有代碼都放在本文的 下載 中。
清單 wnserver.py 包括三個類,分別處理站點 URL 空間中的不同部分。由文件最後的代碼控制。root 基本上是一個空類,實際上是站點根 URL 的占位符。在測試機器上,可能是 http://localhost:8080/ 這種形式。所有真正的動作都在更具體的 URL 中發生。下面的列表描述從 URL 到類的映射:
根類設置了一個篩選器,這是一種 CherryPy 結構,對於從 HTTP 接收的數據以及 HTTP 響應發出的數據執行某些動作。使用特殊的篩選器 PicketFilter,如果需要可以對結果進行 XSLT 轉換。根據 CherryPy 的設計,這個根處理程序實例的篩選器也可用於源自 cherrypy.root 的鏈中的其他處理程序對象。後面將詳細討論篩選器動作。
wordform_handler 類有一個初始化器,並記錄傳遞的參數,決定是否對 XML 結果應用 XSLT。default 這個特殊方法使用 @cherrypy.expose 修飾符標記為 CherryPy 處理程序函數。它從 URL 接收要查詢的單詞作為參數,調用 wnxmllib.serialized_synsets_for_word 得到結果 XML 塊。然後使用字符串連接創建完整的、結構良好的 XML 文檔。注意,使用簡單的字符串連接構造 XML 文檔一般來說比較危險(參考資料 中的一篇文章解釋了這一點)。我采用這種方法,是因為非常清楚 WordNet 2.0 中的數據,並且完全了解 XML 序列化問題。如果不完全肯定自己在做什麼,應避免這種捷徑而使用適當的 XML 輸出工具(如 4Suite 的 MarkupWriter)。
進行轉換
如果 wordform_handler 設置為應用 XSLT,則它會創建 Picket 對象。該對象被前述的篩選器捕獲,用於對生成的結果進行 XSLT 轉換。源文檔是用 WordNet 同義詞集構造的 XML。清單 2(vIEwWord.xslt)是 XSLT 轉換。
清單 2. 把 WordNet XML 呈現為 Html 的 XSLT(vIEwWord.xslt)
<?XML version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
XMLns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="Html"/>
<xsl:template match="/">
<Html>
<head>
<title><xsl:value-of select="Word-senses/@text"/></title>
</head>
<body bgcolor="#ffffff">
<h1><xsl:value-of select="Word-senses/@text"/></h1>
<xsl:apply-templates/>
</body>
</Html>
</xsl:template>
<xsl:template match="noun">
<p>
<xsl:text/>[<xsl:apply-templates select="Word-form"/>] <xsl:text/>
<em>n. </em><xsl:apply-templates select="gloss"/>
<div> ‡ <xsl:apply-templates mode="synset-body"/></div>
</p>
</xsl:template>
<xsl:template match="verb">
<p>
<xsl:text/>[<xsl:apply-templates select="Word-form"/>] <xsl:text/>
<em>v. </em><xsl:apply-templates select="gloss"/>
<div> ‡ <xsl:apply-templates mode="synset-body"/></div>
</p>
</xsl:template>
<xsl:template match="adjective">
<p>
<xsl:text/>[<xsl:apply-templates select="Word-form"/>] <xsl:text/>
<em>adj. </em><xsl:apply-templates select="gloss"/>
<div> ‡ <xsl:apply-templates mode="synset-body"/></div>
</p>
</xsl:template>
<xsl:template match="adverb">
<p>
<xsl:text/>[<xsl:apply-templates select="Word-form"/>] <xsl:text/>
<em>adv. </em><xsl:apply-templates select="gloss"/>
<div> ‡ <xsl:apply-templates mode="synset-body"/></div>
</p>
</xsl:template>
<xsl:template match="Word-form">
<!-- construct a link to this Word form -->
<a href="/vIEw/{.}">
<xsl:apply-templates/>
</a>
<xsl:if test="not(position() = last())">, </xsl:if>
</xsl:template>
<xsl:template match="gloss">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*" mode="synset-body">
<xsl:if test="@target">
<!-- then it's a pointer: construct a link to it -->
<a href="/pointer/{@part-of-speech}/{@target}">
<xsl:value-of select="name()"/>
</a><xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
XSLT 取單詞的含義信息,顯示每種含義的解釋(簡要定義)。還根據 WordNet 中的指針呈現到其他含義的鏈接。通過觀察 XSLT 的結果,可以更清楚地交接其操作。圖 1 是運行 清單 1 中的 Web 服務器並浏覽頁面以查找單詞“code”時的結果。截屏使用的浏覽器是 Mozilla Firefox。 圖中可以看出,訪問的 URL 是 http://localhost:8080/vIEw/code。
圖 1. 查找單詞“code”時的浏覽器視圖
單擊鏈接時進入一個指針,它指向一個同義詞集,而不是某個單詞。這裡選擇了一種更簡單的顯示方式,用方括號表示同義詞集中的所有單詞,包括注解和到其他同義詞集的鏈接。清單 2 中的 XSLT 被設計成能夠顯示完整的詞型信息以及單個同義詞集的信息。Web 服務器中處理指針 URL 的代碼是 清單 1 中的 pointer_handler.default 類。如您所見,它從 URL 中接受兩個值。http://localhost:8080/pointer/noun/5955443 這樣的 URL 變成了對 pointer_handler.default 的調用,包括 noun 和 WordNet 偏移量 5955443。非常重要的一點是,每個注解之前出現的詞型被呈現為鏈接,這意味著通過單擊英文單詞間的很多聯系可以導航到整個 WordNet 數據庫。
只要 XML
這個 WordNet Web 服務器還允許使用 http://localhost:8080/raw/... 這種形式的 URL 得到單詞的原始 XML。 我認為對於使用 XML 的 Web 應用程序,直接在 Web 上公開這些 XML 和准備好在浏覽器中使用的 HTML 一樣非常重要。這樣,您或其他人就很容易構建其他應用程序通過直接處理 XML 來擴展功能,而不是從屏幕顯示的 Html 中摘取。為了說明這一點,清單 3 中的示例 XSLT 代碼從服務器上查詢原始 XML 然後處理它。它接受一個單詞列表,然後輸出同樣的列表,但是增加了每個單詞的定義。
清單 3. 查詢主 WordNet 服務器的示例 XSLT
<?XML version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
XMLns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Word-list">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="Word">
<!-- The Word form to look up is the element content -->
<xsl:variable name="Wordform" select="."/>
<!-- Use the Word form to construct the query URL -->
<xsl:variable name="Wordnet-url"
select="concat('http://localhost:8080/raw/', $Wordform)"/>
<!-- Query the WordNet server, retrIEving an XML document -->
<xsl:variable name="wordnet-info" select="document($Wordnet-url)"/>
<!-- Grab the first gloss from the retrIEved WordNet document -->
<xsl:variable name="gloss" select="$Wordnet-info//gloss[1]"/>
<xsl:copy>
<form><xsl:value-of select="."/></form>
<sample-gloss><xsl:value-of select="$gloss"/></sample-gloss>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
對清單 4(Wordlist.XML)中的測試文檔運行該 XSLT 將得到 清單 5 所示的結果。
清單 4. 用於清單 3 轉換的單詞清單文檔(Wordlist.XML)
<Word-list>
<word>animal</Word>
<word>vegetable</Word>
<word>mineral</Word>
</Word-list>
清單 5. 將清單 3 XSLT 用於清單 4 測試 XML 得到的結果
<?XML version="1.0" encoding="UTF-8"?>
<Word-list>
<Word><form>animal</form><sample-gloss>a living organism characterized
by voluntary movement</sample-gloss></Word>
<Word><form>vegetable</form><sample-gloss>edible seeds or roots or
stems or leaves or bulbs or tubers or nonsweet fruits of any of
numerous herbaceous plant</sample-gloss></Word>
<Word><form>mineral</form><sample-gloss>solid homogeneous inorganic
substances occurring in nature having a definite chemical
composition</sample-gloss></Word>
</Word-list>
為了格式目的,清單 5 中增加了空格。sample-gloss 的內容來自對 WordNet 服務器的動態查詢。這僅僅是說明 WordNet 與 XML 結合起來的強大功能的又一個例子。
結束語
我准備繼續研究 XML 形式的 WordNet 的實際應用。將來的主題包括把 WordNet 公開為 RDF 數據庫來改進搜索。同時,請把您的想法提交到 Thinking XML 討論論壇。