java的sax解析是基于事件的解析:当解析到xml的某个部分的时候,会触发特定事件,可以在自定义的解析类中定义当事件触发时要做得事情。
我们可以继承org.xml.sax.helpers.DefaultHandler类(该类是org.xml.sax.helpers.ContentHandler的接口实现类)来覆盖ContentHandler接口的各种方法,这些方法将定义各个事件所触发的程序动作。
package com.thomas.xml.sax;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ThomasSAXHandler extends DefaultHandler {
private StringBuffer xml;//格式化后的XML文件内容
private static int step = 0;//元素层次
public ThomasSAXHandler(){
this.xml = new StringBuffer();
}
public StringBuffer getXml() {
return xml;
}
public void setXml(StringBuffer xml) {
this.xml = xml;
}
/**
* 给字符串添加TAB,使其能格式化输出,在这里第step层元素缩进step个Tab
*/
private void appendTab(){
for(int i = 1 ; i<step; i++){
for(int j = 0 ;j<4; j++){
xml.append(' ');
}
}
}
/**
* 接收元素中字符数据的通知。
* @param ch - 字符。
* @param start - 字符数组中的开始位置。
* @param length - 从字符数组中使用的字符数。
*/
public void characters(char[] ch, int start, int length) throws SAXException {
String text = new String(ch,start,length);
text = text.trim();
if(!text.equals("")){
step++;
appendTab();
xml.append(text).append("/r/n");
step--;
}
}
/**
* 接收文档的结尾的通知。
* @exception SAXException - 任何 SAX 异常,可能包装另外的异常。
*/
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
}
/**
* 接收元素结束的通知
* @param uri - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
* @param localName - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
* @param qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
* @exception SAXException - 任何 SAX 异常,可能包装另外的异常。
*/
public void endElement(String uri, String localName, String qName) throws SAXException {
appendTab();
xml.append("</");
if(!uri.equals("")){
xml.append(uri+":");
}
xml.append(qName).append(">/r/n");
step--;
}
/**
* 结束前缀 URI 范围的映射。
* @param prefix - 被映射的前缀。当默认的映射范围结束时,这是一个空字符串。
* @exception SAXException - 客户端可能会在处理期间抛出一个异常
*/
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub
}
/**
* 接收元素内容中可忽略的空白的通知。
* @param ch 来自 XML 文档的字符
* @param start 数组中的开始位置
* @param length 从数组中读取的字符的个数
* @exception SAXException - 任何 SAX 异常,可能包装另外的异常
*/
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
}
/**
* 接收处理指令的通知。
* @param target 处理指令目标
* @param data 处理指令数据,如果未提供,则为 null。该数据不包括将其与目标分开的任何空白
*/
public void processingInstruction(String target, String data) throws SAXException {
// TODO Auto-generated method stub
}
/**
* 接收用来查找 SAX 文档事件起源的对象
* @param locator 可以返回任何 SAX 文档事件位置的对象
*/
public void setDocumentLocator(Locator locator) {
// TODO Auto-generated method stub
}
/**
* 接收跳过的实体的通知。将不为标记结构(如元素开始标记或标记声明)内的实体引用调用此方法。(XML 建议书要求报告所跳过的外部实体。SAX 还报告内部实体扩展 / 非扩展,但不包括在标记结构内部。)
* @param name - 所跳过的实体的名称。如果它是参数实体,则名称将以 '%' 开头,如果它是外部 DTD 子集,则将是字符串 "[dtd]"
* @exception SAXException - 任何 SAX 异常,可能包装另外的异常
*/
public void skippedEntity(String name) throws SAXException {
// TODO Auto-generated method stub
}
/**
* 接收文档的开始的通知
* @exception - SAXException - 任何 SAX 异常,可能包装另外的异常
*/
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
}
/**
* 接收元素开始的通知。
* @param uri - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
* @param localName - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
* @param qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
* @param attributes - 附加到元素的属性。如果没有属性,则它将是空的 Attributes 对象。
* @exception SAXException - 任何 SAX 异常,可能包装另外的异常
*/
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
step++;//元素层次加一
appendTab();
xml.append("<");
if(!uri.equals("")){
xml.append(uri+":");
}
xml.append(qName);
for(int i = 0, size = attributes.getLength(); i<size; i++){
xml.append(' ').append(attributes.getQName(i)).append("=/"").append(attributes.getValue(i)).append("/"");
}
xml.append(">/r/n");
}
/**
* 开始前缀 URI 名称空间范围映射。
* @param prefix - 声明的名称空间前缀。对于没有前缀的默认元素名称空间,使用空字符串。
* @param uri - 将前缀映射到的名称空间 URI
* @exception - SAXException - 客户端可能会在处理期间抛出一个异常
*/
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// TODO Auto-generated method stub
}
}
上面是我们自定义的解析器,可以在带有main方法的类中加以测试
package com.thomas.xml.sax;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
public class Test {
public static void main(String[] args){
try{
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sp = sf.newSAXParser();
ThomasSAXHandler handler = new ThomasSAXHandler();
sp.parse(new InputSource("film.xml"),handler);
System.out.println(handler.getXml());
}
catch(Exception e){
e.printStackTrace();
}
}
}
下面是Kungfu.xml
<?xml version="1.0" encoding="gb2312"?>
<Kungfu-vips>
<vip>
<name lang="en,ch">Bruce Li</name>
<age>32</age>
<sex>male</sex>
</vip>
<vip>
<name lang="en,ch">Jakie Chen</name>
<age>39</age>
<sex>male</sex>
</vip>
<vip>
<name lang="en,ch">Jet Li</name>
<age>39</age>
<sex>male</sex>
</vip>
</Kungfu-vips>
运行test类,可以看到输出结果:
<Kungfu-vips>
<vip>
<name lang="en,ch">
Bruce Li
</name>
<age>
32
</age>
<sex>
male
</sex>
</vip>
<vip>
<name lang="en,ch">
Jakie Chen
</name>
<age>
39
</age>
<sex>
male
</sex>
</vip>
<vip>
<name lang="en,ch">
Jet Li
</name>
<age>
39
</age>
<sex>
male
</sex>
</vip>
</Kungfu-vips>