原文地址:http://blog.csdn.net/sunxing007/article/details/5684265
每天都在用xml, 可是却一直没有去深入了解一下DTD和Schama, 当然我觉得很大一个原因是因为不需要, 本人从事web开发3年多也只有一次修改DTD文件的机会. 周末无意间翻看了一下张孝祥的书, 再到w3school上读了两边, 总算略知一二, 关键点记录下来, 以为纪念.
简单的说, DTD和Schema都是用来描述xml文档结构,限定文档的数据类型的. 只是做法上不一样. 想象一下一个xml 文档无非就是元素的集合, 元素可嵌套, 元素可以有属性. 那么DTD或schema就是用来描述一个xml文档可以出现哪些元素, 每个元素都可以有什么属性, 每个元素都可以有哪些嵌套元素, 元素可去什么数据类型, 以及元素的顺序, 重复的次数等等. 下面分别记录DTD和Schema的要点.
DTD:
1 DTD可以嵌入在XML文档中. 如下面的例子:
- <?xml version="1.0"?>
- <!DOCTYPE note [
- <!ELEMENT note (to,from,heading,body)>
- <!ELEMENT to (#PCDATA)>
- <!ELEMENT from (#PCDATA)>
- <!ELEMENT heading (#PCDATA)>
- <!ELEMENT body (#PCDATA)>
- ]>
- <note>
- <to>George</to>
- <from>John</from>
- <heading>Reminder</heading>
- <body>Don't forget the meeting!</body>
- </note>
2 DTD也可以独立的放在一个文件中. 如servlet2.3的部署描述文件xml, dtd文件引用了一个网络资源文件:
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE web-app PUBLIC
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd" >
- <web-app>
- ...
- </web-app>
当然DTD文件也可以放在本地, 需要注意的是两者DOCTYPE的声明的不同:
- <?xml version="1.0"?>
- <!DOCTYPE note SYSTEM "note.dtd">
- <!-- 注意note.dtd要和本xml放在同目录下面 -->
- <note>
- <to>George</to>
- <from>John</from>
- <heading>Reminder</heading>
- <body>Don't forget the meeting!</body>
- </note>
3 一个XML文档由以下模块构成:
- 元素 即一个节点
- 属性 提供有关元素的额外信息
- 实体 预定义的普通文本变量
- PCDATA 会被解析器解析的文本, 这些文本将被解析器检查实体以及标记
- CDATA 是不会被解析器解析的文本
则DTD分别用ELEMENT, ATTLIST, ENTITY, #PCDATA, #CDATA来描述.
4 关于ELEMENT:
<!ELEMENT 元素名称 EMPTY> 描述空元素(没有子节点和属性的元素), 如<!ELEMENT br EMPTY>.
<!ELEMENT 元素名称 (#PCDATA)> 描述只有PCDATA的元素, 如前面提到的<!ELEMENT from (#PCDATA)>.
<!ELEMENT 元素名称 ANY> 描述可包含任何可解析数据的组合. 不常用.
<!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)> 描述元素包含的子元素序列.
如:<!ELEMENT note (to,from,heading,body)>.
当然可以限定元素出现的次数.如web-app_2_3.dtd:
<!ELEMENT web-app (icon?, display-name?, description?, distributable?,context-param*, filter*, filter-mapping*, istener*, servlet*,servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*,login-config?, security-role*, env-entry*, ejb-ref*, ejb-local-ref*)>
也可以描述"或"关系:<!ELEMENT note (to,from,header,(message|body))> 即"note" 元素必须包含 "to" 元素、"from" 元素、"header" 元素,但 "message" 元素和 "body" 元素只能出现一个.
5 关于ATTLIST:
<!ATTLIST 元素名称 属性名称 属性类型 默认值> 声明元素拥有的属性.
<payment type="check" />对应的DTD描述: <!ATTLIST payment type CDATA "check">.
以下是属性类型的选项:
类型 描述 CDATA 值为字符数据 (character data) (en1|en2|..) 此值是枚举列表中的一个值 ID 值为唯一的 id IDREF 值为另外一个元素的 id IDREFS 值为其他 id 的列表 NMTOKEN 值为合法的 XML 名称 NMTOKENS 值为合法的 XML 名称的列表 ENTITY 值是一个实体 ENTITIES 值是一个实体列表 NOTATION 此值是符号的名称 xml: 值是一个预定义的 XML 值 默认值参数可使用下列值:
值 解释 值 属性的默认值 #REQUIRED 属性值是必需的 #IMPLIED 属性不是必需的 #FIXED value 属性值是固定的 如:<!ATTLIST contact fax CDATA #IMPLIED>, 则<contact fax="555-667788" />是合法的.
属性值可枚举:
<!ATTLIST 元素名称 属性名称 (en1|en2|..) 默认值>, 如:
<!ATTLIST payment type (check|cash) "cash">
6 关于实体
<!ENTITY 实体名称 "实体的值">, 如:
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">则在xml中可以这样引用它们:
<author>&writer;©right;</author>
预定义的实体:
实体引用 字符 < < > > & & " " ' ' 下面是一个电视台的schedule和对应的DTD:
- <?xml version="1.0" standalone="no"?>
- <!DOCTYPE tvschedule SYSTEM "TVSCHEDULE.dtd">
- <tvschedule name="ANHUI WEISHI">
- <channel chan="123">
- <banner>BANNEL 1</banner>
- <day>
- <date></date>
- <holiday>HOLIDAY</holiday>
- </day>
- <day>
- <date></date>
- <programslot vtr="">
- <time></time>
- <title rating="" language="EN">12</title>
- <description></description>
- </programslot>
- </day>
- </channel>
- </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>
Schema:
Schema是DTD的替代者, 它比DTD可以做更多的事情:
- 定义可出现在文档中的元素
- 定义可出现在文档中的属性
- 定义哪个元素是子元素
- 定义子元素的次序
- 定义子元素的数目
- 定义元素是否为空,或者是否可包含文本
- 定义元素和属性的数据类型
- 定义元素和属性的默认值以及固定值
但是代价就是Schema比DTD更复杂.
XML Schema的引用:
- <?xml version="1.0"?>
- <note
- xmlns="http://www.w3school.com.cn"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.w3school.com.cn/note.xsd">
- <to>George</to>
- <from>John</from>
- <heading>Reminder</heading>
- <body>Don't forget the meeting!</body>
- </note>
note.xsd:
- <?xml version="1.0"?>
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://www.w3school.com.cn"
- xmlns="http://www.w3school.com.cn"
- elementFormDefault="qualified">
- <xs:element name="note">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="to" type="xs:string"/>
- <xs:element name="from" type="xs:string"/>
- <xs:element name="heading" type="xs:string"/>
- <xs:element name="body" type="xs:string"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- </xs:schema>
由上面的代码可见, schema文件也是一个xml.
Schema命名空间:
schema有一个非常重要的概念就是命名空间(namespace).比如在spring中使用声明式事务管理的时候, 可以采用如下的配置方式为service层配置事务代理:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
- <bean id="txManager">
- ......
- </bean>
- ......
- <tx:advice id="txAdvice" transaction-manager="txManager">
- <tx:attributes>
- <tx:method name="insert*" propagation="REQUIRED" />
- <tx:method name="update*" propagation="REQUIRED" />
- <tx:method name="delete*" propagation="REQUIRED" />
- <tx:method name="list" propagation="REQUIRED" read-only="true" />
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <aop:pointcut id="interceptorPointCuts"
- expression="execution(* services.*Service(..))" />
- <aop:advisor advice-ref="txAdvice"
- pointcut-ref="interceptorPointCuts" />
- </aop:config>
- </beans>
那么这里使用了tx,aop命名空间.一个xml文档可以使用多个命名空间, 命名空间需要先声明, 并给它取别名, 然后依次给出每个命名空间的schema文件地址.如下代码解释希望可以帮助你理解上面臭长的命名空间声明:
- <?xml version="1.0" encoding="UTF-8"?>
- <root xmlns="默认命名空间,它不需要取别名"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:ns1别名="namespace1"
- xmlns:ns2别名="namespace2"
- xsi:schemaLocation="默认命名空间,它不需要取别名" "默认命名空间的xsd文件地址"
- namespace1 namespace1的xsd文件地址
- namespace2 namespace2的xsd文件地址>
- ......
- </root>
需要注意的是xsi命名空间几乎是必要的, 因为需要用xsi:schemaLocation来申明每个命名空间的schema文件地址.
对于上面给出的note.xsd. 因为它本身也是一个xml, 它要使用schema命名空间, 所以它也要申明命名空间.
鉴于schema的复杂性以及现实中没有多少机会编写一个xsd文件, 所以具体的关于schema的编写就不介绍了. 如有问题, 请参看:http://www.w3school.com.cn/schema/index.asp