解码 XML 和 DTD

来源:互联网 发布:用友js面试题 编辑:程序博客网 时间:2024/04/24 23:08

解码 XML 和 DTD

编写格式正确和定义明确的 XML 的初学者指南



级别: 初级

Jane Fung, VisualAge for Java 支持, IBM 加拿大

2001 年 7 月 01 日

这 篇介绍性文章说明了如何创建 XML“文档类型定义(DTD)”和格式正确定义明确的 XML 文件,这些文件能够由您选择的 XML 语法分析器进行确认。虽然不必在产生的每个 XML 文件中都包含 DTD,但这样做将会使您的生活大为轻松。DTD 不仅强制使用为 XML 文件建立的语法,它还将允许文件由确认 XML 语法分析器进行语法分析。代码样本包括 DTD 和 XML 文档示例。

“可扩展标记语言”已经存在了十分长的一段时间,因此现在大多数人都熟悉其最基本的需求:所有 XML 文档都必须既格式正确又有效。但如何确定您的 XML 文档是否满足这些需求呢?简短的回答就是您不用确定。或者至少是不必。大多数时候,您会依赖于 XML 语法分析器来为您管理这些苦活。

在经过一些小调查(请参阅 参考资料)后您就会发现市场上到处充斥着 XML 语法分析器,其中大多数都可以从 Web 上免费获得。一个基本的 XML 语法分析器既强调 XML 语法规则(即,确保文件格式正确),又建立文件的有效性。XML 语法分析器可用于几乎每种相关的计算机语言,包括 C、C++、Perl、Python、Tcl 和 Java。

谈到确保 XML 格式正确时,您可以或多或少地指向一个语法分析器然后执行。然而为了确保文档有效,需要为语法分析器提供文档类型定义或 DTD。


本文回顾了 XML 文档格式正确究竟意味着什么,然后会谈到较少讨论的话题确认 - 更具体地说,是 DTD。我将讨论为什么您需要将 DTD 包含在 XML 文件中、介绍一些最常用的 DTD 语法,并使用几个简单的样本来教您开始编写自己的 DTD。

为什么要格式正确?

当 XML 开发人员谈到格式正确和格式不正确的 XML 时,我们并不是参加美学讨论。当然,格式正确的 XML 文档是满足以下三个基本结构需求的文档:

  • 有一个包含所有其它元素的父(或根)元素
  • 每个开始标记都有结束标记
  • 所有元素都正确嵌套的

清单 1 是一个格式正确的 XML 示例。请注意:该文档的父元素是 <person> ,每个开始标记都有一个结束标记,并且每个结束标记都有与其开始标记完全相同的定义。通常,开始标记和结束标记之间包括的是信息或文本。不过,在某些情况下,标记之间没有包括信息或文本。空标记必须用一个右斜杠来结束。 <nothing/> 就是一个空标记。


清单 1. 格式正确的 XML
<person>
<firstname>Jane</firstname>
<lastname>Fung</lastname>
<nothing/>
</person>


清单 2 是一个格式不正确的 XML 示例。它举例说明了三种常见错误。首先,开始和结束 <firstname> 标记没有完全匹配。其次, <lastname> 标记没有结束标记。最后,空标记没有用一个右斜杠结束。


清单 2. 格式不正确的 XML
<person>
<Firstname>Jane</firstname>
<lastname>Fung
<nothing>
</person>







DTD 中有什么内容?

XML 的优点在于它允许您定义自己的有意义的标记,因此您可以最大程度地定制文档。但 XML 就是 XML(可扩展),而人就是人(疯狂的人),这可能很快就会无法控制。解决方案是 DTD,它指定了 XML 文档的标记。简而言之,DTD 指定:可以在文档中存在的元素、那些元素可以具有的属性、在元素内部元素的层次结构以及元素在整个文档中出现的顺序。

虽然 DTD 不是必需的,但它们确实带来方便。DTD 适合三个基本用途。它能:

  • 对标记编制文档
  • 加强标记参数内部的一致性
  • 使 XML 语法分析器能够确认文档

如果不对 XML 文档进行 DTD 定义,文档就无法由 XML 语法分析器进行确认。使用 XML Schema 实例来代替 DTD 如何?(请参阅侧栏 模式如何?)清单 3 是清单 1 中显示的 XML 文档的 DTD。


清单 3. 精简 person.xml 的 DTD
<!ELEMENT person (firstname, lastname)>
<!ELEMENT firstname (#PCDATA)>
<!ELEMENT lastname (#PCDATA)>
<!ELEMENT nothing EMPTY>

关于示例的几点说明

清单 3 中 DTD 的第一行定义了 XML 文档的父元素: person 。person 元素有两个子元素: firstnamelastname

第二和第三行包含了元素属性 #PCDATA ,它表明 firstnamelastname 元素可能包含经过语法分析的字符数据(在这种情况下是文本)。DTD 文件的最后一行描述了一个空标记: nothing

从清单 3 中的 DTD 可以看出,任何阅读我们的 XML 文档的人(以及对它进行语法分析的语法分析器)都知道 person 元素仅包含两个文本元素: firstnamelastname 。此外,DTD 规定,在整个文档中, firstname 元素必须在 lastname 元素之前出现。

在转到更复杂的示例之前,让我们回顾一下一些最常用的 DTD 语法元素。可以在 W3C 主页上找到完整的 DTD 规范(请参阅 参考资料)。







DTD 语法快速指南

A、B、C 和 D 是在下例中代表元素的变量。

元素必须有正好一个 A 、至少一个 B (由加号表示)、零个或多个 C (由星号表示)以及零个或一个 D (由问号表示):

<!ELEMENT element (A, B+, C*, D?)>

元素可能有 ABC 之一:

<!ELEMENT element (A | B | C)>

元素不包含任何内容:

<!ELEMENT element EMPTY>

元素可以包含在 DTD 中列出的任何元素:

<!ELEMENT element ANY>

元素可能包含经过语法分析的字符数据或另一个元素( element2 )。星号(*)表示混合内容模型 — 其中元素可以包含不同类型的属性。

<!ELEMENT element (#PCDATA|element2)*>

下例将文本 "entity reference" 插到文档中它出现的任何地方:

<!ENTITY element "entity reference">

可以看到在 XML 文档中该实体引用元素如下:

&element;

下例表明其元素是一个包含三个属性的空标记:属性 1( att1 )是一个可选属性,属性 2( att2 )是带有固定值 "A" 的属性,属性 3( att3 )是必需的文本属性。

   <!ELEMENT element EMPTY>


<!ATTLIST element
att1 ID #IMPLIED
att2 CDATA #FIXED "A"
att3 CDATA #REQUIRED>



可以看到在 XML 文档中使用的这个元素如下:

<element att2="A" att3="MustHave"/>

属性 CDATA 表示包括的信息应该是文本。 ID 属性表明必须填入唯一的标识。每个元素只能有一个 ID 属性。另外, CDATA 表示 att2att3 可能包含任何字符串。

如果您对该语法还未完全熟悉,请继续阅读。下一部分中的工作示例应该能帮助您消除疑虑。







工作示例

可以使用 Microsoft Internet Explorer 5 或更高版本查看清单 4 中显示的 XML 文档 ― 前面示例中使用的 people.xml 文件的扩展版本。如果在 IE5 中打开 people.xml,应该看到一个树结构。这是因为 IE5 带有能够将 XML 文档语法分析成元素树的 XML 语法分析器。

还可以在 参考资料中找到这个文件及其 DTD。


清单 4. people.xml 的完整清单
<?xml version="1.0"?>
<!DOCTYPE people SYSTEM "people.dtd">
<people>
<person>
<name>
<firstname>Jane</firstname>
<lastname>Fung</lastname>
</name>
<look>good-looking</look>
<possession>
<car>
<model>Civic</model>
</car>
<job>&IBM;</job>
</possession>
</person>
<person>
<name>
<firstname>G.I.</firstname>
<lastname>Jane</lastname>
</name>
<look>tough</look>
<possession>
<house country="CANADA" city="Toronto">
<townhouse townhouse_type="good" />
</house>
<bankaccount bankaccount_number="sg-123">

<![CDATA[<greeting>5000</greeting>]]>
</bankaccount>
</possession>
<other>
<car>she has a car</car>
<house country="CANADA" city="Toronto">
<townhouse townhouse_type="good" />
</house>
</other>
</person>
</people>

关于 XML 的几点说明

对 XML 的深入探讨主要考虑的是文档头中的几个元素,从以下开始:

<?xml version="1.0"?>

每个 XML 文档都必须包含这样的一个头,向 XML 语法分析器表示它是一个 XML 文档。头中的下一行告诉 XML 语法分析器该文档是使用什么字符编码来创建的:

<!DOCTYPE people SYSTEM "people.dtd">

在 Unix 系统上创建的 XML 文档和在 Windows 系统上创建的 XML 文档可能有不同的编码。

还可以为第一行设置可选的 standalone 属性。standalone 的缺省值是 nono 值表示该 DTD 定义是在另一个文件中描述的。 yes 值表明该 DTD 应该在 XML 文档内部定义。我没有为示例设置这个属性;如果想设置,它应该看起来如下:

   <?xml version="1.0" standalone='yes'?>
<!DOCTYPE people [
<!ELEMENT people (person+)>
<!ELEMENT person (#PCDATA)>
]>


还应该注意使这个文档格式正确的方法。例如,所有空标记都用一个右斜杠结束,如下所示:

<townhouse townhouse_type="good" />

还请注意 CDATA 用于对所有若不进行转义就会以 XML 语言解释的任何数据进行转义,例如:

<![CDATA[<greeting>5000</greeting>]]>

如果适当的格式化,这一行将以文本内容显示:

<greeting> 5000 </greeting>

可以从 XML 文件的进一步研究中获益,甚至可能从对您自己的文件运行 XML 语法分析器获益(请参阅 参考资料)。但是现在,让我们看一下 people.xml 文件的 DTD。


清单 5. people.dtd 的完整清单
<!ELEMENT people (person+)>
<!ELEMENT person (name, look*, possession?, other?)>
<!ELEMENT name (firstname, lastname)>
<!ELEMENT firstname (#PCDATA)>
<!ELEMENT lastname (#PCDATA)>
<!ELEMENT look (#PCDATA)>
<!ELEMENT possession (car?, house?, bankaccount?, job?)>
<!ELEMENT car (#PCDATA|model)*>
<!ELEMENT model (#PCDATA)>
<!ELEMENT house (apartment|standalone|townhouse)>
<!ATTLIST house house_area ID #IMPLIED country CDATA #FIXED
"CANADA" city CDATA #IMPLIED>
<!ELEMENT apartment EMPTY>
<!ELEMENT standalone EMPTY>
<!ELEMENT townhouse EMPTY>
<!ATTLIST townhouse townhouse_type ID #IMPLIED>
<!ELEMENT bankaccount (#PCDATA)>
<!ATTLIST bankaccount bankaccount_number ID #REQUIRED>
<!ELEMENT job (#PCDATA)>
<!ELEMENT other ANY>

<!ENTITY IBM "Proud to work for IBM">

关于 DTD 的几点说明

使用 快速指南作为参考,通过比较 XML 文件及其 DTD,您应该能够方便地定义 DTD 和 XML 文件中各元素之间的关系。不过,还有两个剩下的元素,您可能感兴趣。

清单 4 包含了对实体的引用。

<job>&IBM;</job>

实体引用用于代替在 DTD 文档中定义的特定字符或字符串。进行了语法分析后,该实体引用将读作:

<job> Proud to work for IBM </job>

还应该注意, <other> 标记的内容类型是 ANY 。这表示 <other> 可能包含所有以前已在 DTD 中声明过的元素。因此, other 元素可能包含 carhouse 元素,如下:

   <other>
<car>she has a car</car>
<house country="CANADA" city="Toronto">
<townhouse townhouse_type="good" />
</house>
</other>







结束语

这就结束了对创建格式和定义均正确的 XML 文件的基本介绍。您可能想要继续自己研究 people.xml 和 people.dtd 文件。如果想要尝试使用 XML 语法分析器对这些文件进行语法分析,请参阅“参考资料”来查找可供下载的语法分析器的列表。







参考资料

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

  • 如果希望了解有关 XML 和 DTD 语法的更多信息, XML 1.0 W3C Recommendation应该是您的第一站。

  • Tim Bray 是 XML 1.0 规范的原始编辑之一。他维护着 Textuality.com,可以在上面找到他关于 XML、DTD 等内容思想。还可以找到 Lark 和 Larval,Bray 自己的 XML 语法分析器。

  • Doug Tidwell 的 教程:XML 简介展示了对“可扩展标记语言”近乎完整的探讨。

  • 您可能还想要仔细查看 Mark Johnson 在 JavaWorld 上发表的 XML for the absolute beginner一文。

  • 请下载本文示例中使用的 people.xml 和 people.dtd文件,以进一步研究和分析。
XML 语法分析器:简表
  • IBM 的 XML Parser for Java (XML4J),目前是版本 3.1.1,是以 100% 纯 Java 编写的确认 XML 语法分析器。包(com.ibm.xml.parser)包含了对 XML 文档进行语法分析、生成、操纵和确认的类和方法。

  • IBM 的 XML for C++ parser (XML4C) 基于 Apache 的 Xerces-C XML 语法分析器,它是用 C++ 的可移植子集编写的确认 XML 语法分析器。

  • XML::Parser 是 Perl 扩展模块,充当与 expat的接口。

  • TclXML 是全 Tcl 的 XML 语法分析器。

  • Xerces 是来自 Apache Software Foundation 的 Java 语法分析器,目前是版本 1.4.0。

  • Lars Marius Goshol 负责维护作为公众服务的这个详尽的 XML 语法分析器列表和其它 XML 工具。
相关链接
  • 在 XML 专区页面上查看最新信息。

  • 如同 DTD,在创建 XML 文件时,样式表不是必需的,但如果希望控制浏览器中文档显示,它们就非常重要。Alan Knox 的 developerWorks 文章, Style sheets can write style sheets, too,向您介绍如何使用 XSL 来将 XML 数据转换成用于浏览器的复杂显示标记。

  • 阅读完上述文章后,可能想要查看 IBM alphaWorks 的 XSL Editor。

  • 如果希望探索 XML Schema 以及它与 DTD 的关系,请参阅 David Mertz 在其 developerWorks 专栏“XML 问题 7”中的 DTD 和 XML Schema 比较,以及 Kevin Williams 的 developerWorks 临时讲台 赞同使用 XMLSchema 的文章来了解用于数据的 XML 文档的结构化定义。有关使用 XML Schema 会怎样的简短说明,请参阅介绍性文章 Basics of using XML Schema to define elements。






关于作者

author

Jane Fung 目前在 IBM VisualAge for Java 技术支持小组工作,该小组为使用 VisualAge for Java 的企业开发人员提供支持。Jane 获得了加拿大安大略省的沃特卢大学电子工程应用科学学士学位,并且是一名 Sun Java 2 认证程序员。可以通过 jcyfung@ca.ibm.com 与 Jane 联系。