DTD简介
DTD(Document Type Definition,文档类型定义)的作用是定义XML文档的合法构建模块。DTD使用一系列的合法构成成员来定义文档结构。
DTD构成
DTD可以在XML文档中直接写入,也可以单独形成文档。因此,DTD分为外部DTD和内部DTD两种。外部DTD就是已经编辑好的可以被不同的XML文档共享和调用的DTD,内部DTD就是在XML文档中直接设定DTD。
文档类型声明以<!DOCTYPE 为开始,以 ]> 结束。通常将开始和结束放在不同的行上,文档类型定义的内部子集(即内部DTD)的语法格式为:
<!DOCTYPE 根元素名称[
<!ELEMENT 子元素名称 (#PCDATA)>
]>
- <!DOCTYPE :关键字,表示定义DTD,必须大写
- 根元素名:一个XML文档只有一个根元素。如果XML文档使用DTD,那么文档中的根元素名就在内部子集中指定。
- <!ELEMENT 子元素名称 (#PCDATA)>:定义文档的构成元素
例:编写一个包含两个员工信息的简单XML文件,接着定义相应的DTD文件,并在XML中添加引用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 员工[
<!ELEMENT 员工 (李亮,张合) >
<!ELEMENT 李亮 (性别,出生日期) >
<!ELEMENT 张合 (性别,出生日期) >
<!ELEMENT 性别 (#PCDATA) >
<!ELEMENT 出生日期 (#PCDATA) >
]>
<员工>
<李亮>
<性别>男</性别>
<出生日期>1993.1.1</出生日期>
</李亮>
<张合>
<性别>男</性别>
<出生日期>1992.1.1</出生日期>
</张合>
</员工>
元素声明
元素是XML文档的核心部分,声明的语法格式如下:<!ELEMENT 元素名 EMPTY/(子元素内容)/(混合内容)/ANY/#PCDATA >
- !ELEMENT:关键字
- 元素名:文档中根元素下所包含的子元素名称,在DTD中通常称为基本表示符
元素声明分类
常见的元素类型有五种,但元素声明的种类不止五种,具体分类如下:
- 声明空元素
空元素使用EMPTY来定义,改元素只能有属性而不会有字符数据或子元素,语法如下:
<!ELEMENT 元素名 EMPTY>
例如:<!ELEMENT 员工 EMPTY>
- 声明只有PADATA(字符数据)的元素
PCDATA类型的元素不包含其他任何元素,只包含字符数据(即文本数据)的元素,语法如下:
<!ELEMENT 元素名 (#PCDATA)>
- 声明可以包含任何内容的元素
包含任何内容的元素声明类型为ANY,可以包含任何可解析数据的组合,如DTD中定义的其他任何元素或已编译的字符数据,包括PCDATA、元素或元素和PCDATA的混合内容,语法如下:
<!ELEMENT 元素名 ANY>
- 声明带有子元素的元素
父元素声明用于指定某个元素可以包含哪些子元素以及出现次序,语法如下:
<!ELEMENT 元素名 (子元素列表)>
根据子元素间的关系,子元素内容模型可以有两种可能的结构:序列和选择。
(1)序列
序列结构用于描述根元素下,必须要出现的子元素,如下所示:
<!ELEMENT 员工 (姓名,性别)>
(2)选择
选择结构定义了根元素下的可选元素。如下所示:
<!ELEMENT 出行 (步行|公交)>
该声明表示根元素出行必须包含子元素公交或子元素步行,但不能同事包含两个。
- 声明子元素
- 声明只出现一次的元素
- 声明至少出现一次的元素
- 声明混合类型元素
元素指示符
元素的频率即出现的次数使用加号“+”、星号“*”、问号“?”来指定,其表示如下:
在DTD中,属性声明使用ATTLIST属性列表声明指定元素的属性列表,语法如下:
字符 | 出现次数 |
+ | >=1 |
* | >=0 |
? | 0或1 |
- 声明只出现一次的元素
<!ELEMENT 元素名称 (子元素名称)>
- 声明至少出现一次的元素
<!ELEMENT 元素名称 (子元素名称+)>
- 声明出现零次或多次的元素
<!ELEMENT 元素名称 (子元素名称*)>
- 声明出现零次或一次的元素
<!ELEMENT 元素名称 (子元素名称?)>
- 声明混合型的内容
<!ELEMENT note (#PCDATA|to|from|hrader|message)*>
属性
<!ATTLIST 元素名 属性名 属性类型 属性限定条件>
属性类型 | 含义 |
CDATA | 字符数据,即没有标记的文本 |
枚举 | 被选属性值的值列表 |
ID | 该属性在文档中具有唯一性 |
IDREF | 文档中元素的ID类型属性的值 |
IDREFS | 由空格分隔的元素的多个ID |
ENTITY | 在DTD中声明的实体的名称 |
ENTITIES | 在DTD中声明的由空格分隔的多个实体的名称 |
NMTOKEN | XML名称标记 |
NMTOKENS | 由空格分隔的多个XML名称标记 |
NOTATION | 在DTD中声明的记法的名称 |
属性附加声明:
属性默认值 | 含义 |
#REQUIRED | 元素的每个实例必须具有该属性 |
#IMPLIED | 元素实例不需要包含该属性 |
#FIXED+固定值 | 属性值被指定为固定值,用户不能改变该属性值 |
默认值 | 如果元素中不包含该属性值,那么默认值将作为属性值 |
例如:声明指定name元素具有id属性,该属性的类型为CDATA,每个name实例元素必须具有id属性
<!ATTLIST name id CDATA #REQUIRED>
DTD引用
引用内部DTD
前面介绍,均使用内部DTD
引用外部DTD
使用外部DTD时,要在DOCTYPE中使用SYSTEM或PUBLIC关键字,来指定外部DTD位置。
- 使用SYSTEM关键字主要用于引用一个作者或组织所编写的众多XML文化中通用的DTD文件
- 使用PUBLIC关键字引用外部DTD文件的基本语法格式中DTD-URL被称为FPI(正式公用标识符),也称作实体的“publicId”
除了使用
SYSTEM和PUBLIC指定外部DTD的位置以外,XML中需要以standalone="no"来表示该文档引用的是外部DTD
例如:定义一个DTD文件和XML文件,来描述水果和季节的信息
(1)定义DTD文件xmldtd.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT 水果与季节 (季节+,水果+) >
<!ELEMENT 季节 (#PCDATA) >
<!ATTLIST 季节 id ID #REQUIRED >
<!ATTLIST 季节 名称 CDATA #REQUIRED >
<!ELEMENT 水果 (#PCDATA) >
<!ATTLIST 水果 f_id IDREF #REQUIRED >
<!ATTLIST 水果 名称 CDATA #REQUIRED >
(2
)定义对应的XML文件标记,并引用上述DTD文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 水果与季节 SYSTEM "xmldtd.dtd">
<水果与季节>
<季节 id="f1" 名称="春天"></季节>
<季节 id="f2" 名称="夏天"></季节>
<水果 f_id="f1" 名称="草莓"></水果>
<水果 f_id="f2" 名称="西瓜"></水果>
</水果与季节>
混合引用DTD
如果XML文件同时带有内部DTD和外部DTD文件,那么XML解析器会将二者合一。语法如下
<!DOCTYPE 根标记名 SYSTEM "URI" [
内部DTD内容
]>
或
<!DOCTYPE 根标记名 PUBLIC FPI "URI" [
内部DTD内容
]>
将上述实例保持DTD不变,修改其XML文件,同时使用内部和外部DTD,增加水果元素的属性:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 水果与季节 SYSTEM "xmldtd.dtd" [
<!ATTLIST 水果 性味 CDATA #REQUIRED>
]>
<水果与季节>
<季节 id="f1" 名称="春天"></季节>
<季节 id="f2" 名称="夏天"></季节>
<水果 f_id="f1" 名称="草莓" 性味="性凉"></水果>
<水果 f_id="f2" 名称="西瓜" 性味="性寒"></水果>
</水果与季节>
实体声明与引用
普通实体
实体基本意思是指与XML文档相关的存储单元。根据实体内容与DTD的包含关系可以将实体分为内部实体和外部实体。
内部实体是实体的内容已经包含在DTD文件本身中,如下所示:
<!ENTITY hello "How are you,& 你好">
该实体的内容是“How are you,& 你好”。
外部实体的内容是通过URI引进DTD以外的其他文件。如下所示:
<!ENTITY img SYSTEM "temp.jpg">
或
<!ENTITY img PUBLIC "-//ISO9//ME/IMG/EN" "temp.jpg">
若想引用上述实体,则如 &hello; 与&img;
对于public格式,语法如下:
<!ENTITY name PUBLIC FPI "URI">
FPI的格式为:
"前缀//使用者标识//文本类/文本描述/所用语言"
FPI的详细介绍如下:
- 前缀:前缀为“+”(注册公共标识)或“-”(未注册公共标识)
- 使用者标识:标识拥有这个公共标识的个人或组织。注册可以确保使用者标识的唯一性
- 文本类:文本类表明和公共标识相联系的文本类型。常见的有XML文档或DTD
- 文本描述:有关文档的描述,不可以包含“//”字符串
- 语言:文档使用的语言
参数实体
使用参数实体的DTD是放到一个单独的文件中,是因为在XML内部DTD中,参数实体引用不能在标记声明内部出现。语法如下:
<!ENTITY % name PUBLIC FPI "URI">
例如:
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % 介绍 "(生产日期,库存量)">
<!ELEMENT PC机 %介绍;>
<!ELEMENT 生产日期 (#PCDATA)>
<!ELEMENT 库存量 (#PCDATA)>