mybatis,Spring等工具對xml文件正確性的驗證


  我們知道mybatis或者spring都是使用xml文件作為配置文件,配置文件的格式都是定義在叫做.dtd或者.xsd文件中的,當工具在解析用戶自己定義的xml文件的時候,如何才能知道用戶自定義的文件是否正確的呢?我們不能在xml文件中亂寫一些框架不認識的標簽,比如在spring的xml文件中寫如下<user>標簽,毫無疑問會報錯。那么框架是怎么來驗證我們所寫的標簽是否正確的呢?

<user>
  <id>100</id>
</user>

  由於mybatis使用的是dom解析,利用JDK的dom解析API,如下:

 1     @Test
 2     public void docFactoryTest() throws Exception {
 3         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 4         factory.setValidating(true);
 5         factory.setNamespaceAware(false);
 6         factory.setIgnoringComments(true);
 7         factory.setIgnoringElementContentWhitespace(false);
 8         factory.setCoalescing(false);
 9         factory.setExpandEntityReferences(true);
10         DocumentBuilder builder = factory.newDocumentBuilder();
11         builder.setEntityResolver(new XMLMapperEntityResolver());
      ...(此處省略一部分代碼) 30 Document doc = builder.parse(Resources.getResourceAsStream("mybatis-config.xml")); 31 System.err.println(doc);

  在第11行中,用到了XMLMapperEntityResolver對象,這個對象定義如下:

 1 public class XMLMapperEntityResolver implements EntityResolver {
 2 
 3   private static final Map<String, String> doctypeMap = new HashMap<String, String>();
 4 
 5   private static final String IBATIS_CONFIG_PUBLIC = "-//ibatis.apache.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH);
 6   private static final String IBATIS_CONFIG_SYSTEM = "http://ibatis.apache.org/dtd/ibatis-3-config.dtd".toUpperCase(Locale.ENGLISH);
 7 
 8   private static final String IBATIS_MAPPER_PUBLIC = "-//ibatis.apache.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH);
 9   private static final String IBATIS_MAPPER_SYSTEM = "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH);
10 
11   private static final String MYBATIS_CONFIG_PUBLIC = "-//mybatis.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH);
12   private static final String MYBATIS_CONFIG_SYSTEM = "http://mybatis.org/dtd/mybatis-3-config.dtd".toUpperCase(Locale.ENGLISH);
13 
14   private static final String MYBATIS_MAPPER_PUBLIC = "-//mybatis.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH);
15   private static final String MYBATIS_MAPPER_SYSTEM = "http://mybatis.org/dtd/mybatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH);
16 
17   private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
18   private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";
19 
20   static {
21     doctypeMap.put(IBATIS_CONFIG_SYSTEM, MYBATIS_CONFIG_DTD);
22     doctypeMap.put(IBATIS_CONFIG_PUBLIC, MYBATIS_CONFIG_DTD);
23 
24     doctypeMap.put(IBATIS_MAPPER_SYSTEM, MYBATIS_MAPPER_DTD);
25     doctypeMap.put(IBATIS_MAPPER_PUBLIC, MYBATIS_MAPPER_DTD);
26 
27     doctypeMap.put(MYBATIS_CONFIG_SYSTEM, MYBATIS_CONFIG_DTD);
28     doctypeMap.put(MYBATIS_CONFIG_PUBLIC, MYBATIS_CONFIG_DTD);
29 
30     doctypeMap.put(MYBATIS_MAPPER_SYSTEM, MYBATIS_MAPPER_DTD);
31     doctypeMap.put(MYBATIS_MAPPER_PUBLIC, MYBATIS_MAPPER_DTD);
32   }
33 
34   /*
35    * Converts a public DTD into a local one
36    * 
37    * @param publicId The public id that is what comes after "PUBLIC"
38    * @param systemId The system id that is what comes after the public id.
39    * @return The InputSource for the DTD
40    * 
41    * @throws org.xml.sax.SAXException If anything goes wrong
42    */
43   @Override
44   public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
45 
46     if (publicId != null) {
47       publicId = publicId.toUpperCase(Locale.ENGLISH);
48     }
49     if (systemId != null) {
50       systemId = systemId.toUpperCase(Locale.ENGLISH);
51     }
52 
53     InputSource source = null;
54     try {
55       String path = doctypeMap.get(publicId);
56       source = getInputSource(path, source);
57       if (source == null) {
58         path = doctypeMap.get(systemId);
59         source = getInputSource(path, source);
60       }
61     } catch (Exception e) {
62       throw new SAXException(e.toString());
63     }
64     return source;
65   }
66 
67   private InputSource getInputSource(String path, InputSource source) {
68     if (path != null) {
69       InputStream in;
70       try {
71         in = Resources.getResourceAsStream(path);
72         source = new InputSource(in);
73       } catch (IOException e) {
74         // ignore, null is ok
75       }
76     }
77     return source;
78   }
79 
80 }

  可以看到,當框架在解析xml文件的時候,會把xml文件開頭的publicId和systemId傳給EntityResolver,而EntityResolver對象就是從classpath中去尋找.dtd文件(文件就在org/apache/ibatis/builder/xml/目錄下),在spring中還會存在.xsd文件,原理都是一樣的,然后利用classpath中的.dtd文件進行驗證。如果不指定這個.dtd文件,那么會從互聯網上面下載.dtd文件,性能不好。


免責聲明!

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



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