前几篇文章中,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 方案提供单词信息的程序。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)清单 1. 提供 WordNet 信息的 CherryPy 服务器代码(wnserver.py)
import cherrypyfrom picket import Picket, PicketFilterfrom 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 wordxmlclass 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 resultcherrypy.root = root()cherrypy.root.view = wordform_handler(applyxslt=True)cherrypy.root.raw = wordform_handler()cherrypy.root.pointer = pointer_handler()#Disable debugging messages in Web responsescherrypy.config.update({'logDebugInfoFilter.on': False})cherrypy.server.start()代码非常简单,但是您将看到它做了非常多的工作。至少需要 Python 2.4 版本,因为使用的 油漆工(decorator)是该版本新增加的一个特性。首先看看必备的条件。导入的一个文件是 wnxmllib.py,基本上就是上一期关于 WordNet 的文章中提供的代码,只不过捆绑到了一个文件中,为了使用更简单的 4Suite API 稍微作了一些修改。除了下列必备的工具外,所有代码都放在本文的 下载 中。
CherryPy (import cherrypy):最低版本 CherryPy 2.1,目前为 beta 版。 Picket (from picket import Picket, PicketFilter):一种非常简单的工具,简化了从 CherryPy 服务器中调用 XSLT 的 API。最低版本是 Picket 0.5。 4Suite (imported from wnxmllib.py):核心 XML 库。最低版本是 4Suite 1.0b1。 PyWordNet (imported from wnxmllib.py):WordNet 处理库。最低版本是 PyWordNet 2.0.1。 WordNet:词法数据库文件。最低版本是 WordNet 2.0。清单 wnserver.py 包括三个类,分别处理站点 URL 空间中的不同部分。由文件最后的代码控制。root 基本上是一个空类,实际上是站点根 URL 的占位符。在测试机器上,可能是 http://localhost:8080/ 这种形式。所有真正的动作都在更具体的 URL 中发生。下面的列表描述从 URL 到类的映射:
以 http://localhost:8080/view/ 开始的 URL 由 wordform_handler 的实例处理,它将 XSLT 应用于 WordNet XML 结果。 用于一般的 Web 浏览器查看。 以 http://localhost:8080/raw/ 开始的 URL 由 wordform_handler 的实例处理,它直接传回 WordNet XML 结果。 用于可处理 XML 的应用程序。 以 http://localhost:8080/pointer/ 开始的 URL 由 pointer_handler 类的实例处理。用于解释从单词的一种含义到另一种含义的链接,上一期 WordNet 文章 在最后提到过。它还使用 XSLT 把 XML 结果转化成浏览器显示的 HTML。根类设置了一个筛选器,这是一种 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 titlexsl:value-of select="word-senses/@text"//title /head body bgcolor="#ffffff" h1xsl: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/ emn. /emxsl: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/ emv. /emxsl: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/ emadj. /emxsl: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/ emadv. /emxsl: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()"/ /axsl: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
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)
?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 formxsl:value-of select="."//form sample-glossxsl:value-of select="$gloss"//sample-gloss /xsl:copy /xsl:template/xsl:stylesheet 对清单 4(wordlist.xml)中的测试文档运行该 XSLT 将得到 清单 5 所示的结果。
清单 4. 用于清单 3 转换的单词清单文档(wordlist.xml)
word-list wordanimal/word wordvegetable/word wordmineral/word/word-list
清单 5. 将清单 3 XSLT 用于清单 4 测试 XML 得到的结果
?xml version="1.0" encoding="UTF-8"?word-list wordformanimal/formsample-glossa living organism characterized by voluntary movement/sample-gloss/word wordformvegetable/formsample-glossedible seeds or roots or stems or leaves or bulbs or tubers or nonsweet fruits of any of numerous herbaceous plant/sample-gloss/word wordformmineral/formsample-glosssolid 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 讨论论坛。
本文示例代码或素材下载


