目前主流的XML模式有XML DTD和XML Schema,他们都是用来规定XML的约束的,本文主要讲解DTD(文档类型定义),不会涉及到Schema,从何处开始了解DTD呢,为了便捷直观,我们先直接拿出一份导入了DTD文件的XML配置样例给大家看看,下面的是mybatis3框架的主配置XML文件,这里只配置了部分选项。
我们仔细来看看这个XML文件,首先<!DOCTYPE>声明标签
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-config.dtd">
- <configuration>
- <properties resource="config.properties"></properties>
- <typeAliases>
- <typeAlias alias="User" type="me.poplaris.mybatis.bean.User"/>
- </typeAliases>
- <environments default="development">
- <environment id="development">
- <transactionManager type="JDBC"/>
- <dataSource type="POOLED">
- <property name="driver" value="${driver}"/>
- <property name="url" value="${url}"/>
- <property name="username" value="${username}"/>
- <property name="password" value="${password}"/>
- </dataSource>
- </environment>
- </environments>
- <mappers>
- <mapper resource="mybatis/User.xml"/>
- </mappers>
- </configuration>
这实际上为当前的XML文件引入了DTD约束,大家可以按照下面方式来解读
- <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-config.dtd">
上面configuration即是根元素,一个XML文件只能有一个根元素,后面紧跟的即为该元素的详细声明,PUBLIC表示引入的DTD文件为外部共享文件, "-//mybatis.org//DTD Config 3.0//EN" 表示引入的DTD文件的逻辑名称, "http://mybatis.org/dtd/mybatis-3-config.dtd" 表示引入的DTD文件的URL,即一个完整的引入外部共享DTD的声明方式应该是如下:
- <!DOCTYPE 根元素 元素声明>
<!DOCTYPE 根元素 PUBLIC "DTD文件逻辑名称" "DTD文件URL">如果你引入的是一个私有的本地的DTD文件(自己创建没有公开发行),那么声明方式如下:
<!DOCTYPE 根元素 SYSTEM "DTD文件URL">声明引入DTD已经完成,接下来该是根据DTD的约束来制定相应的配置了,那么在这个XML配置中都规定了哪些配置呢,我们可以通过IDE的内容辅助来详细查看
根元素下的这些子元素配置都是怎么规定的呢,自然是在DTD文件中做约束的,我们详细看看mybatis-3-config.dtd文件
大家看很多 <!ELEMENT> 标签,这是DTD的元素设定标签,它的语法为
- <?xml version="1.0" encoding="UTF-8" ?>
- <!ELEMENT configuration (properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,plugins?,environments?,databaseIdProvider?,mappers?)>
- <!ELEMENT databaseIdProvider (property*)>
- <!ATTLIST databaseIdProvider
- type CDATA #required
- >
- <!ELEMENT properties (property*)>
- <!ATTLIST properties
- resource CDATA #IMPLIED
- url CDATA #IMPLIED
- >
- <!ELEMENT property EMPTY>
- <!ATTLIST property
- name CDATA #required
- value CDATA #required
- >
- <!ELEMENT settings (setting+)>
- <!ELEMENT setting EMPTY>
- <!ATTLIST setting
- name CDATA #required
- value CDATA #required
- >
- <!ELEMENT typeAliases (typeAlias*,package*)>
- <!ELEMENT typeAlias EMPTY>
- <!ATTLIST typeAlias
- type CDATA #required
- alias CDATA #IMPLIED
- >
- <!ELEMENT typeHandlers (typeHandler*,package*)>
- <!ELEMENT typeHandler EMPTY>
- <!ATTLIST typeHandler
- javaType CDATA #IMPLIED
- jdbcType CDATA #IMPLIED
- handler CDATA #required
- >
- <!ELEMENT objectFactory (property*)>
- <!ATTLIST objectFactory
- type CDATA #required
- >
- <!ELEMENT objectWrapperFactory (property*)>
- <!ATTLIST objectWrapperFactory
- type CDATA #required
- >
- <!ELEMENT plugins (plugin+)>
- <!ELEMENT plugin (property*)>
- <!ATTLIST plugin
- interceptor CDATA #required
- >
- <!ELEMENT environments (environment+)>
- <!ATTLIST environments
- default CDATA #required
- >
- <!ELEMENT environment (transactionManager,dataSource)>
- <!ATTLIST environment
- id CDATA #required
- >
- <!ELEMENT transactionManager (property*)>
- <!ATTLIST transactionManager
- type CDATA #required
- >
- <!ELEMENT dataSource (property*)>
- <!ATTLIST dataSource
- type CDATA #required
- >
- <!ELEMENT mappers (mapper*,package*)>
- <!ELEMENT mapper EMPTY>
- <!ATTLIST mapper
- resource CDATA #IMPLIED
- url CDATA #IMPLIED
- class CDATA #IMPLIED
- >
- <!ELEMENT package EMPTY>
- <!ATTLIST package
- name CDATA #required
- >
我们以mybatis-3-config.dtd文件里最先开始的 标签为例
它定义了一个名叫configuration的的元素,后面()内表述的是这个元素的子元素声明,即
- <!ELEMENT configuration (properties?,mappers?)>
- <!ELEMENT 元素名称 (子元素1?,子元素2?,子元素3?,...子元素n?)>
从上面我们可以看出这个configuration元素可以包含的子元素有下面几个,同时注意的是这些元素在XML中出现的顺序也是根据定义的顺序如下
properties settings typeAliases typeHandlers objectFactory objectWrapperFactory plugins environments databaseIdProvider mappers
如果你在设置元素的时候没有按照DTD文件约束的顺序,那么IDE将会显示错误
只知道了configuration都有哪些子元素以及子元素出现的顺序,那么每个子元素后面紧跟的问号又表示什么呢,它有点类似正则的功能,表示这些子元素出现的次数,在这里他们表示这些子元素最多出现一次,类似的声明方式还有
- Thecontentofelementtype"configuration"mustmatch"(properties?,mappers?)"
<!ELEMENT 元素名称 (子元素1|子元素2|子元素3|...|子元素n)>表示这些子元素中只能出现其中一个
更多用来表示元素个数的方式还有
1、+:最少1次
2、?:最多一次
3、*:任意次数
4、无:只能一次
如mybatis-3-config.dtd中定义的
表示元素databaseIdProvider可以出现任意个property子元素
- <!ELEMENT databaseIdProvider (property*)>
表示元素settings最少有一个setting子元素
- <!ELEMENT settings (setting+)>
表示元素environment中的子元素必须有且只有一个transactionManager和dataSource子元素
- <!ELEMENT environment (transactionManager,dataSource)>
当然上面这些方式都是按照元素是包含其他子元素来定义的,除了这种方式来定义元素外,我们还可以根据元素里包含的子元素类型不同来定义,如:
- <!ELEMENT 元素名称 (#PCDATA)>
表示此元素仅仅包含一般文字,是基本元素。在mybatis-3-config.dtd中是没有定义基本元素的。
在mybatis-3-config.dtd中,除了以 <!ELEMENT 元素名称 元素内容> 来定义元素以外,还有发现以下面这种方式来定义元素的
这是用来定义元素的类型的,元素可以根据是否拥有子元素来区分为ANY和EMPTY两种类型,ANY表示该元素下可以包含任意已经被设定过的元素,出现的次数和顺序也不受限制,并且除了可以包含子元素外还可以包含一般的文字。而EMPTY表示该元素为空元素,是单独存在,没有</元素>这样的结束标记的。例如
- <!ELEMENT property EMPTY>
- <!ELEMENT property EMPTY>
- <!ELEMENT setting EMPTY>
- <!ELEMENT typeAlias EMPTY>
- <!ELEMENT typeHandler EMPTY>
- <!ELEMENT mapper EMPTY>
这些元素都是空元素,只能以<property />这种写法来结束,除了定义元素以外,我们还可以定义常量供DTD和XML文件使用,声明方式如下:
- <!ELEMENT package EMPTY>
<!ENTITY 元素名称 "元素内容">例如下面我们定义一个author常量
<!ENTITY author "张三">在XML中引用常量author的方式:以&开头,以;结尾,即&author; 如:
- <name>&author;</name>
前面为大家介绍了元素的定义方式,下面介绍元素的属性定义,在mybatis-3-config.dtd中,大家可以看到在<!ELEMENT>标签下面通常都会紧跟另一个标签<!ATTLIST>,<!ATTLIST>标签是用来约束元素属性的,例如:
我们可以按照下面方式来解读
- <!ELEMENT typeHandler EMPTY>
- <!ATTLIST typeHandler
- javaType CDATA #IMPLIED
- jdbcType CDATA #IMPLIED
- handler CDATA #required
- >
其中属性值的类型主要包括
1、CDATA:字符串
2、(值1|值2|值3):枚举
3、ID:唯一标识,在同一个XML文件中不可重复
还有一些其他的类型暂时未列出也不做介绍,基本不怎么用到,比如nmtoken、nmtokens、idref、idrefs、entity、entities、notation
1、#required:必须的
2、#IMPLIED:可选的
3、#FIXED:固定值
4、字符串:默认值
我们简单举个例子,定义一个员工元素和属性
<!ELEMENT 员工 EMPTY> <!ATTLIST 员工 姓名 CDATA #required 性别 (男|女) "男" 身份证号 ID #IMPLIED 所属星球 CDATA #FIXED "地球" >
在XML中我们可以设置员工元素如下:
<员工 姓名="张三" 身份证号="123456" />它等效于下面方式
<员工 姓名="张三" 性别="男" 身份证号="123456" 所属星球="地球" /></span>
如果你再一定一个员工
<员工 姓名="李四" 身份证号="123456" />解析会报错,因为身份证号值类型的约束为ID,是唯一的,不可重复
OK,DTD部分就介绍到这