SAX高级技术之解析实体

你已经知道如何根据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实例为不同的应用程序提供实现,而不是创建一个通用的实例为所有的应用程序提供实现。这样做是为了避免代码的冗余,更为重要的是,这样可以加快对实体的解析速度。

你可能感兴趣的:(java与XML)