内容


使用 XML

完成 XM 版本 1

管理链接列表和目录

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 使用 XML

敬请期待该系列的后续内容。

此内容是该系列的一部分:使用 XML

敬请期待该系列的后续内容。

经过最近三个月的努力,XM 已经逐渐成形。对于 XM,我的目标是开发一种用于 Web 发布(使用 XML 和 XSLT)的低成本解决方案。由于 XML 和 XSLT 看起来过于复杂,因此许多网站管理员不想使用它们。有了 XM,我希望使这些技术易于被大家接受。

当前版本具有一种只对更改过的文件应用样式表的便利机制和可以维护和验证站点的链接管理。这个最新的 XM 还支持多个样式表,而且给这些样式表传递参数很方便。即使只添加了这几个小特性,在对实际发布网站的有限测试中,XM 证明是有效的。在 XM 的帮助下,我一直在维护三个不同的网站,并且我发现 XM 足以胜任。

虽然我可以想到对 XM 做更多的改进,但这个月我只添加一个重要的新特性。下个月,我将在 使用 XML专栏中讲述另一个项目,并且这个项目是我下面几个月所主要关注的。不,我不是厌倦了这个项目,但在我改进这个项目之前,我需要更多关于哪部分有效和哪部分需要改进等方面的反馈。我计划进一步进行现场测试 XM,并希望从读者(也就是您那里)收集一些反馈。但我不想闲着,在下一篇专栏文章中,我将启动一个新的项目 ― SAX 处理程序编译器。

这个月对 XM 的改进是添加了自动编译文件列表的能力。这对于维护下载页面和目录很方便。

关于原型设计

现在,为什么要到另一个项目?这里有许多原因。当然,在我提议开办一个专栏来讲解如何创建一系列开放源码 XML 应用程序时,就已经和编辑一起制订了这个计划表。但是,更主要的原因是,我需要收集关于 XM 的反馈。

实质上,我把 XM 作为用户界面开发工具来使用它。虽然它不是 GUI,但我最初目标是使用 XSLT 处理器(确切地讲,这个工具对用户不太友好),并通过将 XSLT 与 XM 捆绑在一起而使网站管理员更愿意使用它。实质上,XM 是一种在 TrAX 上可能的用户接口。

用户界面开发涉及到许多原型设计的工作以及实验和错误的过程。没有任何东西能胜过用户的反馈。例如,我最初认为 XM 只需要支持一个样式表即可。虽然理论上听起来蛮好(可以用一个样式表处理许多 XML 词汇,这是可能的),但经验表明这种方法不象我预想的那样方便。所以,我采用了另一种策略,使用这种策略,我感到十分满意。对于我没有事先花更多的时间来设计 XM,一些读者表示很惊奇;我希望这个解释能澄清我为什么在第一个项目中就一头扎入原型设计中。

迄今为止,我已经在两个网站上测试过 XM,其中一个是 ananas.org,另一个还在开发中。这段经历是有用的,但从这两个站点,我只能了解这么多。我需要更多的反馈来确定以后的开发。我将把 XM 应用到其它网站,如 Pineapplesoft(我的公司),但我还希望给您一个机会来尝试该软件,并报告您的发现。我知道您不能测试一个正在发生变化的目标,所以停上几个月,听听大家的反馈是有意义的。

那么请尝试将 XM 应用到您自己的网站上。如果目前还没有网站,则可以向 Geocities 这样的服务商注册申请,得到带服务的免费空间,开始建立个人页面或为本地社团构建站点。

使用 XM

这一节概述如何安装和测试 XM(关于给定特性的更多信息,请参阅 Working XML: Using XSLT for content management,在那里有所介绍)。请记住,如果遇到问题,请将它们报告给“ananas 讨论邮件列表”(请参阅 参考资料)。

首先应该下载最新版本的 XM。如通常一样,可以通过 CVS 资源库访问 XM 的最新版本。然而,可以发现已打包的版本要更方便,该版本包括 Windows 批处理文件和已编译类。下载和解压缩这个打包的版本。关于所有的链接,请参阅 参考资料

创建三个目录:

  • 第一个目录是源码目录 src ,在这里放置您的 XML 文件。
  • 第二个目录是 rules ,它包含 XSLT 样式表。应该将最常用的样式表命名为 default.xsl 。可以通过处理指令来引用其它样式表。
  • 第三个目录是结果目录 publish ,在那里,XM 放置 HTML 文件。

准备一些 XML 文件以及至少一个样式表。运行 XM,传递给它两个参数, srcpublish 目录,如下:

java org.ananas.xm.Console src publish

已打包版本包括作为示例的 ananas.org 网站的源码。请使用它,会得到一些启示。

目录读取

我在这一篇专栏文章中将详细讲述上个月所提示的目录读取特性。这对索引页面 ― 那些主要包含到文件的链接(譬如,下载部分)― 或者其它页面(譬如,目录或词汇表)很有帮助。正如任何 Web 管理员所知道,手工维护长的链接列表是非常单调乏味的。

对于下载部分,Web 管理员不仅必须要选择和准备文件,而且必须创建和维护一个或多个带有到实际文件链接的页面。当文件已经可用或当已经删除了旧文件时,很容易忘记更新新链接。同样,在文档跨几个页面时,Web 管理员必须创建一个目录,该目录包含到文档中所有页面的链接。维护目录页面同样易于出错,而且常常会报告找不到所需要的部分。基本上,词汇表也会造成同样的问题。

很明显,人工编辑器和 web 管理员不擅长于维护长的数据列表。那项令人厌烦的工作最好留给计算机和 XM 的目录读取来做。目录读取促使 XM 创建一个带文件列表的 XML 文档,然后使用 XSLT 样式表将该 XML 文档转换成正确的 Web 页面。这个 XML 文档也许象 清单 1中所示的那样。这样做的好处是,每次运行 XM 时,它都从文件系统读取目录,因而保证了链接页面总是最新的。

顺便说一下,我发现这是一个有趣的、既有动态网站特点(使用 JSP 或类似技术)又有纯静态站点特点的中间站点,在这些站点,Web 管理员必须手工地更新每个文档。XM 构建静态站点,但使用软件来自动创建和维护大多数令人厌烦的页面。

DirectoryReader

目录读取本身由 DirectoryReader 类负责,可以在线地找到该类和本专栏文章中所列出的所有其它类(请参阅 参考资料)。为了提高效率, DirectoryReader 不将 XML 文档写到磁盘,而是启动描述文档的 SAX 事件。

这是一个小小的优化,省去了创建和解析临时文件,而对我这方面没有太多特殊影响。更常见的设置是让 DirectoryReader 将 XML 文档保存在一个临时文件中。然后,经过解析器,将该文档送给 XSLT 处理器。如图 1 所示。

图 1. DirectoryReader 产生 XML 文档
##twb>图 1. DirectoryReader 产生 XML 文档<twb##
##twb>图 1. DirectoryReader 产生 XML 文档<twb##

然而,当编码 DirectoryReader 时,我可能要用一些方法来编写开始标记、结束标记和属性。所以不会花太多力气来将目录调用进 ContentHandlerstartElement()endElement()startPrefixMapping()endPrefixMapping() 。您会在 Working XML: Processing instructions and parameters 中有关编写 LinkFilter 类的描述中看到它们是如何工作的。

在这种解决方案中, DirectoryReader 模拟 SAX 解析器。从来不将文件写入磁盘。相反,直接将它送给 XSLT 处理器。由于所有事情都发生在内存中,如图 2 所示,所以效率略更高一些。

图 2. DirectoryReader 取代解析器
##twb>图 2. DirectoryReader 取代解析器<twb##
##twb>图 2. DirectoryReader 取代解析器<twb##

从 XSLT 处理器的角度来看, DirectoryReader 和常规的 SAX 解析器之间没有区别。从我的观点来看,这有两方面的好处:它的效率比以前略高一些,也许更重要的是,它更便于使用 XML 过滤器合并进实际 XML 文档中的目录文档,稍后就会看到。

顺带提一下,这表明 XML 不仅是一种语法,而且也是一种标准的数据模型。SAX 事件流能正确地描述了 XML 文档。虽然从未将文件写入磁盘,也从未使用 XML 语法,但毫无疑问,该文档是 XML 文档,因为它符合该数据模型。

清单 2DirectoryReader.read() ,它创建文档。它使用标准的 Java File 对象来读取目录,并为 File 对象中每个特性创建属性。上一篇专栏文章中介绍过的 ContentHandlerExtractor 有助于编写这个方法。

DirectoryReader 是设计用来创建完整 XML 文档或创建用来合并到另一文档中的文档。 embedded 特性控制这种行为,唯一的不同是 DirectoryReader 是否发出 startDocument()endDocument() 调用。

DirectoryReaderFile 定义的对象添加一个属性: isMarkedisMarked 用来标识当前文件。样式表可以使用 isMarked 属性过滤出到当前文件的链接。

WalkFilter

要调用 DirectoryReader ,Web 管理员必须创建 XML 文档,并他或她需要这个文件列表的地方插入一个特殊的 xm:Directory 元素。正如清单 3(ananas.org 的主页)所示, xm:Directory 元素替代了项目列表。这个列表本身由样式表在子目录的列表上构建的。

清单 3. ananas.org 的主页
<?xml version="1.0"?>
<?xm-xsl-param name="sponsor" value="ananas"?>
<article xmlns="http://www.psol.com/2001/docbook" 
         xmlns:xm="http://www.ananas.org/2001/XM/Walk">
<articleinfo>
 <title>ananas.org</title>
 <subtitle>open-source software for the 'Working XML' column</subtitle>
 <author><firstname>Beno�t</firstname><surname>Marchal</surname>
<affiliation><orgname>Pineapplesoft sprl</orgname></affiliation></author>
 <copyright>
    <year>2001</year>
    <holder><ulink href="http://www.marchal.com/">Beno�t</ulink></holder>
 </copyright>
</articleinfo>
<simpara><citetitle pubwork="journal">ananas.org</citetitle> is the 
companion Web site for the <citetitle pubwork="series">Working XML
</citetitle> column by <author><firstname>Beno�t</firstname>
<surname>Marchal</surname></author>. <citetitle pubwork="series">
Working XML</citetitle> is published on <citetitle pubwork="journal">
<ulink href="http://www.ibm.com/developerWorks">developerWorks</ulink>
</citetitle>.</simpara>
<simpara>The source for the <citetitle pubwork="series">Working XML
</citetitle> column is being distributed through this site. Currently 
the following projects are available:</simpara>
<xm:Directory dir="." markSource="true"/>
</article>

WalkFilter 拦截 xm:Directory 元素,并用到 DirectoryReader 的调用来替换它。象 LinkFilter 一样, WalkFilter 是作为 XMLFilter 来实现的。然而, LinkFilter 被设计用来对 HTML 文档进行后处理,而 WalkFilter 用来对 XML 文件进行预处理。

WalkFilter 非常简单。如 清单 4 所示,它测试 startElement() 中的 xm:Directory 。在 WalkFilter 中有一个附加的逻辑以废弃 xm:Directory 元素的内容。很明显,我不想让那个内容经过过滤器。

请注意,尽管我将 WalkFilterDirectoryReader 的名称空间都映射到 xm 前缀但它们俩是不同的。由于以后希望为数据库、目录服务和电子邮件添加类似的阅读器,所以 WalkFilter 使用更一般的名称空间( http://www.ananas.org/2001/XM/Walk )。用这两个名称空间来区分样式表中的这两个元素是很方便的。

由于 xm:Directory 中的路径是相对于文档的目录,所以 WalkFilter 需要到文档的路径。SAX 提供了一种标准的特性机制,该机制可以让调用者设置目录。 WalkFilter 为此实现 setProperty()getProperty() 方法。

StylingMover 和 Co.

最后要说明的是,使用来自移动器(mover)的 WalkFilter 。有了 TRaX,通过过滤器,对 XML 文档进行预处理是不太困难的。 SAXSource 的构造器之一取 XMLReader (因而也获得了 XMLFilter )作为参数。我稍微修改了 StylingMover ,以便在 XMLFilter 可用时使用这个构造器。正如清单 5 所示,这些变动很小。

清单 5. StylingMover 对 XML 文件进行预处理
if(xmlFilter != null)
{
   try
   {
      xmlFilter.setProperty(SOURCE_FILE,sourceFile);
   }
   // it's OKay if it does not recognize the property, it
   // just means it's not one of our filter
   catch(SAXNotRecognizedException e)
      { }
   source = new SAXSource(xmlFilter,JAXPHelper.toInputSource(sourceFile));
}
else
   source = new StreamSource(sourceFile);
transformer.transform(source,result);

然而,这里有一个严重问题。由于 WalkFilter 修改输入文档,所以不再可能依靠最后修改文件的日期来确定是否应该重新制定文档的样式。例如,即使 清单 3没有变化,如果目录已经更改,则文档应该重新制定文档的样式。

我无法通过 Java 来检测到最后修改目录是什么时候(如果您有变通的方法,请张贴到这个邮件列表中)。唯一安全的解决方案是,无论什么时候运行 XM,都重新制定文档的样式,但这样做破坏了构建的智能性。这可能对小型站点有用,但对较大的站点就成问题了。折衷的解决方案是,对那些带 xm:Directory 标记的文件使用不同的扩展名(我选择 .xm )。

清单 6 摘自 MoversSupervisor 。正如您所见,它注册 StylingMover 两次。一次是针对常规的 XML 文件,一次是针对 XM 特定的文件。后者通过 WalkFilter 进行预处理。

ReferenceResolver

清单 7摘自 ananas.org 样式表。当应用到 清单 3 时,它创建项目列表。样式表假定每个项目目录包括一个 index.xml 文件。它尝试装入后一个文件,然后抽取出文件的标题和子标题以创建超链接。这显示了如何对目录使用目录读取。

但是还需要了解一点。缺省情况下,XSLT 处理器装入文档时所取路径是相对于样式表目录。由于 XM 将样式表放在一个完全独立的目录里,所以处理器将永远找不到 index.xml 文档。

我已经介绍了新的 URL 格式 x-source: (x- 表示它不是标准的 URL 格式),它解析相对于当前文档而不是相对于样式表的文件名。我修改了 ReferenceResolver 类以识别和处理那些 x-source: URL,如 清单 8 所示。您一定还记得:该处理器使用 ReferenceResolver 来装入文档和样式表。

轮到您了

现在结束对 XM 第一个发行版的讨论。通过这次“旅行”,我们了解到 SAX 和 TrAX API 中的一些有趣特性。正如已经提到过的,我鼓励您下载这个包,并自己来测试它。


相关主题

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文.
  • 通过单击本文顶部或底部的 讨论参加关于本文的 论坛
  • 可以从 ananas.org下载此项目的代码。请使用到 developerWorks 上 CVS 资源库的链接以及到 ananas 讨论邮件列表和 XM 打包版本的链接。我鼓励您加入这个列表,并提供您对这个项目的想法。
  • 如果需要 XM 的 zip 文件,也可以从此下载。
  • XM 分别使用 XalanXerces-J作为 XSLT 处理器和 XML 解析器。Xalan 最初是由 IBM 的 Lotus software 开发的,而 Xerces 最初是由 IBM 开发的。IBM 将该代码赠予了 Apache 基金会(Apache Foundation)。
  • 如果需要在网上找一个地方来放置您用 XM 构建的网站,则可以利用免费的 Geocities。如果可以承担得起主机托管,则可以考虑 Pair Network,它提供了廉价而可靠的主机托管。
  • 如果希望用 Lous Domino 来管理 XML 内容,则 XML Toolkit for Domino是很有用的。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=50642
ArticleTitle=使用 XML: 完成 XM 版本 1
publish-date=10012001