上面我们提到,一个DTD文档实际上就是元素定义的集合,而元素可能包含属性,也可能不包含属性,就象在C++的一个类中,我们可以有虚函数,也可以没有虚函数。属性可以通过以下的语法进行定义:
<! ATTLIST ElementName
AttributeName Type Default
AttributeName Type Default
…..
>
ATTLIST是一个XML语言的保留字,也可以称为是关键字,就象C++语言中的保留字struct,class,inline等一样。ElementName表示元素的名称,元素的名称相当于程序设计语言中变量的名称,你可以任意取,比如student、teacher、book等等。你要取为ttt、kkk也没关系,只是这种名称不能确切的表示它所代表的意义而已。
一个元素可以包含多个属性,一个属性有三部分构成:属性名称(AttributeName)、属性类型(Type)和属性特点(Default)。AttributeName表示属性的名字,你可以任意取名,比如身高、体重、性别等等。Type表明该属性的类型,就象在C++中我们对一个变量需要指定它的类型(比如int,double,bool等等)。Default表明这个属性的特点,在XML语言中,可以有四种形式:#REQUIRED,#IMPLIED,#FIXED value,defaultvalue。在后面会对这四中形式做详细的说明。
现在我们先来看一下XML所定义的属性类型的种类,见图表:
类型
具体的含义说明
CDATA
这个类型表明该属性只能包含字符数据,比如"strong","23","美女","恐龙"等等
ID
该属性的取值必须是唯一的,就象我们每个人都有的身份证号码一样。在一个文档内两个ID属性的值一定不可以一样。
IDREF,IDREFS
这个属性的值实际上就象C++中的指针一样,它是一个指向文档中其他地方声明的ID值。所以如果具体的文档中该属性的取值和它所指向的ID值不匹配的话,就会返回错误。IDREFS和IDREF类似,但是可以具有由空格分隔的多个引用。
ENTITY,ENTITIES
ENTITY属性的值必须对应一个在文档内部声明的但还没有分析过的实体。ENTITIES属性和ENTITY类似,不同的是它可以包含多个实体,每一个实体之间可以用空格进行分隔。需要注意的是实体包括普通实体、外部实体、参数实体和外部参数实体。一般来说,你可以把实体理解为类似C++中的一个定义,比如在C++中,我们定义一个变量: const MYCOMPANYNAME="BigSoft"以后你就可以在程序中使用变量MYCOMPANYNAME。这里可以把MYCOMPANYNAME当成一个实体来理解。
NMTOKEN,NMTOKENS
NMTOKEN和CDATA非常类似,不同之处在于它是CDATA的一个子集。它所使用的字符必须是字母、数字、句点、破折号、下划线或冒号。NMTOKENS和NMTOKEN类似,不同之处在于它可以包含多个值,每个值之间用空格进行分隔
NOTATION
NOTATION属性的值必须引用在文档中其他地方声明的某个注解的名称
NOTATION(enumerated)
该属性的值必须匹配NOTATION名称列表中的某个名称,比如我们已经存在两个NOTATION,一个为beauty,一个为beast。我们可以定义一个属性类型为NOTATION(beauty|beast)
Enumerated
这个几乎和C++中的枚举变量一样,我们事先定义好一些值,该属性的值必须匹配所列出的这些值。比如现在有值为美丽、泼辣、性感、智慧。该属性的类型就可以表现为(美丽|泼辣|性感|智慧),实际内容文档必须从这些值中取一个。注意值之间用"|"进行分隔
我们看上面的XML的例子,它仅仅用到了两种类型,CDATA和Enumerated,其他的还没有使用。在下面的段落中,我们会陆续介绍这些属性类型的使用,在介绍之前,我们需要详细说明一下Default这个字段。
上面我们已经提到Default这个字段可以包含四种形式,下面的表格对这四种形式进行了详细的介绍:
值
含义
#REQUIRED
用来告诉XML解析程序,该元素的所有实例都必须有该属性的值。就象数据表中某一个字段不允许为空一样。
#IMPLIED
表示如果该元素的实例中没有指定该元素的值的话,就忽略该属性。就象在数据表中某一个字段的值可以为NULL一样。
#FIXED value
表示包含该属性的元素实例必须指定所列出的值,比如一个属性名称为美女:美女 CDATA #FIXED "我的老婆"表示如果在实例中没有列出这个属性的话,解析器依然认为存在美女这个属性,它的值就是"我的老婆"。一般的应用是设计这个属性用来说明这些文档都是由一个DTD来实例化产生的。
Defaultvalue
为属性提供一个默认的值。比如一个属性名称为美女:美女 CDATA "我的老婆"如果在该属性的实例中没有包含这个属性的话,解析器就认为该属性的值就是"我的老婆",如果在该属性的实例中包含了这个属性并赋值了的话,就采用这个赋值。
到现在为止,我们就可以定义任意元素的属性了。
举一个例子用来说明属性类型IDREF/IDREFS的使用,见下面的DTD范例:
<!ELEMENT FAMILY (PERSON+)>
<!ELEMENT PERSON EMPTY>
<ATTLIST PERSON
relID ID #REQUIRED
parentID IDREFS #IMPLIED
name CDATA #REQUIRED
>
注意到这里的parentID的类型为IDREFS,这个表明该属性的值必须在文档中出现过。如果该属性的值没在文档中出现过的话,该文档就属于不规范文档,解析器就不会认为该文档是有效的。
比如下面的文档就是一个不正确的文档。
<FAMILY>
<PERSON relID="P_1" name="Joe">
<PERSON relID="P_2" name="NiEr">
<PERSON relID="P_3" name="MoZi">
< PERSON relID="P_4" parentID="P_1 P_5" name="Violet">
</FAMILY>
原因是parentID中出现了值"P_5",而这个值在没有在文档中出现过。
举一个例子用来说明属性类型NMTOKENS的使用,见下面的DTD(ex02.dtd)范例:
<!ELEMENT PERSON (NAME,FAVOURITY)>
<!ELEMENT NAME (#PCDATA)>
<!ATTLIST NAME
USERID NMTOKENS #REQUIRED
>
<!ELEMENT FAVOURITY (#PCDATA)>
<!ATTLIST FAVOURITY
FAVOURDESC NMTOKENS #REQUIRED
>
下面的文档就是一个不正确的文档:
<?xml version="1.0" encoding="GB2312" standalone="no" ?>
<!DOCTYPE PERSON SYSTEM "ex02.dtd">
<PERSON>
<NAME USERID="JOBS22@#$_tt" />
<FAVOURITY FAVOURDESC="FOOTBALL" />
</PERSON>
因为在USERID这个属性值中包含了NMTOKENS所不允许的字符"@#$"。
下面来说明属性类型ENTITY/ENTITIES的使用
前面我们提到,实体可以分为四种类型:普通实体、外部实体、参数实体和外部参数实体。现在我们通过具体的例子来说明每一种实体的使用。
||||||普通实体
下面的DTD(ex03.dtd)文档定义了一个简单的普通实体:
<!ELEMENT PERSON (NAME,WEALTH)>
<!ELEMENT NAME (#PCDATA)>
<!ENTITY currency "$">
<!ATTLIST NAME
USERID NMTOKENS #REQUIRED
>
<!ELEMENT WEALTH (#PCDATA)>
<!ATTLIST WEALTH
WEALTH_MONEY CDATA #REQUIRED
>
然后在实例文档中,我们就可以引用该实体,一个简单的实例文档如下所示:
<?xml version="1.0" encoding="GB2312" standalone="no" ?>
<!DOCTYPE PERSON SYSTEM "ex03.dtd">
<PERSON>
<NAME USERID="Bill Gates" />
<WEALTH WEALTH_MONEY="¤cy;200" />
</PERSON>
这里currency就是我们定义的一个实体,实际上,它很象在C++语言中通过const定义的变量。事实上在XML语言中,系统已经定义好了一些经常使用的实体,它们可以不经过声明就直接使用,以下是系统已经定义好的实体:
实体
替换文本
&
&
<
<
>
>
"
"
'
,
覫
(任何十六进制数) 由该十六进制数指定的UNICODE字符
Ӓ
(任何十进制数) 由该十进制数指定的UNICODE字符
外部实体
外部实体的概念实际上很简单,比如在上面的例子中,我们的实体定义为:
<!ENTITY currency "$">
这里表示用"$"来代替currency,但是如果currency指代的内容很大很复杂的时候,我们可以用一个外部文件来保存这部分的内容。比如采用如下的代码:
<!ENTITY currency system "http://somewebsite/somecategory/something.xml">
这里表示用文档http://somewebsite/somecategory/something.xml来表示实体currency的具体内容。需要指出的是,这里的something.xml文档必须是一个格式完善的XML文档。
上面就是外部实体的概念。
参数实体
所谓参数实体的概念就是说该实体实际上不是在具体实例化文档中使用,而是在DTD文档内部被使用,比如我们可以定义一个如下的实体:
<!ENTITY %地址 "街道,城市,邮编,国家">
然后可以在DTD内部通过%地址;来引用它,具体例子如下:
<!ELEMENT 联系(人名,电话,%地址;)>
上面就是参数实体的概念。
外部参数实体
外部参数实体和参数实体的关系和外部实体与普通实体的关系一样,也就是说,实体的内容不是在两个"之间表示,而是用一个外部的XML文档来表示,比如:
<!ENTITY %地址 system "http://somewebsite/somecategory/something.xml">
然后可以在DTD内部通过%地址;来引用它。这里%地址;相当于一个普通的元素(ELEMENT),这就是外部参数实体的概念。
关于属性类型Notation的使用
Notation主要是用来表明文档中需要来自外部源的数据,而该数据XML本身是不能进行解析的,比如各种格式的二进制文件(比如图形文件、声音文件等),需要外部的应用程序进行处理。
Notation声明的语法格式如下:
<!NOTATION NAME ExternalID>
需要注意的是NAME必须由字母、数字、句点、破折号或冒号组成,并且第一个字符必须为字母或者是下划线。下面的例子表示GIF图象作为不解析的外部内容。
<!NOTATION gif system "iexplore.exe">
<!ENTITY logo SYSTEM "http://somewebsite/somecategory/something.gif" NDATA gif>
<!-- 这里NDATA表示XML不解析该数据 -->
<!ELEMENT PIC EMPTY>
<!ATTLIST PIC
loc ENTITY #REQUIRED
>
然后,在具体的实例化文档中包含下面一行代码:
<PIC loc="&logo;" />
根据DTD定义,loc属性值是一个不解析的实体。解析器可以根据DTD定义知道这一点,然后它就不对其进行解析,也不会象解析实体一样把它包括到XML文档里面。同时,XML解析器将通知iexplore.exe该引用的存在。
||||||元素介绍
前面讨论了元素的属性的一些语法,这里讨论关于元素本身,元素ELEMENT的语法定义如下:
<!ELEMENT NAME CONTENT>
这里ELELENT是XML语言的关键字,NAME表示元素的名称,CONTENT表示元素的类型。它指定了元素起始标记和关闭标记之间允许包含的东西。CONTENT可以以以下几种形式出现:
CONTENT
解释
EMPTY
如果一个元素的CONTENT被声明为EMPTY的话,表示该元素不能包含任何子元素和文本
ANY
表示该元素其中可以包含任何本身有效的元素内容,也就是说,它能够包含在DTD其他位置已经声明过的元素。
#PCDATA
表明该元素可以包含任何字符数据,但是不能在其中包含任何子元素。假设我们定义元素美女<!ELEMENT 美女 #PCDATA>则下面的实例是正确的:<美女>人是因为可爱而美丽,但是美丽一点也就可爱了<美女>而下面的实例就是错误的:<美女>人是因为<B>可爱<B>而美丽,但是美丽一点也就可爱了<美女>因为在其中包含了子元素<B>。一般如果定义元素的CONTENT为#PCDATA,最好在其中只加入纯文本字符数据。
包含其他类型的元素
最通常的情况是一个元素本身是有其他元素的集合构成的,比如下面的例子:表示运算符号这个元素可以选择加法、减法乘法、除法四个元素中的一个作为它的内容
在前面的一些例子中,大家一定注意到了"|","+","*"等这些符号,这些符号具体的含义及使用见下面的表格:
符号
符号类型
描述
示例
示例说明
()
括号
用来给元素分组
(古龙|金庸|梁羽生),(王朔|余杰),毛泽东
表示古龙,金庸,梁羽生可以选择一个,然后后面王朔,余杰可以选择其一,后面跟毛泽东
|
竖条
表明在列出的对象中选择一个
(男人|女人)
表示男人或者女人必须出现,两者选一
+
加号
表示该对象最少出现一次,可以出现多次
(成员+)
表示成员必须出现,可以出现多个成员
*
星号
表示该对象允许出现任意多次,也可以是零次
(爱好*)
爱好可以出现,多次出现,也可以出现零次,那就是不出现了
?
问号
表示该对象可以出现,但只能出现一次
(菜鸟?)
菜鸟可以出现,也可以不出现,如果出现的话,最多只能出现一次
,
逗号
表示对象必须按指定的顺序出现
(西瓜、苹果、香蕉)
表示西瓜、苹果、香蕉必须出现,并且按这个顺序出现
现在你可以充分发挥你的能力,把所有你看的见摸的着的东西用XML DTD定义它一下,这可是考验你综合和分析能力的大好时候了。