SAX 解析 XML 实例

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<class>
<student>
<name>Kyte</name>
<gender>male</gender>
<job>engineer</job>
</student>
<student>
<name>Charry</name>
<gender>female</gender>
<job>manager</job>
</student>
</class>


JavaBean类:


package com.mypack.sax;

import java.io.Serializable;

public class Student implements Serializable
{

private static final long serialVersionUID = -5211833327339857099L;

private String name;

private String gender;

private String job;

public String getName()
{
return name;
}

public void setName(String name)
{
this.name = name;
}

public String getGender()
{
return gender;
}

public void setGender(String gender)
{
this.gender = gender;
}

public String getJob()
{
return job;
}

public void setJob(String job)
{
this.job = job;
}

@Override
public String toString()
{
return "{name = " + this.name + ", gender = " + this.gender + ", job = " + this.job + "}";
}

}




SAX 解析类:

package com.mypack.sax;

import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
* @date 2010-08-21
*/
public class SaxParser
{

/**
*
*/
public static void main(String[] args) throws SAXException, IOException
{
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
ClassesHandler handler = new ClassesHandler();

xmlReader.setContentHandler(handler);
xmlReader.parse("file:c:/t.xml");

System.out.println(handler.stus);

}

private static class ClassesHandler extends DefaultHandler
{

private List<Student> stus;
private Student stu;
private Stack<String> ctx;
private StringBuilder sb;

@Override
public void characters(char[] ch, int start, int length)
throws SAXException
{
if (ctx != null)
{
String tmp = new String(ch, start, length);
tmp = tmp.replaceAll("\\n|\\t+|\\s+", "");
this.sb.append(tmp);
}
}

@Override
public void endElement(String uri, String localName, String name)
throws SAXException
{
if (this.ctx.isEmpty())
{
return;
}

String tmp = this.ctx.pop();

if ("student".equals(tmp))
{
stus.add(stu);
stu = new Student();
}
else
{
try
{
PropertyDescriptor pd = new PropertyDescriptor(tmp, Student.class);
pd.getWriteMethod().invoke(stu, sb.toString());
}
catch (Exception e)
{
e.printStackTrace();
}
}

this.sb = new StringBuilder();
}

@Override
public void startDocument() throws SAXException
{
this.stus = new ArrayList<Student>();
this.stu = new Student();
this.ctx = new Stack<String>();
this.sb = new StringBuilder();
}

@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException
{
if ("student".equals(name) || !this.ctx.isEmpty())
{
ctx.push(name);
}
}

}

}




处理器范型实现


/*
* SAX Generic Handler
* Version: 1.0
* Date : 2010-08-24
*/
package com.mypack.sax;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
* SAX通用处理器,用于处理简单XML结构,范形实现
* @date 2010-08-24
*/
public class BeanHandlerForSAX<T> extends DefaultHandler
{
/** 目标集合 */
private List<T> list;

/** 目标实例 */
private T bean;

/** 用栈来存储XML格式的上下文 */
private Stack<String> ctx;

/** 用来收集节点值 */
private StringBuilder sb;

/**
* 目标类型,这个变量是必须的,
* 通过构造器进行约束
*/
private Class<T> clazz;

/** 开始封装的标签名 */
private String startNode;

/** 日志记录器 */
private final Log logger = LogFactory.getLog(getClass());

public BeanHandlerForSAX(Class<T> clazz)
{
this.clazz = clazz;
}

public BeanHandlerForSAX(Class<T> clazz, String startNode)
{
this.clazz = clazz;
this.startNode = startNode;
}

/**
* 取得目标结果集,有可能返回空集合,但不会是空,
* 所以不会导致空指针异常
*/
public List<T> getList()
{
if (this.list == null)
{
return Collections.EMPTY_LIST;
}

List<T> beanList = new ArrayList<T>(this.list);
this.list = null;
return Collections.unmodifiableList(beanList);
}

/**
* Xces解析器默认传递16K
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException
{
// 表示找到目标节点,将相应的值进行缓存,每次最大缓存16K,这跟底层解析器有关
if (ctx != null)
{
String tmp = new String(ch, start, length);

// 去除换行,退格,两端空格
tmp = tmp.replaceAll("\\n|\\t+", "").trim();
this.sb.append(tmp);
}
}

@Override
public void endElement(String uri, String localName, String name)
throws SAXException
{
// 为空表示还未找到目标节点,继续向下寻找
if (this.ctx.isEmpty())
{
return;
}

// 找到目标节点,出栈进行操作
String tmp = this.ctx.pop();

// 达到目标节点,将Bean加入List,继续下一个Bean实例的封装
if (this.startNode.equalsIgnoreCase(tmp))
{
list.add(bean);
newBeanInstance();
return;
}

// 属性未遍历完成,将值进行填充
try
{
PropertyDescriptor pd = new PropertyDescriptor(tmp, clazz);

Method writer = pd.getWriteMethod();
Class<?> type = pd.getPropertyType();

String stringValue = sb.toString();
Object value = null;

// 将目标串转换成所需要的类型
value = convert(type, stringValue);

// 如果值不空才进行设值,否则忽略
if (value != null)
{
writer.invoke(bean, value);
}
}

// 个别异常将不会影响程序执行流程,内部消化
catch (IntrospectionException e)
{
logger.error(e);
}
catch (IllegalArgumentException e)
{
logger.error(e);
}
catch (IllegalAccessException e)
{
logger.error(e);
}
catch (InvocationTargetException e)
{
logger.error(e);
}
catch (Exception e)
{
// 发生致命错误,应该通知调用方进行合理处理
throw new SAXException(e);
}

// 将节点值重新初始化,避免干扰其他的节点值
this.sb = new StringBuilder();

}

/**
* 类型转换器的简单封装
* @param type 目标类型
* @param target 目标串
* 有可能返回空,需要注意
*/
protected Object convert(Class<?> type, String target)
{
Object res = null;
if (type == String.class)
{
res = target;
}
else if (type == byte.class)
{
res = Byte.valueOf(target);
}
else if (type == int.class)
{
res = Integer.valueOf(target);
}
else if (type == float.class)
{
res = Float.valueOf(target);
}
else if (type == double.class)
{
res = Double.valueOf(target);
}
else if (type == boolean.class)
{
res = Boolean.valueOf(target);
}
else if (type == java.sql.Date.class)
{
res = java.sql.Date.valueOf(target);
}
else if (type == java.util.Date.class)
{
try
{
res = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss").parse(target);
}
catch (ParseException e)
{
logger.error(e);
}
}
return res;
}

/**
* 在文档开始时,进行处理器的初始化工作
*/
@Override
public void startDocument() throws SAXException
{
this.list = new ArrayList<T>(0);
this.ctx = new Stack<String>();
this.sb = new StringBuilder(0);
newBeanInstance();

// 在默认情况下,将简单类名当作目标节点开始标签
this.startNode = this.clazz.getSimpleName();
}

/**
* 通过反射,创建一个新的Bean实例
*/
private void newBeanInstance()
{
try
{
this.bean = clazz.newInstance();
}
catch (InstantiationException e)
{
logger.error(e);
}
catch (IllegalAccessException e)
{
logger.error(e);
}
}

/**
* 开始元素自动触发,只有在遇到目标节点才处理,
* 在上下文不空时亦可处理
*/
@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException
{
if (this.startNode.equalsIgnoreCase(name) || !this.ctx.isEmpty())
{
ctx.push(name);
}
}

}




解析的XML为:


<?xml version="1.0" encoding="UTF-8"?>
<class>
<student>
<name>Tom Kyte</name>
<gender>male</gender>
<job>engineer</job>
<age>16</age>
<height></height>
</student>
<student>
<name>Charry</name>
<gender>female</gender>
<job>manager</job>
<age>16</age>
</student>
</class>


使用方式:


XMLReader xmlReader = XMLReaderFactory.createXMLReader();

BeanHandlerForSAX<Student> h = new BeanHandlerForSAX<Student>(Student.class);
xmlReader.setContentHandler(h);

xmlReader.parse("file:c:/t.xml");

System.out.println(h.getList());



输出结果:
- java.beans.IntrospectionException: Method not found: isHeight
[{name = Tom Kyte, gender = male, job = engineer, age = 16}, {name = Charry, gender = female, job = manager, age = 16}]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值