欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

XML解析 验证之XSD和DTD验证以及 SpringXML验证源码分析

程序员文章站 2022-05-30 12:27:51
...

1.DTD(Documnet Type Definition)


DTD即文档类型定义,是一种XML约束模式语言,是XML文件的验证机制,属于XML文件组成的一部分。
DTD 是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范,元素和标签使用是否正确。
一个 DTD文档包含:
元素的定义规则,元素间关系的定义规则,元素可使用的属性,可使用的实体或符号规则。 DTD和XSD相比:DTD 是使用非 XML 语法编写的。 DTD 不可扩展,不支持命名空间,只提供非常有限的数据类型 .

2.XSD(XML Schemas Definition) 


XML Schema语言也就是XSD。XML Schema描述了XML文档的结构。 可以用一个指定的XML Schema来验证某个XML文档,以检查该XML文档是否符合其要求。文档设计者可以通过XML Schema指定一个XML文档所允许的结构和内容,并可据此检查一个XML文档是否是有效的。XML Schema本身是一个XML文档,它符合XML语法结构。可以用通用的XML解析器解析它。 一个XML Schema会定义:文档中出现的元素、文档中出现的属性、子元素、子元素的数量、子元素的顺序、元素是否为空、元素和属性的数据类型、元素或属性的默认 和固定值。

XSD是DTD替代者的原因,一是据将来的条件可扩展,二是比DTD丰富和有用,三是用XML书写,四是支持数据类型,五是支持命名空间。

XML Schema的优点:

  1. XML Schema基于XML,没有专门的语法
  2. XML Schema可以象其他XML文件一样解析和处理
  3. XML Schema比DTD提供了更丰富的数据类型.
  4. XML Schema提供可扩充的数据模型。
  5. XML Schema支持综合命名空间
  6. XML Schema支持属性组。

3 XSD验证

XML文件

<?xml version="1.0"?>
<note xmlns="http://adcoup.baidu.com/schema/note">
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
    <body>Don't forget me this weekend!</body>
</note>

XSD文件

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://adcoup.baidu.com/schema/note" xmlns="http://adcoup.baidu.com/schema/note"
           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>

JAVA验证代码

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.SAXValidator;
import org.dom4j.util.XMLErrorHandler;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.net.URL;
import java.util.List;

public class XsdXmlValidator {

    public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
        validateXMLByXSD();
    }

    public static void validateXMLByXSD() {
        // 从类路径下读取文件
        URL xmlFileName = XsdXmlValidator.class.getClassLoader().getResource("note.xml");
        // 输出为file:/D:/MyWorkSpace/FirstWorkSpace/validate-xml-test/target/classes/test_schema.xsd
        String xsdFileName = XsdXmlValidator.class.getClassLoader().getResource("note.xsd").toString();

        try {
            //创建默认的XML错误处理器
            XMLErrorHandler errorHandler = new XMLErrorHandler();
            //获取基于 SAX 的解析器的实例
            SAXParserFactory factory = SAXParserFactory.newInstance();
            //解析器在解析时验证 XML 内容。
            factory.setValidating(true);
            //指定由此代码生成的解析器将提供对 XML 名称空间的支持。
            factory.setNamespaceAware(true);
            //使用当前配置的工厂参数创建 SAXParser 的一个新实例。
            SAXParser parser = factory.newSAXParser();
            //创建一个读取工具
            SAXReader xmlReader = new SAXReader();
            //获取要校验xml文档实例
            Document xmlDocument = (Document) xmlReader.read(xmlFileName);
            //设置 XMLReader 的基础实现中的特定属性。核心功能和属性列表可以在 [url]http://sax.sourceforge.net/?selected=get-set[/url] 中找到。
            parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
                    "http://www.w3.org/2001/XMLSchema");
            parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource",xsdFileName);
            //创建一个SAXValidator校验工具,并设置校验工具的属性
            SAXValidator validator = new SAXValidator(parser.getXMLReader());
            //设置校验工具的错误处理器,当发生错误时,可以从处理器对象中得到错误信息。
            validator.setErrorHandler(errorHandler);
            //校验
            validator.validate(xmlDocument);

            StringBuilder errorMsg = new StringBuilder();
            //如果错误信息不为空,说明校验失败,打印错误信息
            if (errorHandler.getErrors().hasContent()) {
                List<Element> elements = errorHandler.getErrors().elements();
                for (Element element : elements) {
                    String line = String.valueOf(Integer.parseInt(element.attributeValue("line")) - 1);
                    String text = element.getText();
                    errorMsg.append("(第 " + line + "行出现错误) " + text+"\r\n");
                }
                errorMsg.append("XML文件通过XSD文件校验失败!");
                System.out.println(errorMsg.toString());
            }else {
                System.out.println("XML文件通过XSD文件校验成功!");
            }
        } catch (Exception ex) {
            System.out.println("XML文件: " + xmlFileName + " 通过XSD文件:" + xsdFileName + "检验失败。/n原因: " + ex.getMessage());
            ex.printStackTrace();
        }
    }

}

4 关于Spring对XML解析的验证源码分析

源码在DefaultDocumentLoader类的createDocumentBuilderFactory()方法:

1  下面使用了javax.xml获取DocumenBuildFactory.这行代码是原生的Java对xml的解析!

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

2 createDocumentBuilderFactory方法传递了两个参数

1)int validationMode:XML验证模式
   /**
	 * 0表示禁用验证XML
	 */
	public static final int VALIDATION_NONE = 0;

	/**
	 * 1表示根据XML文件格式自动验证
	 */
	public static final int VALIDATION_AUTO = 1;

	/**
	 * DTD方式验证XML
	 */
	public static final int VALIDATION_DTD = 2;

	/**
	 * XSD方式验证XML
	 */
	public static final int VALIDATION_XSD = 3;
boolean namespaceAware 是否设置命名空间。在XML解析过程中依情况而定。我在上述XSD代码验证过程中设置了true
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware);

流程如下:

1 根据DocumentBuilderFactory静态工厂实例化DocumentBuilderFactory对象

2 设置命名空间

3 如果验证模式不等于0,表示需要验证XML,设置验证为true

4 如果等于3,设置验证属性进行验证。验证过程出现异常,直接捕获,并且记录验证失败。

5 返回DocumentBuilderFactory工厂实例对象!

如下的源码我做了注释以及稍微改动!

protected DocumentBuilderFactory createDocumentBuilderFactory
                  (int validationMode, boolean namespaceAware) {

      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      /** namespaceAware 是否需要设置命名空间*/
      factory.setNamespaceAware(namespaceAware);
      /**
       * validationMode=0 不验证
       * validationMode=1 自动验证
       * validationMode=2 DTD验证
       * validationMode=3 XSD验证
       * 从代码可以看出Spring使用XSD验证
       */
      if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
         /** 如果不等于0,表示XML需要验证*/
         factory.setValidating(true);
         /** 等于3,表示使用XSD验证*/
         if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
            // XSD验证,强制使用命名空间,设置为true
            factory.setNamespaceAware(true);
            try {
               /** 设置XML属性 java XML以及w3c
                * SCHEMA_LANGUAGE_ATTRIBUTE=http://java.sun.com/xml/jaxp/properties/schemaLanguage
                * XSD_SCHEMA_LANGUAGE=http://www.w3.org/2001/XMLSchema
                * */
               factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
            }
            catch (IllegalArgumentException ex) {
               System.out.println("验证失败");
            }
         }
      }

      return factory;
   }

 

 

 

 

 

相关标签: xml spring java