使用Xerces-J的SAX方式进行XML程序设计
--Filter的使用
在简介中我们已经介绍过为什么要在SAX2中加入过滤器的概念和XMLFilter界面,我们将在下面详细介绍过滤器和XMLFilter界面的使用。XMLFilter界面继承了XMLReader界面,增加了setParent和getParent两个方法。如以下代码:
public interface XMLFilter extends XMLReader
{
public abstract void setParent(XMLReader parent);
public abstract XMLReader getParent ();
}
由上可知,可以说,XMLFilter就是一个带父Reader的XMLReader。在实际的程序设计过程中,我们可以通过两种方法来进行过滤器程序设计,第一是通过实现XMLFilter界面来自己完成一个过滤器的整体概念与结构,第二是使用SAX提供的类org.xml.sax.XMLFilterImpl.来创建过滤器。在实际程序设计中,笔者一般会采用后者。具体原因有两条:第一有了一个完整的类,不必自己实现自己不感兴趣的方法;第二,有了一个完整的实现体系结构,而且这个体系是具有世界标准的,通过这个体系,我们可以很方便地完成自己的程序设计。org.xml.sax.XMLFilterImpl.类实现了XMLFilter界面,还实现了ContentHandler,
DTDHandler, EntityResolver, ErrorHandler等界面,换而言之,XMLFilterImpl具有XMLFilter(含XMLReader)和DefaultHandler的全部功能。但是同普通的XMLReader不同的是,要使用XMLFilterImpl作过滤器需要遵循以下规程。首先,创立一个继承了XMLFilterImpl类的类;第二,在这个类里面定义事件响应方法,例如public
void startElement,这些方法就是过滤器进行过滤的实质;第三,在自己写的事件响应方法最后调用super类中的相应方法,通过这一步可以把处理过的事件消息发送给我们在第四步设定的Handler;第四,为自己的过滤器类的实例设置parent,通过这一步XMLFilter把自己设置为parent的处理器(Handler);第四,之一,为自己的过滤器类设置处理器(Handler),这个处理器将是应用程序和过滤器的接口,之二,把这个过滤器设置为另外一个过滤器的parent,从而开始另一轮的过滤。
从我们在上面的说明可以看出,一个过滤器在应用程序中充当一个中介的作用,在过滤器的底层是一个XMLReader(或者是另一个过滤器),同时过滤器的上层是应用程序及其Handler(或者是另一个过滤器)。底层XMLReader会首先把事件信息发送给过滤器,过滤器经过自身的Handler处理之后再把信息发送给上一层的程序,当然如果过滤器认为上层程序没有必要知道某些信息,也可以选择不继续向上发送,即不调用super类的相应方法。
下面我们就通过一个例子演示如何使用XMLFilterImpl类作一个过滤器。由于SAX2r2pre的一个bug,这个例子可能在某些安装了SAX2r2pre的计算机上产生一个数组越界异常而无法运行。要解决这个bug只需要打开AttributesImpl.java文件,把437行的(length-index)*5);改成(length-index-1)*5);就可以了。这个例子打开一个XML文件,如果一个Element有ID则删除这个ID然后再根据Element在文档中出现的顺序给每个Element增加一个值为0,1,2,3……的ID。通过这个例子我们还可以学习AttributesImpl类的使用方法。
import org.xml.sax.*;
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.AttributesImpl;
public class TestXercesSAX2 extends DefaultHandler
{
static String strParserName = "org.apache.xerces.parsers.SAXParser";
public static void main(String [] x)
{
try
{
SAXParser oParser = (SAXParser)Class.forName(strParserName).newInstance(); //new SAXParser();
//创建一个SAXParser的实例
TestXercesSAX2 oHandler = new TestXercesSAX2();
//创建处理器(Handler)的实例
FilterHandler oFilter = new FilterHandler();
//创建过滤器实例
oParser.setContentHandler( oHandler );
//为parser设置处理器
System.out.println("\nNow the parser is processing the content of XML File ...\n");
oParser.parse("testXerces.xml");
//解析文件
System.out.println("\nNow the filter is processing the content of XML File ...\n");
oFilter.setParent( oParser );
//为过滤器设置parent
oFilter.setContentHandler( oHandler);
//为过滤器设置处理器
oFilter.parse("testXerces.xml");
//过滤器进行解析
}
catch( Exception e )//错误处理
{
e.printStackTrace();
}
}
public void startElement( String uri, String localName, String qName, Attributes oAttributes)
{
System.out.println("start of a Element ==> uri:"+uri+"; localName:"+localName+"; qName:"+qName);
if( oAttributes.getLength() > 0 )
{
for( int i = 0 ; i < oAttributes.getLength() ; i ++ )
{
System.out.println("\t...with attributes==>"+oAttributes.getQName( i )+"="+oAttributes.getValue( i ) );
}
}
}
public void endElement( String uri, String localName, String qName)
{
System.out.println("end of a Element ==> uri:"+uri+"; localName:"+localName+"; qName:"+qName);
}
}
class FilterHandler extends XMLFilterImpl
//继承XMLFilterImpl类,创建自己的过滤器
{
int index = 0;
public void startElement( String uri, String localName, String qName, Attributes oAttributes)
throws SAXException
//过滤器自身的事件响应方法,这个方法起到过滤的作用。
{
AttributesImpl oAttributesImpl = new AttributesImpl( oAttributes );
//在Attributes地基础上新建一个AttributesImpl类的实例。
//AttributesImpl可以修改内容而Attributes不可以。
for( int i = 0 ; i < oAttributesImpl.getLength() ; i ++ )
{
if( oAttributesImpl.getQName( i ).toUpperCase().equals("ID"))
//检查是否有一个名为id的属性
{
oAttributesImpl.removeAttribute(i);
//有的话就删除
break;
}
}
oAttributesImpl.addAttribute("","id","id","ID",String.valueOf(index++));
//新建一个id属性,值为Element在XML文档中出现的顺序。
super.startElement(uri, localName, qName, oAttributesImpl);
//调用super类的相应方法,把事件消息发送给下一级过滤器或处理器。
}
public void endElement(String uri, String localName, String qName)
throws SAXException
{
super.endElement(uri, localName, qName);
}
public void characters(char[] caIn, int iStart,int iLength)
throws SAXException
{
super.characters( caIn, iStart, iLength);
}
}