IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML  >

XML 问题: 使用 RELAX NG 反击,第 2 部分

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

David Mertz,博士 (mertz@gnosis.cx), 推动者, Gnosis Software,Inc.

2003 年 7 月 01 日

RELAX NG 模式提供了一种描述各种有效的 XML 实例的方法,它比 W3C XML Schema 所提供的方法更强大、更简练,语义上更简单。在这一部分,David 通过解决一些附加的语义问题,并探讨一些使用 RELAX NG 的工具,来继续讨论本系列文章第一部分中提出的话题 — RELAX NG。

上一篇文章中,我相当完整地概述了 RELAX NG 模式的语法和语义。然而,有一些问题没有触及到,这里值得对这些问题做进一步的讨论。

DTD 和 W3C XML Schema 都允许 信息集增加,而 RELAX NG 却不行。RELAX NG(以及其它一些广泛使用的 XML 工具)的创建者之一 James Clark 强烈认为信息集增加违反了 XML 实例文档和模式角色中的模块性。换句话说,在 Clark 看来,RELAX NG 所拥有的特性恰是 DTD 和 W3C Schema 的错误所在。我对这一问题的感觉是复杂的,但我能理解他的直觉。

让我们先稍稍回顾一下,看看信息集内容是关于什么的。基本上,您可以询问 XML 实例包含什么数据。如果解析实例而不进行验证,则结果仅取决于实例的属性和元素体中有什么值。如果注重模块性,则模式将只告诉您实例是否有效;它不会改变文档中的实际 信息。然而,如果用 DTD 或 W3C XML Schema 来验证,则违反了这种模块性。例如,考虑下面这个 DTD:


清单 1. curious.dtd
<!ELEMENT foo EMPTY>
<!ATTLIST foo bar CDATA "curious"
              baz CDATA #FIXED "curiouser">

以及这个 XML 实例:


清单 2. curious.xml
<?xml version="1.0"?>
<!DOCTYPE foo SYSTEM "curious.dtd">
<foo/>

非验证解析器在这个文档中找到的信息集与验证解析器找到的不一样。以下是非验证实用程序 xmlcat 与验证实用程序 4xml(两者都将所遇到的任何东西回送到控制台)的对比:


清单 3. 使用验证解析器和非验证解析器的信息集
% ./xmlcat curious.xml
<?xml version="1.0" encoding="iso-8859-1"?>
<foo></foo>
% 4xml -p curious.xml
<?xml version="1.0" encoding="utf-8"?>
<foo bar="curious" baz="curiouser"/>

在 W3C Schema 中, defaultfixed 属性对于 <xsd:attribute><xsd:element> 标记起着类似的作用。

支持使用 default 的理由是它可以使 XML 实例达到最少。正是由于此目的,我使用了 default 属性(或者可能是 #FIXED 属性)。但如果恰好本地 XML 文档的内容依赖于远程 URI(有可能是虚假的 URI),甚至依赖于在解析期间不会出现网络中断,那么我也会看到危害:导致问题出现以及增加调试难度。

RELAX NG 不执行任何信息集增加。唔,差不多 — 我认为 Clark 夸大了这一点。如果将数据类型强加给元素或属性,则仍然需要用一种重要的方法来更改值的内容。字符串值“1.0”不同于浮点值“1.0”,即使在 XML 实例中两者是用完全相同的方法来表示的。





回页首


声明基数

W3C XML Schema 用于表示所需出现的基数的方式比 DTD 或 RELAX NG 模式更简洁。如果希望 <foo> 元素在 <bar> 元素内出现 5 到 30 次,那么可以在 W3C Schema 中用一条简单的规则声明这一点:


清单 4. W3C XML Schema 基数规则
<xsd:element name="bar">
  <xsd:element name="foo" minOccurs="5" maxOccurs="30"/>
</xsd:element>

可以用 DTD 来声明同样的基数规则,但是 十分笨拙:


清单 5. 基数规则
<!ELEMENT bar
    (foo, foo, foo, foo, foo, foo?,foo?,foo?,foo?,foo?
     foo?,foo?,foo?,foo?,foo?,foo?,foo?,foo?,foo?,foo?
     foo?,foo?,foo?,foo?,foo?,foo?,foo?,foo?,foo?,foo?) >

我希望 RELAX NG 有一个显式的 <cardinality> 标记,这样可以(假想地)编写如下规则:


清单 6. 假想的 RELAX NG 2.0 基数规则
<element name="bar" xmlns="http://relaxng.org/ns/structure/1.0>
  <cardinality min="5" max="30">
    <element name="foo"/>
  </cardinality>
</element>

遗憾的是,在 RELAX NG 的当前版本中,您只能使用 <zeroOrMore><oneOrMore><optional> 基数。然而,使用所指定的模式至少可使基数的拼写略微简洁些。例如,以下是紧凑的语法:


清单 7. 实际的 RELAX NG 紧凑语法基数规则
start = element bar { fivefoo, upto25foo }
fivefoo = element foo { empty }, element foo { empty },
          element foo { empty }, element foo { empty },
          element foo { empty }
maybefoo = element foo { empty }?
upto25foo =
  fivefoo?, fivefoo?, fivefoo?, fivefoo?,
  maybefoo, maybefoo, maybefoo, maybefoo, maybefoo

我承认这种命名形式不完美,但至少可以通过重复指定模式来有效地提高效力,从而指定大量基数。





回页首


转换和验证

有许多工具可以使用 RELAX NG 模式。这些工具主要是用 Java 语言实现的,但有些工具和库是用 Python、C# 和 Visual Basic 编写的。令人吃惊的是,我还没发现用其它语言(譬如 Perl、Ruby 或 C/C++)编写的任何库,这些语言似乎很适合。

一类很明显的 RELAX NG 应用程序就是验证程序。就象那些使用 DTD 或 W3C XML Schema 的验证解析器一样,也有许多命令行、在线和库解析器可用于 RELAX NG。一类较不明显的应用程序是使各模式互相转换的工具。Sun 的 RELAX NG Converter 和 James Clark 的 trangDTDinst使您可以在 RELAX NG(XML 和紧凑语法)、DTD 和 W3C XML Schema 之间互相转换。我打算在本专栏的下一篇文章编写一个普通的 Python 工具( compact2xml.py),它使 4Suitexvif能利用 RELAX NG 的紧凑语法(这两个实用程序的作者都表示有意包括这样的工具)。

转换值得我们做更进一步地探讨。 第 1 部分从几个方面讨论了 RELAX NG 确实比 W3C XML Schema 功能强大,对一些最有效的转换所进行的讨论说明了这一点。例如,在上一篇文章中提到了一个用于图书馆 patron 的模式,这里用紧凑语法表示为:


清单 8. 图书馆 patron 紧凑语法
element patron {
  element name { text }   &
  element id-num { text } &
  element book {
    attribute isbn { text } |
    attribute title { text }
  }*
}

关于用 XML 语法所表示的图书馆,请参阅 第 1 部分,在语义上,它俩是一样的,但 XML 方法较冗长。在将此转换成 W3C XML Schema 方面,trang 进行了很好的尝试。输入和输出文件的文件扩展名用于猜测类型(或者用开关来覆盖):


清单 9. 将 RELAX NG 转换成 W3C XML Schema
% java -jar trang.jar patron.rnc patron.xsd
% cat patron.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified" version="1.0">
  <xsd:element name="patron">
    <xsd:complexType>
      <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:element ref="name"/>
        <xsd:element ref="id-num"/>
        <xsd:element ref="book"/>
      </xsd:choice>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="name">
    <xsd:complexType mixed="true"/>
  </xsd:element>
  <xsd:element name="id-num">
    <xsd:complexType mixed="true"/>
  </xsd:element>
  <xsd:element name="book">
    <xsd:complexType>
      <xsd:attribute name="isbn"/>
      <xsd:attribute name="title"/>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

这要归功于 trang,我认为,对于这种情形,这个 W3C XML Schema 是最适合的。RELAX NG 模式接受的 每个 XML 实例,W3C XML Schema 同样也接受,而且两者都可以拒绝许多错误。问题在于,有一类独特的 XML 实例,根据所要求的规则,它们 实际上不是有效的,但是却可以通过 W3C Schema 的验证。 例如:


清单 10. W3C XML Schema 识别的局限性
% cat patron-i1.xml
<?xml version="1.0" encoding="UTF-8"?>
<patron>
  <book isbn="0-528-84460-X"/>
  <name>John Doe</name>    <!-- repeats name subelement -->
  <name>Second Name</name>
  <id-num>12345678</id-num>
  <book title="Why RELAX is Clever"/>
</patron>
% cat patron-i2.xml
<?xml version="1.0" encoding="UTF-8"?>
<patron>
  <name>John Doe</name>
  <id-num>12345678</id-num>
  <!-- Too many and too few attributes of book element -->
  <book title="Why RELAX is Clever" isbn="0-528-84460-X"/>
  <book/>
</patron>
% cat patron-i3.xml
<?xml version="1.0" encoding="UTF-8"?>
<patron/>        <!-- No required subelements -->

当然,即使上面这三个示例的验证都失败,但 W3C XML Schema 仍能拒绝带有完全不允许的元素/属性的 XML 实例,或者拒绝以不正确方式嵌套元素(例如, <book> 嵌套在 <name> 中,而不是作为 <name> 元素的兄弟元素)的 XML 实例。

就验证工具的作用而言,我发现在验证失败时, jing工具能产生有用的错误消息,它在这方面做得很好。Python XML 库 4Suite 合并了 xvif 库的一个版本,它也可以执行验证(也可以在线访问后者 — 请参阅 参考资料)。但比较这些错误:


清单 11. 使用 jing 的验证错误消息
% java -jar ../trang/jing.jar patron.rng patron-i3.xml
Error at URL "file:/.../patron-i3.xml",
line number 2: unfinished element
% java -jar ../trang/jing.jar patron.rng patron-i1.xml
Error at URL "file:/.../patron-i1.xml",
line number 5: element "name" not allowed in this context


清单 12. 使用 4Suite 的验证错误消息
% 4xml --rng=patron.rng patron-i1.xml
Traceback (most recent call last):
...
  File "/.../site-packages/Ft/Xml/_4xml.py", line 89, in Run
    raise RngInvalid(result)
Ft.Xml.Xvif.RngInvalid: Qname {None}name not exected
% 4xml --rng=patron.rng patron-i3.xml
Traceback (most recent call last):
...
Ft.Xml.Xvif.RngInvalid

当然,在应用程序环境中,将首先考虑选择能利用这些库的编程语言,而后才考虑所生成的消息中的差异。





回页首


经过编译的验证程序

除了 RELAX NG 环境之外,我还没有仔细研究过的一类工具是单模式验证程序。请查看 RELAX NG 主页,其中包含至这些工具(包括 BaliRelaxNGCC)的链接。这些框架自动地编写出针对特定 RELAX NG 模式的专用验证代码。可以想象,这样的专用验证程序的运行速度一般比通用验证程序快。这样的工具是有可能的 — 或者就同一件事,相对于 W3C XML Schema 来说,至少要更简单 — 因为 RELAX NG 的设计非常好地基于算法分析之上。





回页首


经过 RELAX NG 增强的 XML 编辑器

遗憾的是,XML 编辑器对 RELAX NG 的支持还不象对 W3C XML Schema 的支持那样广泛。当然,对 DTD 的支持仍然比对其它两种模式类型的支持更广泛。这是一个遗憾,其原因是由于 RELAX NG 验证简单的概念框架,在编辑器中包含关于 RELAX NG 的定制实际上会 更容易。理想情况下,定制的 XML 编辑器将利用 RELAX NG 模式来指导和帮助用户,用保证有效性的方式插入属性和元素。

一种折衷办法是,使用如 trang 这样的工具,将 RELAX NG 模式转换成与其相近的 W3C XML Schema 或 DTD,然后在 GUI XML 编辑器中使用它们。但这样做只能在有限的范围内有所帮助。

有一个围绕 RELAX NG 构建的 XML 编辑器,这是一个基于 Java 技术的 XML Operator(请参阅 参考资料中的 RELAX NG 主页)。我“摆弄”过它一阵,发现它可能很有用,但它将归为我以前所讨论过的低端 XML 编辑器(请参阅 参考资料);XML Operator 只在某些方面实现了几个功能,它既没有提供 XML Spy 所具有的大量工具,也不具备 oXygen 所拥有的简洁性。





回页首


下次见

在第 1 部分和第 2 部分(本文)中,我讨论了 RELAX NG 的大部分内容,还对使用 RELAX NG 的工具进行了总结。第 3 部分(也就是最后一部分)将简要讨论 RELAX NG 如何让您在模式中包含外部模式,以及有选择地合并不同模式的规范。但第 3 部分主要将详细地研究 RELAX NG 紧凑语法,以及说明紧凑语法和 XML 语法之间的确切对应。



参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文.

  • 请参加关于本文的 论坛。(您也可以通过单击本文顶部或底部的 讨论访问论坛。)



  • 请查看 RELAX NG 主页,其中包含了大量至文章和工具等有用链接。尤其值得注意的是,由两位 XML 技术方面的杰出人物 James Clark 和 Murata Makoto 所编写的优秀 教程(Oasis,2001 年 12 月)。



  • James Clark 撰写了一篇有关 RELAX NG 验证的算法原则的讨论。有趣的是,在 Haskell 中提供了他的样本代码,该样本代码具有我在 HaXml 库developerWorks,2001 年 10 月)上的“XML 问题”专栏中描述的优点。



  • 使用这个 在线工具,依据 RELAX NG 模式来验证 XML 实例文档。在这个过程中,还验证 RELAX NG 模式本身。该工具基于 Eric van der Vlist 的 xvif 工具,它是用 Python 编写的。这个在线验证程序允许您从一组测试案例进行选择,并检查您自己的示例。您可以用这些 测试案例(并带有简短的讨论)。



  • 下载xvif 库。另外, 4Suite 是一个较有名的工具,它包含用于 RELAX NG 验证的 xvif。命令行工具 4xml 依据 RELAX NG 和 DTD 进行验证,在验证时,可以带各种选项。4Suite 包含许多其它工具和库,这些工具和库使用了许多与 XML 相关的技术。



  • 有关背景知识和比较结果,可以使用 这个在线工具依据 W3C XML Schema 来验证 XML 实例文档,并尝试用 这个工具依据 Approved Recommendation 来检查 W3C XML Schema。



  • trang 和 jing 是依据 RELAX NG 模式在模式和验证之间进行转换的辅助工具。前者依赖于后者,不过您可以 下载这两个工具



  • 为了使用 trang,您将需要获取 Java API for XML Processing(JAXP)的实现。如果您运行 Java 1.4 JVM,则没问题;否则可以 下载 crimson



  • DTDinst 是一个基于 Java 技术的工具,用于将 DTD 转换成 XML 实例文档格式,以及处理参数实体。由于几乎没有别的程序使用 DTDinst,因此 DTDinst XML 格式受到自身的限制。然而,可以用 XSLT 样式表将该格式转换成 RELAX NG(带有一些告诫)。您将需要 XSLT 工具来利用它。



  • 一组用于本文所讨论的图书馆 patron 示例的模式和测试 XML 实例文档。



  • 请阅读 David Mertz 的 XML 编辑器系列: 第 1 部分developerWorks,2002 年 8 月)探讨了 Java 和 MacOS 应用程序,而 第 2 部分讨论了基于 Windows 的产品( developerWorks,2002 年 9 月)。您会在“XML 问题”专栏的 专栏汇总页面找到 David 以前所撰写的文章。



  • developerWorks XML 专区查找更多的 XML 参考资料。



  • IBM WebSphere Studio提供了一套使用 Java 和其它语言使 XML 开发自动化的工具。它与 WebSphere Application Server紧密集成在一起,但它也可以与其它 J2EE 服务器一起使用。



  • 查找如何成为 IBM 认证的 XML 及相关技术开发人员




关于作者

Author photo

David Mertz 在他的格言愿望中表示,他希望自己已经达成了以下观点:标准的好处在于有众多选择。但另一方面,他在 OS 设计方面也是模糊的。可以通过 mertz@gnosis.cx与 David 联系;在 http://gnosis.cx/publish/上可以了解他的生活。欢迎就这篇、过去的或将来的专栏文章提出您的建议和意见。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款