3.1. 文档类型声明
要使用DTD进行有效性检验,就要使用文档类型定义声明指定DTD。如:
<?xml version="1.0" standalone="no"?><!DOCTYPE portal SYSTEM "http://www.w3c.com/dtd/portal.dtd"><portal> <name>Jims</name> <email>Jims@163.com</email> <email>Jims@21cn.com</email></portal>
文档类型声明位于XML声明之后,根元素之前。如果dtd文档位于本机,可用路径名直接指出dtd文档的位置。portal.dtd的内容如下:
<!ELEMENT portal (name,email*)><!ELEMENT name (#PCDATA)><!ELEMENT email (#PCDATA)>
上面的内容也可直接写到XML文档内,这种dtd声明方式叫内部dtd子集,如:
<?xml version="1.0" standalone="no"?><!DOCTYPE portal [<!ELEMENT portal (name,email*)><!ELEMENT name (#PCDATA)><!ELEMENT email (#PCDATA)>]><portal> <name>Jims</name> <email>Jims@163.com</email> <email>Jims@21cn.com</email></portal>
如果dtd位于XML文档外,则叫外部dtd子集。我们可以结合内外dtd,共同组成一个dtd来为XML文档作验证。如:
<!DOCTYPE portal SYSTEM "external.dtd" [<!ELEMENT portal (name,email*)><!ELEMENT name (#PCDATA)><!ELEMENT email (#PCDATA)>]>
注意,使用内外dtd时,这两个dtd要互相兼容,不能有冲突。
上节文档类型声明中的每一项都是元素声明,定义了每个元素的约束。元素声明的格式为:
<!ELEMENT element_name (content_model)>
有效文档中使用的每个元素都必须在文档的DTD中用元素声明进行声明。element_name可是任何合法的XML名称,content_model(内容模型)指定元素可以或必须包含的子元素以及子元素的顺序。下面具体介绍内容模型的内容。
-
#PCDATA,规定元素只包含已析的字符数据。下面声明指出一个name元素可以包含文本,但不能划分为独立的area_code、number和extension元素:
<!ELEMENT name (#PCDATA)>
-
子元素,可指明元素的子元素。下面声明表示name元素必须包含且只包含一个desc元素。
<!ELEMENT name (desc)>
也可用逗号为分隔符,指明多个子元素。并且子元素出现的次序必须按定义时的顺序。如:
<!ELEMENT name (id,desc)>
name元素的id子元素必须在desc子元素前面,否则验证会出错,该文档不是一个有效的XML文档。
下面这个文档是有效的<name> <id>1</id> <desc>dtd test</desc></name>下面这个文档是无效的,顺序颠倒了<name> <desc>dtd test</desc> <id>1</id></name>下面的文档也是无效的,有多余的元素<name> <id>1</id> <desc>dtd test</desc> <date>2005/01/31</date></name>
-
子元素的个数,我们可通过正则表达式来规定子元素的个数。
-
?,允许零个或一个该元素
-
*,允许零个或多个该元素
-
+,允许一个或多个该元素
下面我们可利用这些符号规定id子元素必须出现,且只能出现一次,而desc子元素可选。
<!ELEMENT name (id,desc*)>
根据上面的声明,下面的name元素都是有效的。
<name> <id>1</id> <desc>dtd test</desc></name><name> <id>2</id></name><name> <id>3</id> <desc>dtd test</desc> <desc>another test</desc></name>
-
-
可选项(|),选项是一个参数列表,每个参数间用“|”分隔,代表能且只能选一个子元素。
<!ELEMENT choice (good | bad)>
上例的choice元素可选一个good子元素,或bad子元素,且只能从选一个。可选的参数列可以多项,不限于两项。如:
<!ELEMENT choice (one | two | three | four)>
-
小括号,可用小括号把选项括起来,以表达更丰富的意思,如我们想表示choice元素必须包含一个good子元素,并且必须包含ok子元素或bad子元素的一个。
<!ELEMENT choice (good,(ok|bad))>
-
混合内容,在一些文档中,一个元素可能既包含子元素,也包含字符串,这些内容叫混合内容。可用以下方式表示:
<!EMEMENT description (#PCDATA | term)* )>
该声明表示description元素可包含已析的字符串和term子元素,且允许出现零次或多次,如:
<description>this is a <term>dtd</term> test.</description>
#PCDATA必须在第一位,可选的子元素可任意多项。
-
空元素,某些元素不用包含任何内容,称之为空元素。写成以/>结束的独立标签。
<!ELEMENT image EMPTY>
示例:
<image src="http://www.xml.com/dtd.jpg" />
-
ANY,允许元素内包含任意内容。该选项在dtd测试时很有用,在生产系统中尽量不要使用。
<!ELEMENT page ANY>
一个有效的XML文档,必须对元素的属性进行声明。使用ATTLIST声明来完成,一个ATTLIST可以为一个元素类型声明多个属性。
<!ATTLIST image src CDATA #REQUIRED>
上例声明image元素必须有一个src属性,该属性的值是字符数据。可用ATTLIST声明为一个元素声明多个属性,如:
<!ATTLIST image src CDATA #REQUIRED width CDATA #REQUIRED height CDATA #REQUIRED alt CDATA #IMPLIED>
上述声明指出src、width、height属性是必须的,alt属性是可选的。
-
CDATA类型属性值可包含任意文本字符串。DTD不能指定属性为一个整数或一个日期,Schema能提供更为强大的数据类型。
-
NMTOKEN类型属性值是一个XML名称记号。XML名称记号与XML名称类似,但XML名称记号允许所有的字符作为名称的开始字符,而XML名称的第一个字母必须是字母、表意字符和下划线。因此10,.bashrc是合法的XML名称标记,但不是合法的XML名称。每个XML名称都是一个XML名称标记,然而XML名称标记不全是XML名称。如果属性包含1990,2005之类的整数,则应该指定其类型为NMTOKEN。如:
<!ELEMENT person birthday NMTOKEN #REQUIRED>
-
NMTOKENS类型属性包含一个或多个用空白分隔的XML名称记号。如:
<person dates="02-01-2005 03-01-2005 05-01-2005">person</person>
对应的声明应为:
<!ATTLIST person dates NMTOKENS #REQUIRED>
另一方面,对01/02/2005这样的形式不能使用该声明,因为其中的正斜杠不是合法的名称字符。
-
枚举声明,枚举不用关键字。直接列举所有的值,中间用竖线分隔。如:
<!ATTLIST date month(January | February | March | April | May | June | July | August | September | October | November | December) #REQUIRED>
针对上述声明,date元素的month属性可选十二个月份的中一个。
-
ID类型的属性必须包含一个XML名称,而且该名称在文档中是独一无二的。ID属性可为元素分配一个唯一的标识符。
<!ATTLIST name card_id ID #REQUIRED>
由于数字不是合法的XML名称,所以ID编号不能以数字开头,解决办法是在前面加下划线或字母。
-
IDREF类型的属性指向文档中某元素的ID类型的属性。因此,它必须是一个XML名称,它的作用是当简单的包含关系不能满足要求时在元素间建立多对多关系。如:
<project project_id="p1"> <goal>deploy linux</goal> <team_member person_card_id="c123"></project><person card_id="c123"> <name>linuxsir</name> <assignment project_project_id="p1"></person>
project元素的project_id属性和person元素的card_id属性应该是ID类型。team_member元素的person_card_id属性和assignment元素的project_project_id属性是IDREF类型。对应的声明如下:
<!ATTLIST person card_id ID #REQUIRED><!ATTLIST project project_id ID #REQUIRED><!ATTLIST team_member person_card_id IDREF #REQUIRED><!ATTLIST assignment project_project_id IDREF #REQUIRED>
-
IDREFS类型的属性包含一个XML名称列表。名称间用空白间隔,且每个名称都是文档中某个元素的ID。当某个元素需要引用多个其他元素时使用该元素。如:
<!ATTLIST person card_id ID #REQUIRED assignment IDREFS #REQUIRED><!ATTLIST project project_id ID #REQUIRED team IDREFS #REQUIRED>
对应的文档可写成:
<project project_id="p1" team="c123"> <gold>deploy linux</gold></project><person card_id="c123" assignment="p1"> <name>Linuxsir</name></person>
-
ENTITY类型的属性包含在DTD的其它位置声明的未析实体的名称中。如movie元素可能有一个标识激活时播放mpeg或rm文件的实体属性:
<!ATTLIST movie src ENTITY #REQUIRED>
如果DTD声明了一个名为play的未析实体,则此movie元素可用于在XML文档中嵌入视频文件:
<movie src="play" />
-
ENTITIES类型的属性包含在DTD的其它位置声明的多个未析实体名称,其间用空白隔开。
<!ATTLIST slide_show slides ENTITIES #REQUIRED>
如果DTD声明了未析实体slide1、slide2、slide3、...,则可使用slide_show元素在XML文档中嵌入幻灯片。
<slide_show slides="slide1 slide2 slide3" />
-
NOTATION类型的属性包含在文档的DTD中声明的某个记法的名称。该属性类型较少用。理论上,可以使用该属性使某些特殊元素与类型相关联,下例声明为不同的图像类型定义了4个记法,然后规定每个image元素都必须从中选择一种type属性。
<!NOTATION gif SYSTEM "image/gif"><!NOTATION tiff SYSTEM "image/tiff"><!NOTATION jpeg SYSTEM "image/jpeg"><!NOTATION png SYSTEM "image/png"><!ATTLIST image type NOTATION (gif | tiff | jpeg | png) #REQUIRED>
每个image元素的type属性的值可以为gif,tiff,jpeg和png四个值中的一个。该属性比枚举类型稍具优势,因为记法的实际MIME媒体类型在理论上是可用的。由于斜杠在XML名称中不是一个合法字符,所以枚举类型不能指定image/png或image/jpeg作为允许值。
-
用ENTITY声明定义实体。如:
<!ENTITY linux "linux is a very good system">用&linux;可引用该字符串
-
可定义一个外部实体,引用外部XML文档
<!ENTITY linux SYSTEM "/home/linux/test.xml">使用&linux;可引用/home/linux/test.xml文档
外部实体没有XML声明,但可以有文本声明,两者很类似,主要区别是文本声明必须有编码声明,而版本信息则是可选的。
<?xml version="1.0" encoding="gb2312"?> 是一个合法的文本声明<?xml encoding="gb2312"?> 也是一个合法的文本声明
-
不是所有的数据都是XML。如jpeg照片,mpeg电影等。XML建议使用外部未析实体作为在文档中嵌入这些内容的机制。DTD为包含非XML数据的实体指定一个名称和URI。
<!ENTITY movie SYSTEM "/home/linux/test.avi" NDATA avi>
由于数据不是XML格式,所以使用NDATA声明指定数据类型。avi是在NOTATION中定义的MIME媒体类型。在XML中嵌入未析实体很复杂且不规范,尽量不要使用。
-
参数实体可定义一组通用的实体,在文档中可通过该参数实体来引用实体。参数实体的定义与通用实体定义类似,只是中间多了一个%,引用时也是用%代码&。
<!ENTITY % person "name,address,postcode">引用方法%person;这样会用name,address,postcode代替参数实体%person;
-
通常DTD都比较大,DocBook的DTD长达11000多行,如果把它存放在单一文件中,管理和维护起来都非常困难。我们可以使用外部DTD子集,把一个大的DTD按功能分成不同的功能块,存放在不同的文件中。再通过外部参数实体声明引入当前DTD中,如:
定义参数实体引用外部names.dtd<!ENTITY % names SYSTEM "names.dtd">调用外部DTD子集%names;
-
使用IGNORE关键字可注释声明,如:
<![IGNORE[ <!ELEMENT note (#PCDATA)>]]>
当然了,使用<!-- 注释 -->的方式也是一样的。
-
INCLUDE关键字表示DTD中的确在使用给定的声明,如:
<![INCLUDE[ <!ELEMENT note (#PCDATA)>]]>
单从该声明来看,有没有使用INCLUDE效果都一样,但如果组合INCLUDE和IGNORE,可实现DTD功能的选择。我们可定义一个参数实体:
<!ENTITY % note_allowed "INCLUDE" >
然后使用参数实体引用而不使用关键字:
<![%note_allowed;[ <!ELEMENT note (#PCDATA)>]]>
按上述操作,元素声明是有效的,但我们也可以把参数实体%note_allowed重新定义为IGNORE,这样,该元素声明就无效了。
my simple example:
.DTD文件
<!--ELEMENT聲明 ===>對元素進行聲明,一個元素可包含多個子元素
ATTLIST聲明===>對元素的屬性進行聲明,一個元素可包含多個屬性
? :表示允許 0個或1個 該元素
* :表示允許 0個或多個 該元素
+ :表示允許 1個或多個 該元素
-->
<!--有4個子元素-->
<!ELEMENT Family (Person, Furniture, Pet)>
<!ELEMENT Person (#PCDATA)>
<!ELEMENT Furniture (#PCDATA)>
<!ATTLIST Family
type CDATA #REQUIRED
>
<!--有3個屬性-->
<!ATTLIST Person
UserName CDATA #REQUIRED
Sex CDATA #REQUIRED
Age CDATA #REQUIRED
>
<!ATTLIST Furniture
Name CDATA #REQUIRED
Number CDATA #REQUIRED
Description CDATA #REQUIRED
>
<!--有1個屬性-->
<!ELEMENT Pet (#PCDATA)>
.xslt文件
<?xml version="1.0" encoding="big5"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="big5" indent="yes"/>
<xsl:template match="/">
<html>
<head><title>My XML SPY教程</title></head>
<body><xsl:apply-templates/></body>
</html>
</xsl:template>
<xsl:template match="Family">
Family
<table>
<tbody>
<tr>
<td>Person</td>
<td>Furniture</td>
<td>Pet</td>
</tr>
<tr>
<td><xsl:value-of select="Person"/></td>
<td> <xsl:value-of select="Furniture"/></td>
<td><xsl:value-of select="Pet"/></td>
</tr>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
.XML文件
<?xml version="1.0" encoding="Big5"?>
<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by KELLY (SS) -->
<!DOCTYPE Family SYSTEM "D:/My xml/myDTD1.dtd">
<?xml-stylesheet type="text/xsl" href="D:/My _fcksavedurl=""D:/My" _fcksavedurl=""D:/My" _fcksavedurl=""D:/My" xml/myXSLT1.xslt"?>
<Family type="">
<Person UserName="Kell" Sex="Femail" Age="20">Kell</Person>
<Furniture Name="Computer" Number="2" Description="Good">Computer</Furniture>
<Pet>Dog</Pet>
</Family>