DTD
DTD是什么?
文档类型定义(Document Type Definition)是一套为了进行程序间的数据交换而建立的关于标记符的语法规则。它是标准通用标记语言和可扩展标记语言1.0版规格的一部分,文档可根据某种DTD语法规则验证格式是否符合此规则。
产生的背景
XML基本语法允许用户随意创建自己的标记,添加元素和属性等,但如果大家都按自己的意愿这么做,产生的XML文档也就失去了共享、交换、理解的价值。因此必须制定一套规则来规范XML文档标记的结构。这就是DTD。
DTD声明的格式
<!DOCTYPE root_node[<!--DTD定义的内容-->]>
三种使用方式
- 直接内装式
- 外部文件式
- 混合式
内装DTD
内装DTD的语法与示例
<?xml version=“1.0” endcoding=“GB2312” standalone=“yes”?>
<!DOCTYPE 持股信息[
<!ELEMENT 持股信息(股东)* >
<!ELEMENT 股东(姓名,浦发银行,华夏基金)>
<!ELEMENT 姓名(#PCDATA)>
<!ELEMENT 浦发银行(#PCDATA)>
<!ELEMENT 华夏基金(#PCDATA)>
]>
<持股信息>
<股东>
<姓名>张志强</姓名>….
外部文件式
外部文档式的示例:
用文本编辑工具建立文件“char01.dtd”,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<!ELEMENT 持股信息(股东)* >
<!ELEMENT 股东(姓名,浦发银行,华夏基金)>
<!ELEMENT 姓名(#PCDATA)>
<!ELEMENT 浦发银行(#PCDATA)>
<!ELEMENT 华夏基金(#PCDATA)>
使用外部文档,在XML中要添加以下声明:
<!DOCTYPE 持股信息 SYSTEM "char01.dtd" >
上述格式中SYSTEM代表此DTD文件由私人制定,假如是国际标准则要用PUBLIC,例如Struts的XML配置:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
DTD元素
元素声明
基本格式
<!ELEMENT 元素名 元素内容模式>
空模式(关键字EMPTY)
<!ELEMENT image(EMPTY)>
在相应的XML文档中对应为:<image/>
任意模式 (关键字ANY):与ANY相对应的元素内容没有任何定义和限制。应注意:ANY类型的元素,其包含的子元素并不能继承父元素的模式类型。ANY的使用将导致XML文档结构的丧失,通常只在创建文档的初期使用。例如,一份描述图书信息的DTD设计
<?xml version=“1.0” endcoding=“GB2312” ?>
<!ELEMENT booklist(book?)>
<!ELEMENT book ANY>
<!ELEMENT author(#PCDATA)>
<!ELEMENT title(#PCDATA)>
混合模式:没有关键字,语法格式:
<!ELEMENT 父元素名(#PCDATA|子元素1|子元素2|…)*>
注意:
1、#PCDATA是指该混合元素的父元素内容可以是字符串,长度不限,但要交XML解析器处理。
2、子元素之间的“|”符号与后面的“*”符号一起表示这些子元素出现的次数与顺序都不受限制
示例:
<!ELEMENT music (#PCDATA | name | singer)* >
另外,附加一些符号说明
符号 | 含义 |
---|---|
+ | 子元素至少要出现一次 |
* | 子元素可出现任意次,包括不出现 |
? | 子元素出现零次或一次 |
? | 子元素有多种选择,但只可以选择其一 |
DTD定义的完整性
(1)不允许无穷嵌套,例如:
<!ELEMENT 商品名称(name,price)>
<!ELEMENT price(商品名称,unit)>
(2)XML文件中的每个标记都必须在DTD中有相应元素进行约束,且必须最终约束数据类型为#PCDATA。
例如:<!ELEMENT 列车时刻表(T28,T29)>
<!ELEMENT T28(hour,minute)>
<!ELEMENT T29(hour,minute)>
这样的DTD不完整,因为还没有约束元素 hour 和 minute。
DTD属性
声明格式
<!ATTLIST 元素名 属性名 属性类型 属性默认值>
以下为XML属性类型
CDATA | 文本字符串。解析器不处理。 |
---|---|
ID | 具有唯一性的属性类型,此属性值在整个XML文档中不可重复。 |
IDREF | 这是其它元素的ID属性值 |
IDREFS | 这是其它元素的ID属性值列表,用空格分隔。 |
ENTITY | 为一个实体。 |
ENTITYS | 用空格分隔的实体。 |
NMTOKEN | Name和Token。是一个关键字的名称 |
NMTOKENS | 用空格分隔的NMTOKEN |
NOTATION | 参考的标记声明。 |
Enumerated | 枚举类型的属性。 |
属性的默认值只有三种:#REQUIRED、#IMPLIED、#FIXED。
#REQUIRED是非空的意思,只要该属性出现就必须有一个具体的取值。
#IMPLIED表示该属性的值可有可无。
#FIXED表示该属性取用引号括越来的具体值。也有使用竖线分隔的具体值,这时属性值取枚举值。
一些例子:
<!ATTLIST 汽车 车牌 CDATA #REQUIRED>
<!ATTLIST 电动车 车牌 CDATA #IMPLIED>
<!ATTLIST 报警电话 号码 #FIXED“110”>
<!ATTLIST 论文 关键字 NMTOKENS #REQUIRED>
XML文档中对应:<论文 关键字=“Agent 进化 协作”>
<!ATTLIST 姓名 性别(男|女)#REQUIRED>
DTD实体
实体机制允许将不同类型的数据并入XML文档中,可以是一段文本、一块数据,甚至一个文件。这样就可以快速地将经常使用的数据插入到XML文档中任何位置。
实体的作用就是用较短的文本替代较长的文本,实现一处修改,处处修改。
实体必须在DTD中声明后才能在其它地方引用。 实体有许多称呼:通用实体、参数实体、内部实体、外部实体、解析实体、未解析实体。下面分别阐述:
内部实体与XML文档在一起,外部实体则存放在其它文件内,通过URL来关联。
通用实体:在XML文档中引用的实体。以“&”开始,以“;”结束。声明格式:
内部通用实体: <!ENTITY 实体名 实体值>
外部通用实体: <!ENTITY 实体名 SYSTEM URL-URI>
DTD标记符号
XML文档只是一个文本文档,它自身无法包容其它类型的数据(理论上允许通过转换编码方式嵌入),如二进制代码、图片、视频、动画等。XML不处理这些数据,而是采用定义符号的方式标识这些数据,必要时再通过关联外部处理程序交由指定的外部程序去处理。
定义符号用途:1、定义未解析实体;2、作为NOTATION类型的属性值。
声明格式如下:
普通符号:<!NOTATION 符号名称 SYSTEM “value”>
公共符号:<!NOTATION 符号名称 PUBLIC “name” “value”>
标记符号值通常有两种形式:1、MIME类型;2、外部程序所在路径。
<!NOTATION gif SYSTEM “ACDSee.exe”>
<!ATTLIST DISPLAY src ENTITY #REQUIRED>
参数实体
这是一种专门用于DTD文件中的实体,在DTD中定义并且只能由DTD文件自身通过实体引用来使用。它以“%”开始,以“;”结束。主要用于简化DTD,方便重用与修改。格式:
<!ENTITY %实体名 实体值>
<!ENTITY % HeadingAlign “left|center|right”>
<!ELEMENT message(Content,Align)+>
<!ELEMENT Content(#PCDATA)>
<!ELEMENT Align(%HeadingAlign;)>
第一行说明所创建的参数实体HeadingAlign是用于保留描述对齐方式的字符串,随后再使用对齐方式就只要用对齐元素Align,用%HeadingAlign代替就行了。参数实体也可以采用外部定义方式,但它只存在于DTD内与关联的XML文档无关。例如:
<?xml version=“1.0” encoding=“gh2312”?>
<!ELEMENT name (#PCDATA)>
<!ELEMENT sex EMPTY>
<!ATTLIST sex value (男|女) “男”>
将上述代码保存为importDtd.dtd,下面是引用它的例子:
<?xml version=“1.0” encoding=“gh2312”?>
<!DOCTYPE students[
<!ENTITY % name SYSTEM “importDtd.dtd”>
<!ELEMENT students (student*)>
<!ELEMENT students(name,sex)>
%name;
]>
<students>
<student> <name>陈晓</name> <sex /> </student>
</students>
三个样例
1.电视节目表DTD
<!DOCTYPE TVSCHEDULE [
<!ELEMENT TVSCHEDULE (CHANNEL+)>
<!ELEMENT CHANNEL (BANNER,DAY+)>
<!ELEMENT BANNER (#PCDATA)>
<!ELEMENT DAY (DATE,(HOLIDAY|PROGRAMSLOT+)+)>
<!ELEMENT HOLIDAY (#PCDATA)>
<!ELEMENT DATE (#PCDATA)>
<!ELEMENT PROGRAMSLOT (TIME,TITLE,DESCRIPTION?)> <!ELEMENT TIME (#PCDATA)>
<!ELEMENT TITLE (#PCDATA)>
<!ELEMENT DESCRIPTION (#PCDATA)>
<!ATTLIST TVSCHEDULE NAME CDATA #REQUIRED>
<!ATTLIST CHANNEL CHAN CDATA #REQUIRED>
<!ATTLIST PROGRAMSLOT VTR CDATA #IMPLIED>
<!ATTLIST TITLE RATING CDATA #IMPLIED>
<!ATTLIST TITLE LANGUAGE CDATA #IMPLIED>
]>
2.报纸文章DTD
“`
2.产品目录DTD
```
<!DOCTYPE CATALOG [
<!ENTITY AUTHOR "John Doe">
<!ENTITY COMPANY "JD Power Tools, Inc.">
<!ENTITY EMAIL "jd@jd-tools.com">
<!ELEMENT CATALOG (PRODUCT+)>
<!ELEMENT PRODUCT (SPECIFICATIONS+,OPTIONS?,PRICE+,NOTES?)>
<!ATTLIST PRODUCT
NAME CDATA #IMPLIED CATEGORY (HandTool|Table|Shop-
Professional) "HandTool"
PARTNUM CDATA #IMPLIED PLANT (Pittsburgh|Milwaukee|Chicago) "Chicago" INVENTORY (InStock|Backordered|Discontinued) "InStock">
<!ATTLIST SPECIFICATIONS WEIGHT CDATA #IMPLIED POWER CDATA #IMPLIED>
<!ELEMENT OPTIONS (#PCDATA)>
<!ATTLIST OPTIONS
FINISH (Metal|Polished|Matte) "Matte"
ADAPTER (Included|Optional|NotApplicable) "Included"
CASE (HardShell|Soft|NotApplicable) "HardShell">
<!ELEMENT PRICE (#PCDATA)>
<!ATTLIST PRICE MSRP CDATA #IMPLIED WHOLESALE CDATA #IMPLIED STREET CDATA #IMPLIED SHIPPING CDATA #IMPLIED>
<!ELEMENT NOTES (#PCDATA)> ]>
<!ELEMENT SPECIFICATIONS (#PCDATA)>
DTD存在的问题:
1、DTD文档采用EBNF语法,相对独立,规则也比较繁琐,其本身不是标记语言,也不符合XML文档标准。
2、DTD的数据类型太简单,元素几乎都声明为#PCDATA,属性类型虽然稍多,但仍缺少常用的整数、日期等。
3、使用DTD的XML文档只能引用一个DTD文件,即DTD不支持命名空间。需要引用多个领域的XML规则时遇到困难。
4、DTD的扩展机制复杂而且较弱,已经不能适应信息环境的不断发展,其功能已显不足。
DTD适用场合:
I、文件是叙述性的,并有混合内容;
II、需要约束标记之间的关系,而非标记本身的内容;
III、需要使用实体;
IV、XML文档的使用者对于使用DTD达成一致。