Popular understanding of spring source code (3)-Get xml verification mode

Popular understanding of spring source code (3)-Get xml verification mode

The previous article talked about the xmlBeanDefinitionReader.doLoadBeanDefinitions (inputSource, encodedResource.getResource ()) method.

protected  int doLoadBeanDefinitions (InputSource inputSource, Resource resource)
             throws BeanDefinitionStoreException { 

        try {
             // convert from resource file to document object 
            Document doc = doLoadDocument (inputSource, resource);
             // parse document and register beanDefiniton to factory 
            int count = registerBeanDefinitions ( doc, resource);
             if (logger.isDebugEnabled ()) { 
                logger.debug ( "Loaded" + count + "bean definitions from" + resource); 
            } 
            return count; 
        } 
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

 In this method, the first is to replace the resource file with a document object

    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }

   Get the validation mode of the xml file through getValidationModeForResource (resource).

There are two verification modes for xml files, DTD and XSD. Here is a brief introduction:

1. DTD check mode

DTD (Document Type Definition), which is a document type definition, is an xml constraint mode language. It is a verification mechanism of xml files and belongs to a part of xml files. DTD is an effective method to ensure that the xml document format is correct. You can compare the xml document and the DTD file to see whether the document meets the specifications, and whether the elements and tags are used correctly. A DTD document contains: the definition rules of elements, the definition rules of relationships between elements, the attributes that can be used by elements, the rules of entities or symbols that can be used.

This DTD file can be written directly inside the xml, such as:

<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

It can also be referenced externally, such as writing the DTD content in note.dtd in the same directory as the xml file, such as:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note> 

   You can also refer to the DTD file on the network, as in our most familiar mybatis configuration file:

<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

  To quote an external DTD file, there must be a <! DOCTYPE> statement!

  For the detailed syntax of the DTD document, you can refer to https://www.w3school.com.cn/dtd/index.asp .

2. XSD verification mode

  The XML Schema language is XSD (XML Schemas Definition). XML Schema describes the structure of an XML document. You can use a specified XML Schema to verify an XML document to check whether the XML document meets the requirements. The document designer can specify the allowed structure and content of the xml document through XML Schema, and can check whether the xml document is valid based on this. XML Schema itself is an xml document, which conforms to the xml syntax structure. It can be parsed with a universal xml 'parser.

  XSD is more powerful than DTD and can be expanded for future needs. It is written based on XML and supports data types and namespaces.

  Multiple namespaces can be introduced in an xml file, each namespace must be bound to a prefix, or no prefix, as the default namespace, and each namespace must specify its corresponding xml Schema file location or URL location , As in the spring configuration file:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">

</beans>

  among them,

xmlns="http://www.springframework.org/schema/beans
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd

  Indicate the introduction of beans as the default namespace. The corresponding xsd file is in http://www.springframework.org/schema/beans/spring-beans-4.3.xsd. To use the label of this namespace, no prefix is ​​needed.

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd

   It means to introduce the context namespace and bind it with the context prefix. The corresponding xsd file is in http://www.springframework.org/schema/context/spring-context-4.3.xsd, that is, the namespace Labels need to be prefixed with context, such as <context: component-scan base-package = ""> </ context: component-scan>, which we are most familiar with.

  For the detailed syntax of the XSD document, you can refer to https://www.w3school.com.cn/schema/index.asp .

 3. Reading in verification mode

  After understanding the difference between DTD and XSD, it is much easier to analyze the acquisition of verification mode in spring.

  Then look at getValidationModeForResource (resource).

    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;
    }

   The logic here is very simple, and the author's comments are also very interesting, which means that we cannot clearly know the exact verification mode. If there is no obvious DTD statement before the root tag of the document is found, it is presumed to be the XSD verification mode.

  Continue to look at the detectValidationMode (resource) method:

    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);
        }
    }

   It is also the delegation mode, which is processed by validationModeDetector and enters validationModeDetector.detectValidationMode (inputStream):

    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; 
            // read line by line File content 
            while ((content = reader.readLine ())! = Null ) {
                 // Remove the comment content of the file 
                content = consumeCommentTokens (content);
                 if( this .inComment ||! StringUtils.hasText (content)) {
                     continue ; 
                } 
                // Determine whether the line contains the DOCTYPE string 
                if (hasDoctype (content)) { 
                    isDtdValidated = true ;
                     break ; 
                } 
                // Determine whether the line is Contains the start tag symbol, ie "<" 
                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();
        }
    }

    private boolean hasDoctype(String content) {
        return content.contains(DOCTYPE);
    }
    private boolean hasOpeningTag(String content) {
        if (this.inComment) {
            return false;
        }
        int openTagIndex = content.indexOf('<');
        return (openTagIndex > -1 && (content.length() > openTagIndex + 1) &&
                Character.isLetter(content.charAt(openTagIndex + 1)));
    }

  Read the content of the file line by line, remove the comment content of the file, first determine whether the line contains the string DOCTYPE, if there is, it is determined to be VALIDATION_DTD, if not, then determine whether the line contains the start tag symbol, if there is, then determine VALIDATION_XSD , If not, read the next line.

 

  The logic of obtaining the xml verification mode is not complicated, mainly to know the difference between DTD and XSD.

  Go too far, don't forget why you set off! The purpose of obtaining the verification mode is to verify the xml file and then parse it into a document.

    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }

   The next chapter will explain documentLoader.loadDocument and get Document.

 

Reference: https://www.w3school.com.cn/

   https://www.cnblogs.com/osttwz/p/6892999.html

   In-depth analysis of spring source code

Guess you like

Origin www.cnblogs.com/xiaohang123/p/12709192.html