上篇博客讨论了文件定义格式的基本用法,即DTD中元素和实体的声明语法,同时讨论了DTD中为了避免命名冲突而引入的命名空间和前缀标识。DTD同时为我们提供了一种节省时间的方法,它的功能很类似于抽象类,接下来将着重讨论实体机制。
一. 实体详解
有了元素为什么还要引入实体呢?要想区分两者,首先要看实体引入的目的。实体机制是一种节省大量时间的工具,将多种不同类型的数据并入XML文档的方法。它就好像是面向对象的抽象类一样,把经常使用的抽象成一个实体,在使用它的地方可以直接引用,避免了重复。
详细的说
(2)代替一些与xml规范保留字相冲突的内容,如:< > 等等。
(3)代替大段的重复的文本。
实体引用按照引用的位置分为内部和外部两种,按照引用的内容分为一般和参数引用两种。下面看一个外部实体引用的实例:
清单1:“2.dtd”的声明
<!-- 声明外部DTD,并保存为2.dtd --> <!ELEMENT 影片目录 (影片)+> <!ELEMENT 影片 (片名,主演,导演,简介)> <!ATTLIST 影片 类别 CDATA "动作" 年份 CDATA #required> <!ENTITY 十面埋伏 "漫天大雪,三人在雪中决斗"> <!ENTITY 霍元甲 "民族英雄,与西方帝国主义抗争"> <!ELEMENT 片名 (#PCDATA)> <!ELEMENT 主演 (#PCDATA)> <!ELEMENT 导演 (#PCDATA)> <!ELEMENT 简介 (#PCDATA)> <!ENTITY filmcomment SYSTEM "影评.xml"> <!-- 引用外部通用实体,文件名称为“影评.xml” -->
清单2:影评.xml的内容
<?xml version="1.0" encoding='utf-8'?> <影评> 这些影评都是由XXX公司出品,值得观看! </影评>
<?xml version="1.0" encoding='utf-8'?> <影评> 这些影评都是由XXX公司出品,值得观看! </影评> 清单3:使用dtd的xml文件中的内容。 <?xml version="1.0" encoding='utf-8'?> <!DOCTYPE 影片目录 SYSTEM "./2.dtd" > <影片目录> <影片 类别="武侠" 年份="2008"> <片名>十面埋伏</片名> <主演>刘德华、金城武、章子怡</主演> <导演>张艺谋</导演> <简介>&十面埋伏;</简介> </影片> <影片 类别="武侠" 年份="2006"> <片名>霍元甲</片名> <主演>李连杰</主演> <导演>于仁泰</导演> <简介>&霍元甲;</简介> </影片> &filmcomment; </影片目录>
清单4:使用IE8打开清单3后的内容
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE 影片目录 (View Source for full doctype...)> - <影片目录> - <影片 类别="武侠" 年份="2008"> <片名>十面埋伏</片名> <主演>刘德华、金城武、章子怡</主演> <导演>张艺谋</导演> <简介>漫天大雪,三人在雪中决斗</简介> </影片> - <影片 类别="武侠" 年份="2006"> <片名>霍元甲</片名> <主演>李连杰</主演> <导演>于仁泰</导演> <简介>民族英雄,与西方帝国主义抗争</简介> </影片> <影评>这些影评都是由XXX公司出品,值得观看!</影评> </影片目录>
内部和外部很容易理解,主要看一般和参数两种引用的区别。
1.参数实体
清单1:test.dtd,在此该内容单独存在了一个dtd文件中是因为在内部DTD子集中。
参数实体引用不能在标记声明内部出现,可以在标记声明允许出现的地方出现。然而,对于外部DTD子集,则没有这个限制。
参数实体引用不能在标记声明内部出现,可以在标记声明允许出现的地方出现。然而,对于外部DTD子集,则没有这个限制。
<!-- 声明外部DTD,并保存为test.dtd --> <!-- 个人信息实体声明的是参数类型的,可以再各个元素中共同使用该参数 --> <!ENTITY % 个人信息 "(姓名,性别,出生日期)"> <!ELEMENT 学生信息 %个人信息;> <!ELEMENT 教师信息 %个人信息;> <!ELEMENT 员工信息 %个人信息;>
<?xml version='1.0' encoding='utf-8'?> <!-- 学校信息.xml文件 --> <!-- 引用外部DTD --> <!DOCTYPE 学校信息 SYSTEM './test.dtd'> <!-- 由DTD获得的XML --> <学校信息> <学生信息> <姓名>张三</姓名> <性别>男</性别> <出生日期>2013-10-12</出生日期> </学生信息> <教师信息> <姓名>张三</姓名> <性别>男</性别> <出生日期>2013-10-12</出生日期> </教师信息> <员工信息> <姓名>张三</姓名> <性别>男</性别> <出生日期>2013-10-12</出生日期> </员工信息> </学校信息>
清单3:使用IE8打开清单2的内容后
<?xml version="1.0" encoding="utf-8" ?> - <!-- 声明内部DTD --> <!DOCTYPE 学校信息 (View Source for full doctype...)> - <!-- 由DTD获得的XML --> - <学校信息> - <学生信息> <姓名>张三</姓名> <性别>男</性别> <出生日期>2013-10-12</出生日期> </学生信息> - <教师信息> <姓名>张三</姓名> <性别>男</性别> <出生日期>2013-10-12</出生日期> </教师信息> - <员工信息> <姓名>张三</姓名> <性别>男</性别> <出生日期>2013-10-12</出生日期> </员工信息> </学校信息>
2. 一般实体
3.对比升华
参数实体与一般实体的区别如下:
(l)在定义参数实体时,实体名前必须加一个“%”号。
(2)参数实体引用以“%”开始,而不是一般实体引用的“&”。
(3)参数实体的内容不仅可以包含文本,还可以包含标记。
(4)参数实体只能应用于DTD,而不能在文档本体中引用。即参数实体只能用来构成DTD的内容,而不能构成文档内容。
(5)参数实体只能在外部DTD文档中使用,无法应用于内部DTD。
外部参数实体与外部一般实体的区别如下:
(1)外部参数实体应用于独立的DTD文档,外部一般实体应用于XML文档。
(2)外部参数实体应用于将多个独立的DTD文档组合为一个大的DTD文档,外部一般实体用于将多个独立的XML文档组合成一个大的XML文档。
二. 验证XML文件的合法性
DTD定义了XML文件的使用格式,它从结构和形式上限制了XML文档,通过引用DTD可以形成统一的规范化的XML文档,另外通过使用实体简化了DTD和XML文档的内容。使用DTD验证的XML文档才能称为规范化文档,那如何验证所写的XML文档是否符合DTD的规范呢。通过如下的代码串:
上面代码中的类和结构主要完成了XML文档的解析,并且在解析之前验证当前XML文件是否符合某个DTD的定义。在上面的代码运行前需要将需要验证的XML和提供规范化的DTD文档引入到当前ValidateDTD项目中,后运行上面的代码实例,该项目会在项目文件中自动查找规范的DTD,然后验证xml文件。
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.xml.sax.InputSource; public class ValidateDTD { public static void main(String[] args){ //在验证前需要把需要验证的XML和规范DTD包含在jar中 try{ DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); //创建一个文档构造工厂 dbf.setValidating(true); DocumentBuilder builder=dbf.newDocumentBuilder(); builder.parse(new InputSource("xml-2-2.xml")); //需要验证的XML名称 }catch(Exception e){ e.printStackTrace(); } } }