3.4 定义元素
元素类型定义的全称是Elememt Type Definition,简称ETD。ETD不但会定义每个文件中可能存在的元素,给出元素的名字,而且会定义元素的具体类型。XML元素可以为空,可以为文本字符串,可以包含若干子元素,每个子元素又可包含若干子元素。DTD正是通过元素之间的父子关系,描述了整个文件的结构。ETD的语法格式如下:
元素类型描述主要有如下5种:
任意类型:这种元素既可以是字符串,也可以包含其他子元素,还可以是空元素。
字符串值:这种元素只能是字符串,不能包含其他子元素,也不可以是空元素。
空元素:这种元素只能是空元素,既不可以包含子元素,也不可以包含字符串值。
包含子元素:包含子元素的元素比较复杂,因为需要详细定义子元素之间的顺序和子元素出现的次数等。
混合类型:指定XML元素的值只能是几个确定的类型,混合类型是比任意类型更强的约束,但又能提供和任意类型大致相当的功能。
注意
不管是哪种类型的XML元素,都可以添加任意多个属性,即使空元素也可添加一个或多个属性,只是添加属性时必须指定属性值。
3.4.1 定义任意类型的元素
如果需要定义某个元素的值可以是任意类型,可采用如下语法:
看如下XML文档:
从表面上看,上面的文档是份有效的XML文档。因为DTD定义了该XML文档的根元素是“书籍列表”,<书籍列表…/>元素的值可以是任意类型。从这一点上看,该文档的确是有效文档。但DTD中仅定义了一个<书籍列表…/>元素,这意味着该XML文档中不应该包含其他元素。而事实上,该XML文档还出现了相当多的其他元素,因此这份文档依然不是一份有效的文档。
注意
DTD必须定义XML文档中允许出现的所有元素。由此可见,虽然XML文档允许开发者自由扩展各种标签,但一旦使用DTD为其增加了语义约束,该XML文档中就只能出现在DTD中定义过的元素。
而下面的文档则是有效的:
程序清单:codes\03\3.4\any.xml
上述文档的内部DTD定义了文档的<书籍列表…/>元素的值可以是任意类型,且仅定义了一个<书籍列表…/>元素,因此该XML文档中只能包含一个<书籍列表…/>元素,其值可以是任意类型。该XML文档满足此规则,因此是有效的。
不仅如此,由于ANY规则对XML元素几乎没有任何约束,因此下面的XML文档也是有效的:
程序清单:codes\03\3.4\any2.xml
ANY允许元素是空元素。如上所见,如果将一个元素的类型定义为ANY,则对该元素几乎没有任何约束,这与DTD的目的是背离的。DTD的目的是为XML文档提供更详细的语义约束,而使用ANY则不会提供任何有用的约束,显然没有任何效果。因此,应尽量避免使用ANY元素类型定义。
注意
应尽量避免使用ANY规则来定义XML元素,因为ANY规则对XML元素几乎没有任何约束。
3.4.2 定义空元素
空元素的定义非常简单,其语法如下:
对于上面根元素为空的情形,使用如下DTD定义将更加严格而有效:
程序清单:codes\03\3.4\empty.xml
上述XML文档的内部DTD使用EMPTY将<书籍列表…/>元素定义为空元素,而XML文档中的<书籍列表…/>元素也确实是个空元素,因此该文档是个有效的XML文档。
而下面的文档则是无效的:
程序清单:codes\03\3.4\emptyError.xml
上述文档中的<书籍列表…/>元素的值是字符串,而DTD定义了该元素只能是空元素,因而该文档是格式良好但无效的XML文档,而不是有效的XML文档。为了定义某个元素的值必须是字符串,可采用定义字符串内容的ETD语法。
3.4.3 定义字符串内容的元素
定义字符串内容的元素的语法格式如下:
上面的语法定义了元素的值只能是字符串。因而将上面的XML文档改为如下形式,即为有效文档:
程序清单:codes\03\3.4\pcdata.xml
值得指出的是,一旦在DTD中使用(#PCDATA)定义了某个元素的类型,那就意味着该元素的内容只能是字符串,绝不可包含子元素。例如如下XML文档就是无效的:
程序清单:codes\03\3.4\pcdataError.xml
由于上述XML文档里的内部DTD指定了<书籍列表…/>元素的类型为(#PCDATA),这意味着该元素只能包含字符串内容,绝不可包含任何子元素,因此上面的XML文档是无效的XML文档。
3.4.4 定义混合内容
在某些极端的情况下,某个元素既有字符串内容,又包含子元素,这种元素被称为混合内容的元素。一般说来,XML文档不推荐使用混合内容的元素,不过实际使用中还是可以使用混合内容的。DTD也为混合内容的元素提供了支持。
混合内容的ETD语法格式如下:
上面的ETD语法指定了父元素的内容既可以是普通字符串,也可以是各子元素名所指定的子元素。值得指出的是,这里的子元素1、子元素2和子元素3之间的竖线(|)并不是表示互斥,而只是表示这些子元素能无序地重复出现,出现多少次不受限制。
注意
关于上面的语法格式必须注意如下几点:① #PCDATA必须放在最前面。② #PCDATA和各子元素之间只能用竖线(|)分隔,不要试图用逗号分隔,也不要试图将多个子元素合并成组。③ 不要试图在各子元素之后添加?、*、+等表示频率的修饰符。
例如有如下的XML文档:
程序清单:codes\03\3.4\mixed.xml
上述XML文档中的<游戏…/>元素的内容比较复杂,它既可包含字符串内容,又可包含<游戏名称…/>和<游戏类型…/>两个元素,而且这两个元素的出现次数也比较随意。为了保证上面的XML文档有效,可为其定义如下DTD文档:
程序清单:codes\03\3.4\mixed.dtd
该DTD文档定义了<喜欢的游戏…/>元素的内容是混合内容,它可以包含<游戏…/>子元素和字符串内容,而<游戏…/>元素也是混合内容的元素,它可以包含<游戏名称…/>和<游戏类型…/>两个子元素,而且这两个子元素之间的顺序和出现频率没有任何限制。上面的XML文档和该DTD定义的规则完全吻合,因此上面的XML文档是有效的。
注意
前面已经指出,我们应该尽量避免使用ANY规则来定义XML元素,因为ANY规则对XML元素没有任何约束。通常情况下,需要使用ANY规则定义XML元素时,都可以考虑使用混合内容来进行定义,混合内容的语法可以完成ANY规则的定义,又可提供比ANY规则更细致的语义约束。