博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
XML的验证模式
阅读量:5272 次
发布时间:2019-06-14

本文共 5627 字,大约阅读时间需要 18 分钟。

前言

  上一篇文章讲述了bean的加载的最关键的三个步骤,这三个步骤很重要,是支撑着Spring容器实现的基础,所以这三个步骤是值得仔细认真的去学习的,其中第一个步骤就是获取XML的验证模式,这篇文章就是讲述这个步骤。

DTD和XSD

DTD:

  DTD(Document Type Definition)即文档类型定义。是一种XML约束模式语言,是XML文件的验证机制,属于XML文件组成的一部分。DTD是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范,元素和标签使用是否正确。

  一个DTD文档包含:元素的定义规则、元素间关系的定义规则、元素可使用的属性、可使用的实体或符号规则。

  要使用DTD验证模式的时候需要在XML文件头部声明,以下是Spring中使用DTD声明方式的代码:

  DTD在一定的阶段推动了XML的发展,但是它本身存在着一些缺陷:

  (1)它没有使用XML格式,而是自己定义了一套格式,相对解析器的重用性比较差;而且DTD的构建和访问没有标准的编程接口,因而解析器很难简单的解析DTD文档。

  (2)DTD对元素的类型限制较少;同时其他的约束力也较弱。

  (3)DTD扩展能力较差。

  (4)基于正则表达式的DTD文档的描述能力有限。

XSD:

  针对DTD的缺陷,W3C在2001年推出XSD。XSD(XML Schemas Definition)就是XML Schema语言。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地址(xsi:schemaLocation="http://www.Springframework.org/schema/beans http://www.Springframework.org/schema/beans/Spring-beans.xsd")。

  XSD具有以下优势:

  (1)XML Schema基于XML,符合XML语法结构。

  (2)XML Schema可以像其他XML文件一样解析和处理。

  (3)XML Schema比DTD提供更丰富的数据类型。

  (4)XML Schema提供可扩充的数据模型。

  (5)XML Schema支持综合命名空间。

  (6)XML Schema支持属性组。

验证模式的获取

  在了解了DTD和XSD 的区别后,我们再来分析Spring中对于验证模式的读取就更容易理解了。通过我们上一篇文章的分析,我们锁定了getValidationModeForResource方法来获取对应资源的验证模式,下面来看一下这个方法的源码:

1   protected int getValidationModeForResource(Resource resource) { 2         int validationModeToUse = getValidationMode(); 3         if (validationModeToUse != VALIDATION_AUTO) { 4             return validationModeToUse; 5         } 6         int detectedMode = detectValidationMode(resource); 7         if (detectedMode != VALIDATION_AUTO) { 8             return detectedMode; 9         }10         // Hmm, we didn't get a clear indication... Let's assume XSD,11         // since apparently no DTD declaration has been found up until12         // detection stopped (before finding the document's root tag).13         return VALIDATION_XSD;14     }

  可以看出,方法的实现其实还是很简单的,在代码第3行的意思是:如果手动指定了验证模式则使用指定的验证模式。代码第6行:如果未指定则使用自动检测。所以,该方法的逻辑就是:如果设定了验证模式则使用设定的验证模式(可以通过调用 XmlBeanDefinitionReader中的setValidationMode方法进行设定),否则使用自动检测的方式。

  而自动检测验证模式的功能是在函数detectValidationMode方法中实现的,在detectValidationMode函数中又将自动检测验证模式的工作委托给了专门处理类XmlValidationModeDetector,调用了XMLValidationModeDetector的validationModeDetector方法,具体方法如下:

XmlBeanDefinitionReader.detectValidationMode(Resource resource):

1 protected int detectValidationMode(Resource resource) { 2         if (resource.isOpen()) { 3             throw new BeanDefinitionStoreException( 4                     "Passed-in Resource [" + resource + "] contains an open stream: " + 5                     "cannot determine validation mode automatically. Either pass in a Resource " + 6                     "that is able to create fresh streams, or explicitly specify the validationMode " + 7                     "on your XmlBeanDefinitionReader instance."); 8         } 9 10         InputStream inputStream;11         try {12             inputStream = resource.getInputStream();13         }14         catch (IOException ex) {15             throw new BeanDefinitionStoreException(16                     "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +17                     "Did you attempt to load directly from a SAX InputSource without specifying the " +18                     "validationMode on your XmlBeanDefinitionReader instance?", ex);19         }20 21         try {22             return this.validationModeDetector.detectValidationMode(inputStream);23         }24         catch (IOException ex) {25             throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +26                     resource + "]: an error occurred whilst reading from the InputStream.", ex);27         }28     }

XmlValidationModeDetector.detectValidationMode(InputStream inputStream):

1 public int detectValidationMode(InputStream inputStream) throws IOException { 2         // Peek into the file to look for DOCTYPE. 3         BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); 4         try { 5             boolean isDtdValidated = false; 6             String content; 7             while ((content = reader.readLine()) != null) { 8                 content = consumeCommentTokens(content); 9                 if (this.inComment || !StringUtils.hasText(content)) {10                     continue;11                 }12                 if (hasDoctype(content)) {13                     isDtdValidated = true;14                     break;15                 }16                 if (hasOpeningTag(content)) {17                     // End of meaningful data...18                     break;19                 }20             }21             return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);22         }23         catch (CharConversionException ex) {24             // Choked on some character encoding...25             // Leave the decision up to the caller.26             return VALIDATION_AUTO;27         }28         finally {29             reader.close();30         }31     }

  第一段代码没有什么需要解释的,就是调用了XMLValidationModeDetector类的detectValidationMode(inputStream)方法。

  第二段代码第9行:如果读取的行是空或者是注释则略过。代码第16行:读取到“<”开始符号时直接退出,因为验证模式一定在开始符号之前。

  总的来说,Spring用来检测验证模式的办法就是判断是否包含DOCTYPE,如果包含就是DTD,否则就是XSD。

至此,已经将加载Bean的第一个步骤,获取验证模式分析完毕,下篇文章将讲述Bean加载的第二个步骤:获取Document实例。

参考:《Spring源码深度解析》 郝佳 编著:

转载于:https://www.cnblogs.com/Joe-Go/p/10059073.html

你可能感兴趣的文章
GoFramework框架简介(三)通信机制篇
查看>>
python全栈学习--day31(正则)
查看>>
h.264语法结构分析
查看>>
基督-神[上帝]的道,真理的本真归回
查看>>
https请求抛出异常
查看>>
chrome浏览器更换favicon.ico后不更新缓存解决方案
查看>>
面试试题 一 (排列组合)
查看>>
CString转char*实现方法
查看>>
Go直接调用C函数
查看>>
Mac 系统环境变量配置
查看>>
《你的灯亮着吗?:发现问题的真正所在》读书笔记2
查看>>
Winform开发框架之权限管理系统功能介绍
查看>>
从C#到Objective-C,循序渐进学习苹果开发(1)--准备开发账号和开发环境
查看>>
视图的定义、更新、撤销
查看>>
iOS之页面传值-----单例传值、通知传值
查看>>
数组换位子
查看>>
软件测试草图
查看>>
一个App项目设计开发完整流程
查看>>
如何使用iClap创建普通批注
查看>>
用Java编写自己的机器人,为你承担苦力
查看>>