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