Description
The Javax.xml.parsers.DocumentBuilder.setEntityResolver(EntityResolver er) method specifies the EntityResolver to be used to resolve entities present in the XML document to be parsed. Setting this to null will result in the underlying implementation using it's own default implementation and behavior.
Declaration
Following is the declaration for Javax.xml.parsers.DocumentBuilder.setEntityResolver() method
public abstract void setEntityResolver(EntityResolver er)
Parameters
-
er -- The EntityResolver to be used to resolve entities present in the XML document to be parsed.
Return Value
This method does not return a value.
Exception
-
NA
Example
For our examples to work, a xml file named Student.xml is needed in our CLASSPATH. The contents of this XML are the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <student id="10"> <age>12</age> <name>Malik</name> </student>
The following example shows the usage of Javax.xml.parsers.DocumentBuilder.setEntityResolver()method.
package com.tutorialspoint; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; // an EntityResolver for our builder. class Resolver implements EntityResolver { public InputSource resolveEntity(String publicId, String systemId) { System.out.println(publicId); System.out.println(systemId); if (systemId.equals("")) { System.out.println("Resolving Entity..."); return null; } else { // use the default behaviour return null; } } } public class DocumentBuilderDemo { public static void main(String[] args) { // create a new DocumentBuilderFactory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { // use the factory to create a documentbuilder DocumentBuilder builder = factory.newDocumentBuilder(); Resolver res = new Resolver(); builder.setEntityResolver(res); // create a new document from input stream and an empty systemId Document doc = builder.parse("Student.xml"); // get the first element Element element = doc.getDocumentElement(); // get all child nodes NodeList nodes = element.getChildNodes(); // print the text content of each child for (int i = 0; i < nodes.getLength(); i++) { System.out.println("" + nodes.item(i).getTextContent()); } } catch (Exception ex) { ex.printStackTrace(); } } }
为什么要设置EntityResolver呢?在解析的时候如果xml文件不符合xsd文件的要求则会报错误,从而终止解析,其实跟下面的一样效果的
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(true); SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); factory.setSchema(schemaFactory.newSchema( new Source[] {new StreamSource("contacts.xsd")})); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new SimpleErrorHandler()); Document document = builder.parse(new InputSource("document.xml"));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new SimpleErrorHandler()); Document document = builder.parse(new InputSource("document.xml"));
现在问题来了,如果要使用外部的dtd文件校验的话怎么办?
问题提出 :
解析ejb-jar.xml,出现在网络连不上的情况下,解析失败的情况。
问题分析:
我们使用的是DOM进行XML的解析的:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); //位置点 Document doc = builder.parse(file);
由于ejb-jar.xml中,有
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
在解析的时候,会从网络http://java.sun.com/dtd/ejb-jar_2_0.dtd中抓紧DTD文件,进行验证,如果网络不通,那么就会出现解析失败。
首先,DocumentBuilderFactory.newInstance()创建DocumentBuilderFactory实现类的对象,它会通过一下方式来查找实现类:
1.在系统环境变量中(System.getProperties())中查找 key=javax.xml.parsers.DocumentBuilderFactory
2.如果1没有找到,则找java.homelibjaxp.properties 文件,如果文件存在,在文件中查找key=javax.xml.parsers.DocumentBuilderFactory
3.如果2没有找到,则在classpath中的所有的jar包中查找META-INF/services /javax.xml.parsers.DocumentBuilderFactory 文件
全都没找到,则返回null
如果上面都没有找到,那么就使用JDK自带的实现类:
com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
在创建DocumentBuilder实例的时候,是根据DocumentBuilderFactoryImpl的不同有不同的实现。
为了在网络不可用的情况下,正常解析XML文件,我们可以在使用builder之前,设置EntityResolver:
builder.setEntityResolver( new EntityResolver(){ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { return new InputSource(new StringBufferInputStream("")); // return null;//这个的效果仍然是从网络来抓取DTD来验证 } } );
上面的设置就不会对XML文件进行验证。
如果一定要验证的话,我们也可以设置使用本地的DTD文件来做验证:
builder.setEntityResolver( new EntityResolver(){ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if(publicId.equals("-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN")) { String dtd_uri = "C:/TEMP/ejb-jar_2_0.dtd"; return new InputSource(dtd_uri); } } );
注意:直接return null,仍然会从网络来抓取DTD来验证。
所以这也是spring为什么采用设置setEntityResolver来校验xml格式的方式的原因