使用Xerces-J的SAX方式进行XML程序设计

--使用serialize的方法输出xml文档


尽管一般情况下使用SAX接口的应用程序不需要输出XML文件,但是网络应用程序还是经常要输出XML文件。例如一个运行在服务器上面的程序,这个程序向用户提供XML格式的数据文件,数据源为储存在服务器上的一个XML文件,这个数据源文件的内容和格式并不完全符合用户所需的文件的内容和格式,因此需要程序进行转换,再把经过转换的XML文件输出成XML文件。转换的任务我们可以通过过滤器来完成,为了完成输出XML文件的任务,apache提供了org.apache.xml.serialize包,通过序列化的方式来完成这个任务。这个包里面不仅仅包含了输出XML文件需要的文件,还包含了输出HTML和XHTML需要的文件,其中我们处理XML文件需要的类为XMLSerializer和OutputFormat。XMLSerializer类实现了DefaultHandler的全部方法,因此还可以作为一个Handler来使用。另外XMLSerializer还提供了ContentHandler asContentHandler()方法,通过这个方法可以从一个XMLSerializer的实例得到一个ContentHandler的实例,然后可以把这个ContentHandler的实例注册为一个XMLReader的ContentHandler,这样的结果是在解析的同时就可以完成输出工作。当然,XMLSerializer和XMLFilterImpl同样可以很好地共同工作。下面我们详细介绍一下XMLSerializer。

XMLSerializer继承了org. apache. xml. serialize. BaseMarkupSerializer类,可以对SAX和DOM两种解析方法进行序列化,我们在这里仅仅介绍SAX序列化的使用方法,在后面介绍如何使用Xerces的DOM方法解析XML文件的时候介绍如何使用DOM序列化方法。org. apache. xml. serialize. BaseMarkupSerializer具有DefaultHandler的全部功能,因此org. apache. xml. serialize. BaseMarkupSerializer可以作为一个处理器(Handler)来使用。org. apache. xml. serialize. BaseMarkupSerializer还实现了界面org. apache. xml. serialize. Serializer,其中的方法如表6。

方法 使用说明
ContentHandler asContentHandler() 调用这个方法之后可以把一个实现Serializer界面的类转换成一个ContentHandler并将其返回。如果使用的实现不支持ContentHandler,则会返回null。
DocumentHandler asDocumentHandler() 调用这个方法之后可以把一个实现Serializer界面的类转换成一个DocumenttHandler并将其返回。如果使用的实现不支持DocumentHandler,则会返回null。DocumentHandler是一个SAX1中的界面,笔者在这里建议使用。
DOMSerializer asDOMSerializer() 调用这个方法之后可以把一个实现Serializer界面的类转换成一个DOMSerializer并将其返回。如果使用的实现不支持DOMSerializer,则会返回null。关于DOMSerializer我们会在后面介绍DOMSerializer的时候介绍。
void setOutputByteStream(java.io.OutputStream output) 这个方法用来设置输出的位置,即把序列化的结果输出到什么地方。这个方法设置了一个OutputStream。
void setOutputCharStream(java.io.Writer output) 同上,但是设置一个Writer。使用这种方法在字符处理方面要比使用OutputStream更加方便。
void setOutputFormat(OutputFormat format) 设置输出格式。后面介绍OutputFormat的使用方法。

XMLSerializer还实现了DOMSerializer界面,由于这方面的内容与SAX无关,我们将在后面介绍DOM的时候介绍。

OutputFormat定义了在序列化时输出的格式,在这里仅仅简单地定义一个实例,因此我们不作详细的介绍,仅仅介绍其结构函数。OutputFormat总共有四个结构函数,详细介绍如表7。

结构函数 使用说明
OutputFormat() 使用缺省值创建一个OutputFormat对象。缺省值在OutputFormat.Defaults类中用静态数据定义,编码(encoding)为UTF-8,缩进为4个字符,行宽为72个字符。这个结构函数对中文用户用处不大。
OutputFormat(Document doc) 这个结构函数在序列化DOM文档对象的时候使用,这里也进行一并介绍,这个函数根据Document对象中的数据决定文件类型,输出类型,字符编码,缩进大小,行宽等数据。但是我觉得用的时候并不是很好。
public OutputFormat(Document doc, java.lang.String encoding, boolean indenting) 同上,这个结构函数也是在序列化DOM文档对象的时候使用的,但是可以指定是否使用缩进和文档使用的字符编码。这个方法对于使用DOM中文程序设计时是最有用的。
OutputFormat(java.lang.String method, java.lang.String encoding, boolean indenting) 这个方法可以指定输出方法,字符编码和是否使用缩进,在使用SAX方法进行解析的时候,这个方法是最有用的。

 

下面的jsp程序演示了如何使用serializer输出XML文件。该程序在Windows98,apache1.3.7,tomcat3.2环境下调试通过。

<%@ page contentType="text/xml; charset=GB2312" import="org.xml.sax.*, org.apache.xerces.parsers.SAXParser, org.xml.sax.helpers.XMLFilterImpl, org.xml.sax.helpers.AttributesImpl, org.apache.xml.serialize.XMLSerializer, org.apache.xml.serialize.OutputFormat, org.apache.xml.serialize.Method" %><%! static String strParserName = "org.apache.xerces.parsers.SAXParser"; class FilterHandler extends XMLFilterImpl //这里通过继承XMLFilterImpl创建一个自己的过滤器 { int index = 0;   public void startElement( String uri, String localName, String qName, Attributes oAttributes) throws SAXException //过滤StartElement事件 { AttributesImpl oAttributesImpl = new AttributesImpl( oAttributes ); for( int i = 0 ; i < oAttributesImpl.getLength() ; i ++ ) { if( oAttributesImpl.getQName( i ).toUpperCase().equals("ID")) { oAttributesImpl.removeAttribute(i); break; } } oAttributesImpl.addAttribute("","id","id","ID",String.valueOf(index++)); super.startElement(uri, localName, qName, oAttributesImpl); } 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); } } %><% try { SAXParser oParser = (SAXParser)Class.forName(strParserName).newInstance(); //new SAXParser(); FilterHandler oFilter = new FilterHandler(); System.out.println("\nNow begin XML serielizing..."); oFilter.setParent( oParser ); XMLSerializer oXSerializer = new XMLSerializer( out , new OutputFormat(Method.XML,"GB2312",true)); //创建一个XMLSerializer的实例。 //这里使用了一个OutFormat的实例,第一个参数为一个字符串, //此处为Method.XML,实际上就是“XML”, //第二个参数为字符编码,第三个为是否输出退格。 oFilter.setContentHandler( oXSerializer.asContentHandler()); //上面一行设置Serializer作为过滤器的处理器。 oFilter.parse("d:\\mytest\\testXerces.xml"); } catch( Exception e ) { out.println(e.toString()); } %>

 

下图是运行的结果分别在Mozilla 0.8英文版和IE5.5中文版中的显示结果,由于没有使用任何格式化手段来美化显示效果,因此看着比较难看,但是至少所有的中文都显示出来了。另外还用各自浏览器的“查看源代码”选项显示了源代码。左上的窗口为Mozilla 0.8英文版的显示效果,右上为Mozilla 0.8显示的源代码。左下为IE5.5中文版显示的结果,右下为IE5.5显示的源代码效果。