前言
XML允许使用者宣告DTD(Document Type Definition)来指定可以被包含在XML文件中的标签种类。 DTD必须包含在文件的档头(prolog)中,以使XML解析器在一开始执行时便可以知道该份XML文件的格式定义。
基本的 DTD 定义
首先我们建造一个名为 sample.dtd 的档案,然后输入一个XML宣告和注解来做为档案识别,如下所示:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片简报DTD范例 -->
接着,增加下列粗体字部份来定义在"投影片简报"元素中只能够包含名为"投影片"的元素:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片简报DTD范例 -->
<!ELEMENT 投影片简报 (投影片+)>
利用这一行元素宣告我们定义了一个可以包含一或多个"投影片"元素的"投影片简报"元素。在此读者们可以看到,一个元素的宣告格式为"<!ELEMENT"启始符号加上我们所要指定的标签名称("投影片简报"),然后再以刮弧方式加入允许在指定的标签名称("投影片简报")中存在的元素名称("投影片")及数量,最后使用">"来结束元素的宣告。
如果我们在这一行元素宣告中未加上"+ "符号,这将会导致"投影片简报"只能含有单一个"投影片"元素。 (表一)中列出我们可以使用来定义元素数量的qualifier(限定词)。
Qualifier(限定词) 名称 所代表意义
? 问号 可选择的 (零或一)
* 星号 零或多个
+ 加号 一或多个
我们可以在一个刮弧之内以逗点做为分隔符号来允许一个元素包含多个子元素,并且在每个子元素后面加上一个qualifier(限定词)来宣告每个子元素可以出现的次数。以逗点分隔的元素列表代表了哪一些元素是允许被使用以及他们可以出现的顺序。
定义Text和Nested元素
接下来,增加下面粗体字部分来定义"投影片"、"标题"和"项目"元素:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片简报DTD范例 -->
<!ELEMENT 投影片简报 (投影片+)>
<!ELEMENT 投影片 (标题, 项目*)>
<!ELEMENT 标题 (#PCDATA)>
<!ELEMENT 项目 (#PCDATA | 项目)*>
在我们所增加的第一行宣告中叙述了每一个"投影片"元素中必须含有一个名为"标题"的元素,而且在"标题"元素之后可以含有零或一个名为"项目"的元素。第二行宣告则叙述一个"标题"元素包含了可被解析的文字资料parsed character data(PCDATA),也就是一般所谓的纯文字(text),但是在XML中它被称之为"parsed character data "。 PCDATA字串前所使用的"#"代表其接下来的字串(在此为PCDATA)有其特别的意义,而非一个元素名称。
最后一行宣告中采用了一个直条符号"|",来表示一个"or"条件。在笔者所使用的范例中,这一个"or"条件表示"项目"元素中可以存有PCDATA或者是另一个名为"项目"的元素。在结尾的"*"(星号符号)则代表它可出现零或一次以上。我们可以称这个规格的结果为一个mixed-content model(混合内容的模型),因为任何数目的"项目"元素均可以与纯文字(text)一起散布。 这样的模型首先必须定义#PCDATA叙述,接着使用直条符号"|"来分隔其他的项目,最后在结尾加上一个星号(*)。
定义DTD里的属性
到这里为止,笔者已经为各位示范了如何定义一份可使用来叙述XML文件的DTD。但是由于到目前所完成的DTD只叙述了XML文件内容应出现的位置,因此,这份DTD将只适合被nonvalidating语法解析器来使用。要让validating语法解析器能够使用这一份DTD,我们将需要为各个不同的元素增加有效属性的叙述。
首先我们增加定义"投影片简报"元素属性的DTD,如下列所示:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片简报DTD范例 -->
<!ELEMENT 投影片简报 (投影片+)>
<!ATTLIST 投影片简报
标题 CDATA #REQUIRED
日期 CDATA #IMPLIED
讲师 CDATA #REQUIRED
>
<!ELEMENT 投影片 (标题, 项目*)>
<!ELEMENT 标题 (#PCDATA)>
<!ELEMENT 项目 (#PCDATA | 项目)*>
如同前面介绍过的元素宣告保留字ELEMENT一样,ATTLIST标签为DTD使用来定义一连串属性的启始符号。跟随在ATTLIST后面的则为包含这些被定义属性的元素名称。在上面的范例中,这个元素为"投影片简报"。
元素中的每一个属性是由一连串的三个分隔数值所定义而成。这三个数值是不允许使用逗点或其他的符号来分隔的,因此,如果将这些属性定义如上面范例中的格式来排列显示将增加文件的可读性。在每一行属性定义里的第一个元素代表的是属性的名称,在此依序分别为: "标题"、"日期"及"讲师"。第二个元素所象征的则是各属性的资料类型: CDATA代表其内容为文字类型、未解析的(unparsed)资料。笔者在(表二)中为各位介绍可选择使用的各属性类型。
属性类型 叙述说明
(value1 | value2 | ...) 使用直条符号"|"分隔的数值列表 (范例如后)
CDATA 文字字串资料 (Unparsed character data)
ID 一个没有其他ID属性分享的名称
IDREF 一个参照到相同文件中不同位置的ID索引
IDREFS 一个使用空格来分隔,包含一或多个ID索引的列表
ENTITY 定义在DTD中的实体名称
ENTITIES 一个使用空格来分隔的实体名称列表
NMTOKEN 一个由字母、数字、连字号、底线和冒号组成的有效XML名称
NMTOKENS 一个使用空格来分隔的名称列表
NOTATION DTD使用来描述一个非XML资料格式的叙述记号名称,例如:影像档
当所有可利用的属性类型被包含在括弧内并以直条符号分隔时,这表示此一个属性的数值将必需为括弧中的任何一种已定义的数值型态。举例来说,当我们增加下列粗体字定义到DTD:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片简报DTD范例 -->
<!ELEMENT 投影片简报 (投影片+)>
<!ATTLIST 投影片简报
标题 CDATA #REQUIRED
日期 CDATA #IMPLIED
讲师 CDATA #REQUIRED
>
<!ELEMENT 投影片 (标题, 项目*)>
<!ATTLIST 投影片
型态 (管理 | 技术 | 全部) #REQUIRED
>
<!ELEMENT 标题 (#PCDATA)>
<!ELEMENT 项目 (#PCDATA | 项目)*>
这一个新增加的定义表示"投影片"元素的"型态"属性必需设定为: 型态="管理"、型态="技术"或是型态="全部"。所有其他的型态数值均是不被接受的设定。
属性定义里的最后一个项目叙述此一属性的预设值,而且告知此属性是否是必要的。 (表三)中列出目前所有可被选择使用的属性预设值。
规格 叙述说明
#REQUIRED 该元素必须要设定该属性的属性值
#IMPLIED 该元素不一定要设定该属性的属性值。
如果它未被叙述定义,应用程式将会使用预设的数值。
"defaultValue" 一个没有其他ID属性分享的名称
#FIXED "fixed Value" 一个参照到相同文件中不同位置的ID索引
让XML文件参照DTD
在笔者的范例中,DTD定义与XML文件是分开储存于各别的档案中。我们可以增加下面粗体字部份到需要使用DTD的XML文件sample.xml(内容如下所列)中,使解析器在解析它时能参照到我们刚刚建立的DTD格式定义档案sample.dtd:
<?xml version='1.0' encoding='Big5'?>
'
<!-- XML投影片简报格式示范 -->
<投影片简报 标题="简短的投影片简报" 日期="简报日期" 讲师="王泳泰">
<!-- 投影片 标题 -->
<投影片 型态="全部">
<标题>XML应用</标题>
</投影片>
<!-- 投影片 概观 -->
<投影片 型态="全部">
<标题>概观</标题>
<项目>何谓 <em>XML</em>? </项目>
<项目/>
<项目><em>产业</em>XML化</项目>
</投影片>
</投影片简报>
在上列加入的指令中,"<!"为DTD标签的启始符号。接着,标签名称DOCTYPE叙述此文件为一份"投影片简报",其意思表示此文件的根元素名称为"投影片简报"以及所有其他资讯(例如:"投影片"元素)均包含在这个根元素"投影片简报"之内:
<投影片简报>
...
</投影片简报>
DOCTYPE标签必须撰写在XML档案宣告之后及根元素之前。而SYSTEM识别符号则是用来叙述DTD档案所在的位置。由于它的起头并不是http:/ 或 file:/,因此其路径将连结到与XML文件相同的目录位置中。另外,一个PUBLIC识别符号也能够被使用来替代SYSTEM识别符号,PUBLIC识别符号将允许我们以unique name(唯一名称)来叙述DTD档案的位置。
DOCTYPE规格并且也能够让使用者将DTD定义直接包含在所需的XML文件中,如此我们将无须再参照XML文件到外部的DTD档案。这样的定义将需要被撰写在square brackets(正方形括弧)中,其架构如下:
...这里是DTD定义所撰写位置...
]>
如果我们将上面的外部DTD范例修改为内部DTD,其格式架构将如下所示(下列粗体字部分为我们所自订的DTD内容):
<?xml version='1.0' encoding='Big5'?>
<!DOCTYPE 投影片简报 [
<!-- XML投影片简报DTD范例 -->
<!ELEMENT 投影片简报 (投影片+)>
<!ATTLIST 投影片简报
标题 CDATA #REQUIRED
日期 CDATA #IMPLIED
讲师 CDATA #REQUIRED
>
<!ELEMENT 投影片 (标题, 项目*)>
<!ATTLIST 投影片
型态 (管理 | 技术 | 全部) #REQUIRED
>
<!ELEMENT 标题 (#PCDATA)>
<!ELEMENT 项目 (#PCDATA | 项目)*>
]>
<!-- XML投影片简报格式示范 -->
<投影片简报 标题="简短的投影片简报" 日期="简报日期" 讲师="王泳泰">
<!-- 投影片 标题 -->
<投影片 型态="全部">
<标题>XML应用</标题>
</投影片>
<!-- 投影片 概观 -->
<投影片 型态="全部">
<标题>概观</标题>
<项目>何谓 <em>XML</em>? </项目>
<项目/>
<项目><em>产业</em>XML化</项目>
</投影片>
</投影片简报>
结论
在介绍了DTD符号的使用方法之后,我们就可以开始试着为自己的XML文件定义DTD,这时您将会实际体验到DTD的实用性。