DTD与XSD的区别
DTD(Document Type Definition)即文档类型定义,是一种XML约束模式语言,是XML文件的验证机制,是属于XML文件组成的一部分。DTD是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范,元素和标签使用是否正确。一个DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用的属性,可使用的属性或者实体规则。
要使用DTD验证模式的时候需要在XML文件的头部声明,以下是Spring中使用DTD声明方式的代码:
XML Schema语言就是XSD(XML Schema Definition)。XML Schema描述了XML文档的结构。可以用一个指定的XML Schema来验证某个XML文档,以检查该XML文档是否符合其要求。文档设计者可以通过XML Schema指定一个XML文档所允许的结构和内容,并可据此检查一个XML文档是否有效。XML Schema本身就是一个XML文档,它符合XML语法结构。可以通过通用的XML解析器解析它。
在使用XML Schema文档对XML实例文档进行检验,除了要声明命名空间以外(xmlns=http://www.Springframework.org/schema/beans),还必须指定该命名空间所对应的XML Schema文档的储存位置。通过schemaLocation属性来指定命名空间所对应的XML Schema的存储位置,它包含两个部分:命名空间的URI和该命名空间所标识的XML Schema文件的存储位置或URL地址。
了解了DTD与XSD的区别后分析Spring中对于验证模式的提取就更容易的多了。通过之前的分析我锁定了spring通过getValidationModelForResource方法来获取对应资源的验证模式。
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
//如果手动指定了验证模式则使用指定的验证模式
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
//如果未指定则使用自动验证
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}
方法的实现挺简单的。无非是如果设定了验证模式则使用验证模式(可以通过对调用XmlBeanDefinitionReader中的setValidationModel方法进行设定),否则使用自动检测的方式。而自动检测模式的功能是在函数detectValidationMode方法中实现的。在detectValidationMode函数中又将自动检测验证模式的工作委托给了专门处理类XmlValidationModelDetector,调用了XmlValidataionModelDetector的validationModeDetector方法。
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException(
"Passed-in Resource [" + resource + "] contains an open stream: " +
"cannot determine validation mode automatically. Either pass in a Resource " +
"that is able to create fresh streams, or explicitly specify the validationMode " +
"on your XmlBeanDefinitionReader instance.");
}
InputStream inputStream;
try {
inputStream = resource.getInputStream();
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
"Did you attempt to load directly from a SAX InputSource without specifying the " +
"validationMode on your XmlBeanDefinitionReader instance?", ex);
}
try {
return this.validationModeDetector.detectValidationMode(inputStream);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
resource + "]: an error occurred whilst reading from the InputStream.", ex);
}
}
public int detectValidationMode(InputStream inputStream) throws IOException {
// Peek into the file to look for DOCTYPE.
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) {
isDtdValidated = true;
break;
}
if (hasOpeningTag(content)) {
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
}
catch (CharConversionException ex) {
// Choked on some character encoding...
// Leave the decision up to the caller.
return VALIDATION_AUTO;
}
finally {
reader.close();
}
}