最近在做快捷支付这块,对XML这块接触的比较多.梳理XML这块的时候, 突然发现 Digester 对不管是 字符串的 XML 还是 XML文件都能很好的解析..不足点就是引用的 apache的东西有点多. (apache的东西 耦合性太高.....)不过确实好用..
首先是 import
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
这几个是主要的..至于还有其他的可以自己再加入.
一 : 然后是主方法(分两个,一个是 文件. 一个是 string字符串)
1:首先看 读取文件的主方法, 一些解释的话 可以上这个地址
http://onjava.com/pub/a/onjava/2002/10/23/digester.html?page=2 查看
public static void testXML1() throws ParseException{
File inputStream = new File("c:/jack/test.xml");
Digester configDigester = new Digester();
configDigester.setNamespaceAware(true);
configDigester.setValidating(false);
configDigester.setUseContextClassLoader(true);
//load rule set
configDigester.addRuleSet(new PaymentStatusCheckResponseRuleSet());
OrderCheckResponseConfig datas = new OrderCheckResponseConfig();
configDigester.push(datas);
try {
configDigester.parse(inputStream);
} catch (IOException e) {
e.printStackTrace();
throw new ParseException(e);
} catch (SAXException e) {
e.printStackTrace();
throw new ParseException(e);
}
Map responseProp = new HashMap();
responseProp.put("status", datas.getStatus());
responseProp.put("statusText", datas.getStatusText());
responseProp.put("msgCode", datas.getMsgCode());
responseProp.put("msgCn", datas.getMsgCn());
responseProp.put("orderDate", datas.getOrderDate());
responseProp.put("orderTime", datas.getOrderTime());
responseProp.put("orderNo", datas.getOrderNo());
responseProp.put("orderAmt", datas.getOrderAmt());
responseProp.put("currId", datas.getCurrId());
responseProp.put("payAmt", datas.getPayAmt());
responseProp.put("memo", datas.getMemo());
responseProp.put("payNo", datas.getPayNo());
responseProp.put("hostDate", datas.getHostDate());
responseProp.put("accNo", datas.getAccNo());
responseProp.put("hoistTime", datas.getHoistTime());
responseProp.put("accType", datas.getAccType());
responseProp.put("pbCstName", datas.getPbCstName());
System.out.println(responseProp);
}
addRuleSet , 可以写一个内部的 RuleSet 类,主要是用来读取XML的节点信息和内容的
/**
* Inner class for StatusCheckResponse ruleset
*/
class PaymentStatusCheckResponseRuleSet extends RuleSetBase{
public void addRuleInstances(Digester digester) {
digester.addCallMethod("stream/status", "setStatus", 1);
digester.addCallParam("stream/status", 0);
digester.addCallMethod("stream/statusText", "setStatusText", 1);
digester.addCallParam("stream/statusText", 0);
digester.addCallMethod("stream/msgCode", "setMsgCode", 1);
digester.addCallParam("stream/msgCode", 0);
digester.addCallMethod("stream/msgCn", "setMsgCn", 1);
digester.addCallParam("stream/msgCn", 0);
digester.addCallMethod("stream/orderDate", "setOrderDate", 1);
digester.addCallParam("stream/orderDate", 0);
digester.addCallMethod("stream/orderTime", "setOrderTime", 1);
digester.addCallParam("stream/orderTime", 0);
digester.addCallMethod("stream/orderNo", "setOrderNo", 1);
digester.addCallParam("stream/orderNo", 0);
digester.addCallMethod("stream/orderAmt", "setOrderAmt", 1);
digester.addCallParam("stream/orderAmt", 0);
digester.addCallMethod("stream/currId", "setCurrId", 1);
digester.addCallParam("stream/currId", 0);
digester.addCallMethod("stream/payAmt", "setPayAmt", 1);
digester.addCallParam("stream/payAmt", 0);
digester.addCallMethod("stream/memo", "setMemo", 1);
digester.addCallParam("stream/memo", 0);
digester.addCallMethod("stream/payNo", "setPayNo", 1);
digester.addCallParam("stream/payNo", 0);
digester.addCallMethod("stream/hostDate", "setHostDate", 1);
digester.addCallParam("stream/hostDate", 0);
digester.addCallMethod("stream/hoistTime", "setHoistTime", 1);
digester.addCallParam("stream/hoistTime", 0);
digester.addCallMethod("stream/accNo", "setAccNo", 1);
digester.addCallParam("stream/accNo", 0);
digester.addCallMethod("stream/accType", "setAccType", 1);
digester.addCallParam("stream/accType", 0);
digester.addCallMethod("stream/pbCstName", "setPbCstName", 1);
digester.addCallParam("stream/pbCstName", 0);
}
}
最后就是一个实体的接受类 Digester会push数据进来的(省了 get set 方法)
public class OrderCheckResponseConfig {
private String status; //该笔直联查询交易的状态
private String statusText;//该笔直联查询交易状态的说明
private String msgCode; //交易状态
private String msgCn; //交易状态信息
private String orderDate;//订单日期
private String orderTime;//订单时间
private String orderNo; //订单号
private String orderAmt;//订单金额
private String currId; //支付币种
private String payAmt; //支付金额
private String memo; //摘要信息
private String payNo; //支付交易流水号
private String hostDate;//主机操作日期
private String hoistTime;//主机操作时间
private String accNo; //支付卡号
private String accType; //卡号类型
private String pbCstName;//个人消费者中文姓名
这个 的 XML 比较简单 如下图所示.没有什么复杂的节点.
1 2 交易状态 交易状态信息 订单日期 订单时间 订单号 订单金额 支付币种 支付金额 摘要信息 支付交易流水号 主机操作日期 主机操作时间 支付卡号 卡号类型 个人消费者中文姓名
2:如果是字符串形式的话. 方法如下 (删除了一些, 还需要转变编码格式)
public static void testXML2() throws ParseException{
String text = "交易状态 交易状态信息 批次号银行受理成功总笔数 银行受理成功总金额 银行受理失败总笔数 银行受理失败总金额 " +
"商户充值退回流水号 liststatus liststatusText |
";
System.out.println(text);
InputStream inputStream=new ByteArrayInputStream(text..getBytes("gb2312"));//指定编码格式防止乱码
//File inputStream = new File("c:/jack/refund.xml");
Digester configDigester = new Digester();
configDigester.setNamespaceAware(true);
configDigester.setValidating(false);
configDigester.setUseContextClassLoader(true);
//load rule set
configDigester.addRuleSet(new CNCBRefundRuleset());
CNCBRefundConfig datas = new CNCBRefundConfig();
configDigester.push(datas);
try {
configDigester.parse(inputStream);
} catch (IOException e) {
e.printStackTrace();
throw new ParseException(e);
} catch (SAXException e) {
e.printStackTrace();
throw new ParseException(e);
}
Map responseProp = new HashMap();
responseProp.put("status", datas.getStatus());
responseProp.put("statusText", datas.getStatusText());
responseProp.put("batNo", datas.getStatus());
responseProp.put("sucTotalNum", datas.getSucTotalNum());
responseProp.put("sucTotalAmt", datas.getSucTotalAmt());
responseProp.put("errTotalNum", datas.getErrTotalNum());
responseProp.put("errTotalAmt", datas.getErrTotalAmt());
responseProp.put("cancelFlwNo", datas.getCancelFlwNo());
responseProp.put("liststatus", datas.getListsStatus());
responseProp.put("liststatusText", datas.getListstatusText());
System.out.println(responseProp);
}
设置RuleSet ,写一个内部类
class CNCBRefundRuleset extends RuleSetBase{
@Override
public void addRuleInstances(Digester digester) {
// TODO Auto-generated method stub
digester.addCallMethod("stream/status", "setStatus", 1);
digester.addCallParam("stream/status", 0);
digester.addCallMethod("stream/statusText", "setStatusText", 1);
digester.addCallParam("stream/statusText", 0);
digester.addCallMethod("stream/sucTotalAmt", "setSucTotalAmt", 1);
digester.addCallParam("stream/sucTotalAmt", 0);
digester.addCallMethod("stream/sucTotalNum", "setSucTotalNum", 1);
digester.addCallParam("stream/sucTotalNum", 0);
digester.addCallMethod("stream/errTotalNum", "setErrTotalNum", 1);
digester.addCallParam("stream/errTotalNum", 0);
digester.addCallMethod("stream/errTotalAmt", "setErrTotalAmt", 1);
digester.addCallParam("stream/errTotalAmt", 0);
digester.addCallMethod("stream/list/row/cancelFlwNo", "setCancelFlwNo", 1); //这里的 list 也可以用name 来表示.结果是一样的
digester.addCallParam("stream/list/row/cancelFlwNo", 0);
digester.addCallMethod("stream/list/row/status", "setListsStatus", 1);//以后不管子节点有多少,从最开始往下取,这样就很方便的解析了.
digester.addCallParam("stream/list/row/status", 0);
digester.addCallMethod("stream/list/row/statusText", "setListstatusText", 1);
digester.addCallParam("stream/list/row/statusText", 0);
}
}
实体bean
class CNCBRefundConfig{
private String status;
private String statusText;
private String batNo;
private String sucTotalNum;
private String sucTotalAmt;
private String errTotalNum;
private String errTotalAmt;
private String cancelFlwNo;
private String listsStatus; //如果有重名的,则可以加上list 这个 父节点,区别. 这个就解决了子节点太难读的缺点,可以按照节点路径取值.
private String liststatusText;
这个是 XML的 文件形式的. 上面字符串的删除了一些东西. 这个是完整的
交易状态 交易状态信息 批次号 银行受理成功总笔数 银行受理成功总金额 银行受理失败总笔数 银行受理失败总金额
|
商户充值退回流水号 liststatus liststatusText
这里面在整理的时候, 不是很方便整理. 而且还去掉了银行的缩写. 如有需要. 到时候再看有心情整理否.
------------------------------------------------------追加-----------------------
追加一点如果是 XML中的字段含有属性, 想获取属性值.原理差不多. 只是调用的方法不一样.
digester.addSetProperties("items/result", "value", "resultStatus");
在ruleset 里面 用这个就好了. 其中 resultStatus 是接受bean里面的一个属性.
--------------------------------------------------------继续追加----------------------------------------
如果是是下面这种格式的XML
则可以用更简单的编码格式.
RuleSetBase
public class ConfigRuleSet extends RuleSetBase{ //注意,需要继承RuleSetBase
public void addRuleInstances(Digester digester){
digester.setValidating( false );
digester.addObjectCreate("web", WebConfig.class) ;
digester.addSetProperties("web");
digester.addObjectCreate( "web/root", Root.class );
digester.addSetProperties("web/root");
digester.addSetNext( "web/root", "addRoot" );
digester.addObjectCreate( "web/root/bar", Bar.class );
digester.addSetProperties("web/root/bar");
digester.addSetNext( "web/root/bar", "addBar" );
}
}
编译解析XML
final String fileName = "/card/bean/Item.xml" ;
Items items = new Items() ;
Digester digester = new Digester() ;
ConfigRuleSet rule = new ConfigRuleSet();
rule.addRuleInstances(digester) ;
try {
items = (Items)digester.parse(new File(fileName)) ;
System.out.println("items size :" + items.getSize()) ;
System.out.println("items getResult :"+items.getResult());
Item[] item = items.getItemMap() ;
for (int i = 0; i < item.length; i++) {
System.out.println("item type:" + item[i].getType()) ;
Param[] param = item[i].getParams() ;
for (int j = 0; j < param.length; j++) {
if(j>0) System.out.println("/t------------------");
System.out.println("/param name:" + param[j].getName()) ;
System.out.println("/param value:" + param[j].getValue()) ;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
然后是各个 bean 之间的关系, 这里就不整理了.
这里摘自 :http://blog.csdn.net/gooing/article/details/381399