你已经知道如何根据XML文档的内容来解析(使用ContentHandler类),并且知道如何来处理出现的错误(ErrorHandler类)。它们两者关心的都是XML文档中的数据。我现在讨论的并不是通过解析器分享并得到数据的处理。例如,考虑从XML文档创建一个简单实体:
<FM>
<P>Text placed in the public domain by Moby Lexical Tools,1992. </P>
<P>SGML markup by Jon Bosak, 1992-1994. </P>
<p>XML version by Jon Bosak,1996-1998. </P>
<P>&usage-terms;</P>
</FM>
你的文档模式效验指出解析器是如何解析实例的:
<!ENTITY usage-terms SYSTEM "http://www.newInstance.com/entities/usage-terms.xml"
在解析时,usage-terms实体引用将会扩展。
但是下面的一些情况,并不是你想要的“默认”行为:
由于不能访问网络,因此希望实体去解析本地的一个引用文档(也许你自己已经下载了一个)
想用自己的内容去取代Schema中指定的内容。
你可以使用org.xml.sax.EntityResolver来缩短一个普通实体的解析。这个接口就是严格执行它所说的解析实体。创建并实现这个接口,通过将XMLReader的setEntityResolver()方法将该接口注册到XMLReader实例中,这些做好之后,每当阅读器遇到一个实体引用的时候,它会将公共ID和系统ID传递给EntityResolver实例中的resolveEntity()方法。
具有代表性的是,XML阅读器通过指定公共或系统ID来解析实体。如果在你自己实现的EntityResolver中接受了这种默认行为,将会从ResolverEntity()方法中返回null。如下例:
package javaxml3;
import java.io.IOException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class SimpleEntityResolver implements EntityResolver {
public InputSource resolveEntity(String publicID,String systemID)
throws IOException,SAXException{
//默认情况下返回null
return null;
}
}
当然,大多数情况下你都不希望返回null值。如果从这个方法中返回InputSource对象,该InputSource将被用作实体引用,而不是文档模式校验中的公共ID或者系统ID。换句话说,你可以指定自己的数据替代阅读器自己处理的解析,例如,在本地机器上创建一个usage-terms.xml文件:
private static final String USAGE_TERMS_ID = "http://www.newInstance.com/entities/usage-terms.xml";
private static final String USAGE_TERMS_LOCAL_URI = "/your/path/to/usage-terms.xml";
public InputSource resolveEntity(String publicID,String systemID)
throws IOException,SAXException {
if(systemID.equals(USAGE_TERMS_ID)){
return new InputSource(USAGE_TERMS_LOCAL_URI);
}
//在默认情况下,返回null
return null;
}
注意:请确保修改USAGE_TERMS_LOCAL_URI以配置自己的文件系统路径。
将这个解析过程通过setFeatureEntityResolver()方法注册到XMLReader中,如下:
//注册实体解决方案
reader.setEntityResolver(new SimpleEntityResolver());
在实际的应用程序中,resolveEntity()往往会变成一系列冗长的if/then/else代码块,每一块都会处理一个特殊的系统或公共ID。这就会带来一个重要的问题:怎样避免该方法成为ID的深渊。如果不再需要触发一个特殊的解析,而且可以删除的话,那就删除它。另外,尽量使用不同的EntityResolver实例为不同的应用程序提供实现,而不是创建一个通用的实例为所有的应用程序提供实现。这样做是为了避免代码的冗余,更为重要的是,这样可以加快对实体的解析速度。