DTD的学习应用
一、DTD概述
1、定义
DTD:Document Type Definition
,翻译过来就是:文档类型定义
。它使用一系列元素来定义文档的结构,可以定义合法的XML
文档结构。说白了就是一套规则。
2、为什么要有DTD
我觉得最重要的一点就是,有了DTD,每个XML文件就携带一个自身格式的描述,所谓格式描述就是我的XML文档里面可以写哪些东西,比如元素、属性、文本;
还有应用程序可以使用一个标准DTD校检从外部接收的XML数据是否有效。
二、DTD构建XML文档结构
DTD主要有两种声明方式:内部的DOCTYPE声明、外部的文档声明。
1、内部的DOCTYPE声明
在XML文档中直接声明,这个XML文档里面既包含XML定义,又包含DTD的定义。
<!DOCTYPE 根元素 [定义内容]>
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE people [
<!ELEMENT people (man, woman)>
<!ELEMENT man (#PCDATA)>
<!ELEMENT woman (#PCDATA)>
]>
<people>
<man>里斯</man>
<woman>张三</woman>
</people>
这个[ ]里面是DTD的定义的内容。
2、外部的文档声明
所谓外部,就是DTD的定义和我们的XML文档是在不同的文件里面。就像我们的CSS样式文件和HTML分开一样
那么外部的DTD如何使用呢?
那就需要在XML文档的根元素的上面引入自定义DTD文件路径。
<!DOCTYPE 根元素 SYSTEM '自定义DTD文件路径'>
引入DTD后,XML就会有固定的格式。
示例:
dtd文件
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT configuration (properties?, typeAliases?, mappers?)>
<!ELEMENT properties (property*)>
<!ATTLIST properties
resource CDATA #IMPLIED
url CDATA #IMPLIED
>
<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED
>
xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE people SYSTEM "config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="com.coldlight.domain"/>
</typeAliases>
</configuration>
三、DTD的结构定义
我们刚刚看了DTD构建XML文件结构的两种方式,他的作用主要就是用一些参数限制元素、属性和内容,
在工作中,我们使用外部DTD文档声明比较多,我们具体看一下外部申明中每个参数具体的作用:
1、元素的定义
**语法 :**元素声明有两种方式,区别是最后一位是类别还是元素内容
<!ELEMENT 元素名称 类别>
<!ELEMENT 元素名称 (元素内容)>
ELEMENT:就是关键字,固定写法;
元素名称:是指XML中元素的名称;
1.1、元素类别
通过第一种方式声明的:<!ELEMENT 元素名称 类别>
,这里类别为下边左一栏标识的
类别 | 举例 | 描述 |
---|---|---|
EMPTY | <!ELEMENT 元素名称 EMPTY> | 该元素不能包含子元素和文本,但可以有属性 |
(#PCDATA) | <!ELEMENT 元素名称 (#PCDATA)> | 可以包含任何字符数据,但是在其中不能包含任何子元素; |
ANY | <!ELEMENT 元素名称 ANY> | 该元素可以包含任何在DTD中定义的元素内容 |
(子元素名称) | <!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.)> | 带一个或多个子元素的元素通过圆括号中的子元素名进行声明,只包含子元素,并且这些子元素外没有文本,子元素必须按照顺序出现在XML中 |
1.1.1、EMPTY
该元素不能包含子元素和文本,但可以有属性
<!ELEMENT property EMPTY>
正确:
<property name="username" value="root"/>
错误:不能包含文本和子元素
<property>李四</property>
<property>
<node1><node1>
</property>
1.1.2、(#PCDATA)
可以包含任何字符数据,但是在其中不能包含任何子元素;
<ELEMENT note (#PCDATA)>
正确:
<note name="李四">23岁</note>
错误:不能包含子元素
<note>
<node1><node1>
</note>
1.1.3、ANY
该元素可以包含任何在DTD中
定义的元素内容
<!ELEMENT property ANY>
示例:
<property name="name">name</property>
<property>
<name></name>
</property>
注意:将根元素设置为ANY后,元素出现的次数和顺序将不受限制。
1.1.4、子元素
带一个或多个子元素的元素通过圆括号中的子元素名进行声明,只包含子元素,并且这些子元素外没有文本,子元素必须按照顺序出现在XML中。除根元素设置为ANY除外。
<!ELEMENT typeAliases (typeAlias,package)>
示例:
<typeAliases>
<typeAlias></typeAlias>
<package></package>
</typeAliases>
通过第二种方式声明的:<!ELEMENT 元素名称 (元素内容)>
,这里类别为下边左一栏标识的
类别 | 举例 | 描述 |
---|---|---|
, | <!ELEMENT node (node1,node2)> | 元素必须按指定顺序出现,必须先出node1,再出现node2; |
( ) | <!ELEMENT node (node1,node2)> | 用来给元素分组 |
| | <!ELEMENT node (node1|node2)> | 表示node1或者node2必须出现,两者必须出现一个。 |
* | <!ELEMENT node (message*)> | 声明出现零次或多次的元素,message子元素可在node元素里出现零次或多次。 |
+ | <!ELEMENT node (message+)> | 声明最少出现一次的元素,message子元素至少在node元素里出现一次 |
? | <!ELEMENT node (message?)> | 声明出现零次或一次的元素,message子元素可在node元素里出现零次或一次。 |
注意:+,*,?为基数操作符,若没有基数操作符,则表示必须有且仅有一个元素;
下面是mybatis-3-config.dtd的配置
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
这个是根元素的配置,根元素的名称为:configuration,里面包含properties、settings......等子元素。且在XML中,子元素必须按照当前的顺序,且每个资源子只能出现0次或一次。
2、属性的定义
语法:
<!ATTLIST 元素名称
属性名称 属性类型 属性特点
>
元素名称:所属元素的名称。
属性名称:自定义
2.1、属性类型
2.1.1、CDATA
CDATA是表示属性的值,可以是任何字符,这里包括数字和中文。
例如:
<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED
>
<payment name = "username" value="root"/>
<payment name = "password" value="123456"/>
2.1.2、ID
表明该属性的取值必须是唯一的。
<!ELEMENT property EMPTY>
<!ATTLIST property
name ID #REQUIRED
value CDATA #REQUIRED
>
正确:
<payment name = "username" value="root"/>
<payment name = "password" value="123456"/>
错误:
两个name不唯一了
<payment name = "username" value="root"/>
<payment name = "username" value="123456"/>
2.1. 3、Enumerated
枚举,预先定义了一些值,属性的值必须在所列出的值的范围内;
<!ELEMENT property EMPTY>
<!ATTLIST property
name ("username" | "password") #REQUIRED
value CDATA #REQUIRED
>
2.2、属性特点
2.2.1、#REQUIRED
它表示元素的所有的实例都必须有该属性的值(NOT NULL)
<!ATTLIST if
test CDATA #REQUIRED
>
示例:test参数不可为空
select * from sys_user
where 1 = 1
<if test="id != null">
AND id = #{id}
</if>
2.2.2、#IMPLIED
这就表示该属性的值是可以被忽略的。
<!ATTLIST select
id CDATA #REQUIRED
parameterMap CDATA #IMPLIED
resultType CDATA #IMPLIED
......
resultSets CDATA #IMPLIED
>
示例:添加了#IMPLIED的参数可以忽略不写
<select id="getUser" resultType = "int">
select count(id) from sys_user
</select>
2.2.3、#FIXED
元素中该属性的值必须为指定的固定值。
<!ELEMENT property EMPTY>
<!ATTLIST property
name CADATA #FIXED "username"
value CDATA #REQUIRED
>
# 只能为固定值
<payment type = "username" />
2.2.4、Default
为属性提供一个默认的值。
四、实战练习
简单的学习了一下DTD的基础,那么我们也可以写出一些DTD,来构建XML文档结构了,下面我们有一个简单的练习:
用DTD构建一个XML文件结构,XML文档中的结构如下:
1、根元素为
mapper
,包含namespace
属性,属性为任意字符,且非必填项;2、根元素下面有子元素:
select
、sql
,且子元素必须要出现一个,且每个出现零次或者多次;3、
select
元素要求:必须包含任何字符的id 属性,可以包含属性:parameterMap
、parameterType
、resultMap
、resultType
,四个 参数可以为任何字符类型,且可以被忽略;可以包含include
元素,元素可以出现多次;4、
sql
元素要求:可以不包含任何子元素、也可以包含include
、where
、if
四个参数任意;
练习DTD:
<!ELEMENT mapper (sql* | select*)+>
<!ATTLIST mapper
namespace CDATA #IMPLIED
>
<!ELEMENT select (#PCDATA | include)* >
<!ATTLIST select
id CDATA #REQUIRED
parameterMap CDATA #IMPLIED
parameterType CDATA #IMPLIED
resultMap CDATA #IMPLIED
resultType CDATA #IMPLIED
>
<!ELEMENT sql (#PCDATA | include| where | if )*>
解析:
<!ELEMENT mapper (select* | sql* )+>
<!--
根元素为mapper,下面有两个子元素:select和sql
select*:表示出现零次或多次的
(select* | sql* )+ : +表示()里面的声明子元素必须出现一次;
-->
<!ATTLIST mapper
namespace CDATA #IMPLIED
>
<!--
mapper中包含namespace属性;
CDATA : 属性为任意字符;
#IMPLIED : 表示该属性的值是可以被忽略的
-->
<!ELEMENT select (#PCDATA | include)* >
<!--
select中可以包含includ元素,或者不包含任何子元素
* :可以出现0次或多次
-->
<!ATTLIST select
id CDATA #REQUIRED
parameterMap CDATA #IMPLIED
parameterType CDATA #IMPLIED
resultMap CDATA #IMPLIED
resultType CDATA #IMPLIED
>
<!ELEMENT sql (#PCDATA | include| where | if )*>
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper SYSTEM "mybatis-3-mapper.dtd">
<mapper namespace="com.coldlight.mapper.SysUserMapper">
<sql id="restMap">
id ,user_account AS accountName, nick_name AS nickName, mobile As phone
</sql>
<select id="getUserById" parameterType="long" resultType="user">
SELECT <include refid="restMap"/> FROM sys_user where id = #{id}
</select>
</mapper>
五、总结回顾
1、总结回顾
- DTD Document Type Definition 文档类型定义;
- 它使用一系列元素来定义文档的结构,给XML文件就携带一个自身格式的描述;
- 被多个XML共享,保持统一的数据交换格式,不同组织的人使用同一个通用的DTD来交换数据;
- 应用程序可以使用一个标准DTD效验从外部世界接受来的XML数据是否有效
2、思考一下
我门通过学习和实战书写DTD,我们可以思考一下,DTD有没有缺陷:
1、DTD与XML不是一样的语法,我们写DTD的时候,还得去了解DTD的书写语法,比较麻烦;
2、DTD的数据类型有限,与我们的Java中基本数据类型不一致;
3、扩展性比较差;
我们看,DTD有这么多缺陷,我们有没有可以取代DTD的技术呢?
肯定是有的,就是Shema。