使用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); } }