dtd/xsd 这点事
工作多年,发现以前不怎么在乎的东西,越发是大有文章。值得我们去深入学习下。最近公司的时间比较宽松,想把以前只会用的东西,继续学习下。才发现不懂的东西还是比较多的。本着“知其然,知其所以然”的态度,这里记录下一些文字。
今天在看hibernate源码的时候,发现hibernate包下有个hibernate-configuration-3.0.dtd文件,而spring关于配置方面的验证文件却是spring-beans-3.0.xsd文件。那么dtd文件跟xsd文件之间有什么不同呢?下面介绍一下DTD,XSD的区别。
1.DTD(Documnet Type Definition)
DTD即文档类型定义,是一种XML约束模式语言,是XML文件的验证机制,属于XML文件组成的一部分。
DTD 是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范,元素和标签使用是否正确。
一个 DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用的属性,可使用的实体或符号规则。
2.XSD(XML Schemas Definition)
XSD:XML结构定义,XML Schema描述了XML文档的结构。
可以用一个指定的XML Schema来验证某个XML文档,以检查该XML文档是否符合其要求。XML Schema本身是一个XML文档,它符合XML语法结构。可以用通用的XML解析器解析它。
一个XML Schema会定义:文档中出现的元素、文档中出现的属性、子元素、子元素的数量、子元素的顺序、元素是否为空、元素和属性的数据类型、元素或属性的默认 和固定值。
对比下
DTD文件 |
XSD文件 |
|
支持对XML文件的验证? |
支持 |
支持 |
是XML语法编码? |
不是 |
是的,可以像其他XML文件一样解析和处理 |
可扩展吗? |
不可 |
可以 |
支持命名空间吗? |
不可 |
可以 |
可扩充数据类型? |
只提供非常有限的数据类型 |
可以 |
可见XSD要比DTD文件丰富。
实例说明:
一个XML文档:
<?xml version="1.0"?> <!-- 本文档根元素为gridbag, 其中验证文档为gridbag.dtd --> <!DOCTYPE gridbag SYSTEM "gridbag.dtd"> <gridbag> <row> <cell anchor="EAST"> <bean> <class>javax.swing.JLabel</class> <property> <name>text</name> <value> <string>Face:</string> </value> </property> </bean> </cell> <cell fill="HORIZONTAL" weightx="100"> <bean id="face"> <class>javax.swing.JComboBox</class> </bean> </cell> <cell gridheight="4" fill="BOTH" weightx="100" weighty="100"> <bean id="sample"> <class>javax.swing.JTextArea</class> <property> <name>text</name> <value> <string>The quick brown fox jumps over the lazy dog</string> </value> </property> <property> <name>editable</name> <value> <bolean>false</bolean> </value> </property> <property> <name>lineWrap</name> <value> <boolean>true</boolean> </value> </property> <property> <name>border</name> <value> <bean> <class>javax.swing.border.EtchedBorder</class> </bean> </value> </property> </bean> </cell> </row> <row> <cell gridwidth="2" weighty="100"> <bean id="bold"> <class>javax.swing.JCheckBox</class> <property> <name>text</name> <value> <string>Bold</string> </value> </property> </bean> </cell> </row> <row> <cell gridwidth="2" weighty="100"> <bean id="italic"> <class>javax.swing.JCheckBox</class> <property> <name>text</name> <value> <string>Italic</string> </value> </property> </bean> </cell> </row> </gridbag>
DTD文件描述
<!ELEMENT gridbag (row)*> <!--根元素是gridbag,可以多个子元素row--> <!ELEMENT row (cell)*> <!--row下面可以有多个cell子元素 --> <!ELEMENT cell (bean)> <!--cell元素下只有一个bean元素--> <!ATTLIST cell gridx CDATA #IMPLIED> <!--cell有gridx属性,类型为任意文本,如果有特殊字符用相应的替代字符代替(用于属性中),可选--> <!ATTLIST cell gridy CDATA #IMPLIED> <!ATTLIST cell gridwidth CDATA "1"> <!--gridwidhth属性默认为1--> <!ATTLIST cell gridheight CDATA "1"> <!ATTLIST cell weightx CDATA "0"> <!ATTLIST cell weighty CDATA "0"> <!ATTLIST cell fill (NODE|BOTH|HORIZONTAL|VERTICAL) "NONE"> <!--fill属性有几个可选值,默认为NONE--> <!ATTLIST cell anchor (CENTER|NORTH|NORTHEAST|EAST|SOUTHEAST|SOUTH|SOUTHWEST|WEST|NORTHWEST) "CENTER"> <!ATTLIST cell ipdx CDATA "0"> <!ATTLIST cell ipady CDATA "0"> <!ELEMENT bean (class, property*)> <!--bean子元素有一个class子元素,多个property子元素--> <!ATTLIST bean id ID #IMPLIED> <!--bean的id属性是ID类型,也就是唯一性 --> <!ELEMENT class (#PCDATA)> <!--class元素下面可以只包含文本也可以包含子元素,类似于ANY(用于元素中)--> <!ELEMENT property (name, value)> <!ELEMENT name (#PCDATA)> <!ELEMENT value (int|string|boolean|bean)> <!ELEMENT int (#PCDATA)> <!ELEMENT string (#PCDATA)> <!ELEMENT boolean (#PCDATA)>
XSD文件描述:
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.mysite.org/schema/mytag" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.mysite.org/schema/mytag" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:element name="gridbag" type="GridBagType" /><!--根元素 --> <xsd:element name="bean" type="BeanType" /> <xsd:complexType name="GridBagType"> <xsd:sequence> <xsd:element name="row" type="RowType" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="RowType"> <xsd:sequence> <xsd:element name="cell" type="CellType" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CellType"> <xsd:sequence> <xsd:element ref="bean"></xsd:element> </xsd:sequence> <xsd:attribute name="gridx" type="xsd:int" use="optional" /> <xsd:attribute name="gridy" type="xsd:int" use="optional"></xsd:attribute> <xsd:attribute name="gridwidth" type="xsd:int" use="optional" default="1"></xsd:attribute> <xsd:attribute name="gridheight" type="xsd:int" use="optional" default="1" /> <xsd:attribute name="weightx" type="xsd:int" use="optional" default="0" /> <xsd:attribute name="weighty" type="xsd:int" use="optional" default="0" /> <xsd:attribute name="fill" use="optional" default="NONE"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="NONE" /> <xsd:enumeration value="BOTH" /> <xsd:enumeration value="HORIZONTAL" /> <xsd:enumeration value="VERTICAL"></xsd:enumeration> </xsd:restriction> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="anchor" use="optional" default="CENTER"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="CENTER"></xsd:enumeration> <xsd:enumeration value="NORTH" /> </xsd:restriction> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="ipady" type="xsd:int" use="optional" default="0"></xsd:attribute> <xsd:attribute name="ipadx" type="xsd:int" use="optional" default="0" /> </xsd:complexType> <xsd:complexType name="BeanType"> <xsd:sequence> <xsd:element name="class" type="xsd:string" /> <xsd:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID" use="optional"></xsd:attribute> </xsd:complexType> <xsd:complexType name="PropertyType"> <xsd:sequence> <xsd:element name="name" type="xsd:string" /> <xsd:element name="value" type="ValueType" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ValueType"> <xsd:choice> <xsd:element ref="bean" /> <xsd:element name="int" type="xsd:int" /> <xsd:element name="string" type="xsd:string" /> <xsd:element name="boolean" type="xsd:boolean" /> </xsd:choice> </xsd:complexType> </xsd:schema>
Spring中 XSD文件对XML校验:
见博客另一I篇文章。
Herbernate 中DTD 文件对XML校验:
正常的 dom4j 读取 xml 的方式如下:
package com.zs.test.xsd; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class DTDExample { public static String fileRealPath = "D:/vingsoft2/clientTest/src/com/zs/test/xsd/"; public static void main(String[] args) throws DocumentException, IOException { EntityResolver resolver = new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { // 这个publicId 没有搞明白? System.out.println(publicId); // file:///D:/vingsoft2/clientTest/src/com/zs/test/xsd/gridbag.dtd System.out.println(systemId); if (systemId.endsWith("gridbag.dtd")) { InputStream in = new FileInputStream(new File(fileRealPath + "gridbag.dtd")); return new InputSource(in); } return null; } }; SAXReader reader = new SAXReader(); reader.setEntityResolver(resolver); // 负责绑定dtd文件,对xml文件进行校验 reader.setValidation(true);// 是否需要验证 Document doc = reader.read(new File(fileRealPath + "MyXml.xml")); Element root = doc.getRootElement(); OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding(doc.getXMLEncoding()); XMLWriter writer = new XMLWriter(new FileOutputStream(fileRealPath + "haha.xml"), format); writer.write(doc); writer.close(); } }
Hibernate在读取配置文件,进行XML校验的时候,主要用到了三个类:
org.hibernate.cfg.Configuration
org.hibernate.util.XMLHelper
org.hibernate.util.DTDEntityResolver
public InputSource resolveEntity (String publicId, String systemId) { if ( systemId!=null && systemId.startsWith(URL) ) { log.debug("trying to locate " + systemId + " in classpath under org/hibernate/"); // Search for DTD String path = "org/hibernate/" + systemId.substring( URL.length() ); InputStream dtdStream = resourceLoader==null ? getClass().getResourceAsStream(path) : resourceLoader.getResourceAsStream(path); if (dtdStream==null) { log.debug(systemId + " not found in classpath"); if ( systemId.substring( URL.length()).indexOf("2.0")>-1 ) { log.error("Don't use old DTDs, read the Hibernate 3.x Migration Guide!"); } return null; } else { log.debug("found " + systemId + " in classpath"); InputSource source = new InputSource(dtdStream); source.setPublicId(publicId); source.setSystemId(systemId); return source; } } else { // use the default behaviour return null; } }
参考:
http://lg-asus.iteye.com/blog/1517942
http://www.w3school.com.cn/dtd/
http://www.w3school.com.cn/schema/index.asp