级别: 中级 Uche Ogbuji (uche.ogbuji@fourthought.com), 首席顾问, Fourthought, Inc.
2002 年 6 月 01 日 可以使用几种技术来对 XML 模式进行版本控制,譬如定义特殊根属性或使用 DTD。本技巧文章讨论了如何使用 XML 名称空间来对格式进行版本控制。
XML 的核心特性之一是它处理数据规则中变化的能力(所以其名称“可扩展标记语言 (Extensible Markup Language)”中有
可扩展(extensible)这个词)。因为要对 XML 词汇表进行更改,所以不可避免地会产生多个版本。因此,有必要对人和机器信息都明确地标记版本。对版本进行明确标记可以用来进行验证,或用于根据每个版本需求进行分支处理。
可以用许多方法标记 XML 词汇表的版本。本文重点讲述如何使用 XML 名称空间来标记版本。
用特殊属性或文档类型进行版本控制
让我们通过研究一个邮件标签格式的 XML 词汇表来开始讨论:
清单 1. 邮件标签格式
<?xml version="1.0"?>
<labels>
<label>
<name>Thomas Eliot</name>
<address>
<street>3 Prufrock Lane</street>
<city>Stamford</city>
<state>CT</state>
</address>
</label>
</labels>
|
如果我认为这个格式有可能会更改,那么在第一次部署它时标记其版本就很有意义了。这样做的方法之一是使用文档类型声明(DTD)。DTD 引用一个可以特定于文档版本的公用标识。这种方法的一个不错的示例是 W3C 的 XHTML 公用标识,如下列声明中所使用的:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
|
您不仅可以看到版本(1.0),而且可以看到版本中的变体(XHTML 有三个变体:strict、transitional 和 frameset)。
自然,各种版本的 DTD 本身就反映了正在做的更改。这种方法要求用 DTD 来定义格式,但有时侯我不愿意这样做。还有,尽管 DOM 和 SAX 提供了对源文档的声明中所用的公用标识的访问,但 XSLT 不提供。
另一种方法经常在顶级版本属性中使用。例如:
清单 2. 带有版本属性的邮件标签格式
<?xml version="1.0"?>
<labels version="1.0">
<label>
<name>Thomas Eliot</name>
<address>
<street>3 Prufrock Lane</street>
<city>Stamford</city>
<state>CT</state>
</address>
</label>
</labels>
|
无论我是否使用 XML 模式系统,顶级版本属性都管用。并且可以用 DOM、SAX、XSLT 或任何其它普通 XML 处理技术获得版本信息。
XSLT 语言本身采用了版本属性方法。这种方法的最大问题主要是概念上的:版本标识和每个 XML 信息项之间的连接多少有点松散(通常是通过一个祖先 — 可能是远祖 — 的某个属性)。这还有可能在根据版本进行分派的代码中造成一些麻烦。
用名称空间进行版本控制
要使版本信息成为 XML 信息项更直接的特性,可以将版本信息放到反映版本的 XML 名称空间中。例如:
清单 3. 带有名称空间版本的邮件标签格式
<?xml version="1.0"?>
<labels xmlns="http://uche.ogbuji.net/eg/labels/1.0">
<label>
<name>Thomas Eliot</name>
<address>
<street>3 Prufrock Lane</street>
<city>Stamford</city>
<state>CT</state>
</address>
</label>
</labels>
|
因此通过名称空间(在每个 SAX 事件上、在每个 DOM 节点上或在每个 XPath 节点的名称空间轴上)传递版本信息。大多数 W3C 词汇表中使用这个公共系统。实际上,XSLT 除了使用版本属性之外也使用它。
为了精确起见,W3C 通常在名称空间 URI 而不是版本号中使用日期戳记。我可以用下列代码模仿这一点:
清单 4. 带有日期戳记的名称空间版本的邮件标签格式
<?xml version="1.0"?>
<labels xmlns="http://uche.ogbuji.net/eg/labels/2002/05">
<label>
<name>Thomas Eliot</name>
<address>
<street>3 Prufrock Lane</street>
<city>Stamford</city>
<state>CT</state>
</address>
</label>
</labels>
|
当您象
清单 4中所演示的那样用名称空间来进行版本控制时,最大的问题是:因为名称空间的传播,所以即使是实际格式中很小的更改也会变成大问题。如果我调整格式,以便在地址中出现可选的
country 元素,那么,即使它可能对处理代码没有多少实际影响,用户最终还是要在其所有处理代码中支持原始名称空间和更新的名称空间(比方说
http://uche.ogbuji.net/eg/labels/1.0 )。
如果不同版本之间的格式更改足够小,以致您预期这种更改不会对处理造成太大影响,那么,一种可行的解决方案是不要在每次更改格式时更改名称空间 URI。在大多数情况下,这种解决方案都有效,但是,当名称空间的维护人员使用指向描述格式的实际文档的可检索 URI 时,该解决方案却会失效。在这个实例中,文档将很可能随任何格式更改而更改(无论这种更改多么小);因此更改该文档的 URI 是有意义的,而它恰巧就是名称空间。
Eric van der Vlist 在 2001 年 3 月的 XML-DEV 邮件列表中建议用一种系统来使这个问题所造成的影响最小化(请参阅
参考资料)。
在本例中,根据所表示的格式更改的多少将版本号划分成主要部分和次要部分。在名称空间中仅使用版本号的主要部分。例如,我的邮件标签格式的原始版本是 1.0(主版本号为 1,次版本号为 0)。在添加了可选的 country 元素之后,新版本是 1.1(主版本号为 1,次版本号为 1)。我在这两个示例中使用的名称空间是:
http://uche.ogbuji.net/eg/labels/1
|
然后,我设置 HTTP 服务器(它提供每个名称空间 URI 所指向的文档),来将用户从只带有主版本号的 URL 重定向到给出精确版本的 URL。因此,当服务器得到对
http://uche.ogbuji.net/eg/labels/1 的请求时,会将该请求重定向到位于
http://uche.ogbuji.net/eg/labels/1.1 的文档上,因为那是最新的版本。用户仍然可以自由地通过对 1.0 文档的 URI 进行显式请求来检索该文档。
结束语
本技巧文章通过假定常用的实践来掩盖一些争议点。使用名称空间标记版本的方法比用版本属性的方法更常用,尽管到底哪种方法更好还有争议。另外,关于名称空间 URI 是否应该指向任何东西,是直接指向定义格式的文档,还是按资源目录描述语言(Resource Directory Description Language (RDDL))所定义的那样指向关于词汇表的一般信息文档,这些问题也都有争议。同样,常用实践将 HTTP URL 用于名称空间。考虑到这篇讨论中所研究的细微差别,将版本放置到名称空间中实际上已经经过很好的验证,并使得对 XML 格式中更改的处理轻松一点。
参考资料
关于作者
对本文的评价
|