SAX EntityResolver 的作用


1.1 何為 EntityResolver :

官方解釋: 如果SAX應用程序敘事實現自定義處理外部實體,則必須實現此接口,

並使用setEntityResolver方法向SAX 驅動器注冊一個實例.

也就是說,對於解析一個xml,sax

首先會讀取該xml文檔上的聲明,根據聲明去尋找相應的dtd定義,以便對文檔的進行驗證,
默認的尋找規則,(即:通過網絡,實現上就是聲明DTD的地址URI地址來下載DTD聲明),
並進行認證,下載的過程是一個漫長的過程,而且當網絡不可用時,這里會報錯,就是應為相應的dtd沒找到,

1.2 EntityResolver 的作用就是項目本身就可以提供一個如何尋找DtD 的聲明方法,

即:由程序來實現尋找DTD聲明的過程,比如我們將DTD放在項目的某處在實現時直接將此文檔讀取並返回個SAX即可,這樣就避免了通過網絡來尋找DTD的聲明

1.3 首先看看EntityResolver 接口聲明的方法.

 

  public abstract InputSource resolveEntity (String publicId,
                                               String systemId)
        throws SAXException, IOException;

 

這里,他接收2個參數,publicId ,systemId ,並返回一個InputStream對象,
這里我們以特定的文件來講解;

1.3.1  如果我們在解析驗證模式為xsd的配置文件,代碼如下 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
...
</beans> 

讀取得到以下參數,

 publicId : null

 systemId : http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

1.3.2 如果我們解析的是DTD的配置文件;

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"  "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
        ...
</beans>

讀取得到以下參數:

publicId : -//SPRING//DTD BEAN//EN

systemId : http://www.springframework.org/dtd/spring-beans.dtd

之前已經提到過,默認的尋找規則,(即:通過網絡,實現上就是聲明DTD的地址URI地址來下載DTD聲明),這樣才會造成延遲,用戶體驗也不好,一般的做法是將驗證文件放在自己的工程里面,

那么怎么做才能將這個Url轉換為自己工程里對應的文件呢?我們已加載DTD文件為例看看Spring中是如通過getEntityResolver() 對  EntityResolver 的獲取,

1.4  DelegatingEntityResolver

我們知道Spring中使用DelegatingEntityResolver 類為 EntityResolver的實現類,

 EntityResolver 的實現方法如下

 

 1 @Override
 2     public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
 3         if (systemId != null) {
 4             // 如果是DTD從這里開始
 5             if (systemId.endsWith(DTD_SUFFIX)) {
 6                 return this.dtdResolver.resolveEntity(publicId, systemId);
 7             }
 8             // 如果是XSD從這里開始
 9             else if (systemId.endsWith(XSD_SUFFIX)) {
10                 // 通過調用META-INF/Spring.schemas解析
11                 return this.schemaResolver.resolveEntity(publicId, systemId);
12             }
13         }
14         return null;
15     }

 

我們可以看到,對不同的驗證模式,Spring用了不同的解析器,這里簡單描述一下原理,

1.4.1  BeanDtdResolver 

比如加載DTD類型的 BeanDtdResolver 的 resolveEntity是直接截取systemId最后的xxx.dtd ,然后去當前路徑下尋找,代碼如下:

 1 @Override
 2     public InputSource resolveEntity(String publicId, String systemId) throws IOException {
 3         if (logger.isTraceEnabled()) {
 4             logger.trace("Trying to resolve XML entity with public ID [" + publicId +
 5                     "] and system ID [" + systemId + "]");
 6         }
 7         //截取systemId最后的xxx.dtd
 8         if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
 9             int lastPathSeparator = systemId.lastIndexOf("/");
10             for (String DTD_NAME : DTD_NAMES) {
11                 int dtdNameStart = systemId.indexOf(DTD_NAME);
12                 if (dtdNameStart > lastPathSeparator) {
13                     String dtdFile = systemId.substring(dtdNameStart);
14                     if (logger.isTraceEnabled()) {
15                         logger.trace("Trying to locate [" + dtdFile + "] in Spring jar");
16                     }
17                     try {
18                         Resource resource = new ClassPathResource(dtdFile, getClass());
19                         InputSource source = new InputSource(resource.getInputStream());
20                         source.setPublicId(publicId);
21                         source.setSystemId(systemId);
22                         if (logger.isDebugEnabled()) {
23                             logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
24                         }
25                         return source;
26                     }
27                     catch (IOException ex) {
28                         if (logger.isDebugEnabled()) {
29                             logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex);
30                         }
31                     }
32 
33                 }
34             }
35         }

 

1.4.2 PluggableSchemaResolver 

而加載XSD類型的PluggableSchemaResolver 類的 resolveEntity 是默認到META-INF/Spring.schemas文件中找到systemid 對應的XSD文件並加載代碼如下

 1 @Override
 2     public InputSource resolveEntity(String publicId, String systemId) throws IOException {
 3         if (logger.isTraceEnabled()) {
 4             logger.trace("Trying to resolve XML entity with public id [" + publicId +
 5                     "] and system id [" + systemId + "]");
 6         }
 7 
 8         if (systemId != null) {
 9             //獲取 systemId 對應的XSD文件
10             String resourceLocation = getSchemaMappings().get(systemId);
11             if (resourceLocation != null) {
12                 Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
13                 try {
14                     InputSource source = new InputSource(resource.getInputStream());
15                     source.setPublicId(publicId);
16                     source.setSystemId(systemId);
17                     if (logger.isDebugEnabled()) {
18                         logger.debug("Found XML schema [" + systemId + "] in classpath: " + resourceLocation);
19                     }
20                     return source;
21                 }
22                 catch (FileNotFoundException ex) {
23                     if (logger.isDebugEnabled()) {
24                         logger.debug("Couldn't find XML schema [" + systemId + "]: " + resource, ex);
25                     }
26                 }
27             }
28         }
29         return null;
30     }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM