您的位置:首页 > 其它

xml 解析之digester

2006-08-21 09:16 176 查看
Java的xml解析,有很多名词,dom,jdom,sax,xslt,jaxp,jaxb,xerces,dom4j,castor等等,使用它们都能解析xml文档。要选择合适的解析方式,就要了解它们之间的关系,它们各自的分工。
dom、jdom、sax,xslt提供了不同的解析方式的体系结构定义(接口的定义),xerces,dom4j提供了xml语法分析器实现。
jaxp是j2ee的一部分,它只有很少类的一组api,对dom、sax提供了更高层的抽象,使我们可以比较容易的在这些方式上切换。
Jaxb、castor是更高级的api,他们可以根据xml的dtd或者scheme定义来生成相应的对象,并只需调用3-5行代码就可以把xml文档中的数据绑定到对象中,单从编程的角度上讲,使用非常方便。但是它们需要xml文档有一个明确的定义,那就是要么用dtd定义,要么用scheme定义。而我们很多xml文档只是口头上约定了xml文档的格式,并没有作这个步骤。
在此,我们选用另一个简单、高级的实用工具,这也是很多著名的开源项目采用的xml解析工具,apache的digester工具,它原是struts项目的的一部分,后来由于其通用性,成为jakarta commons里面的一个包。实际上它的工作方式和jaxb、castor很类似。
首先,需要根据约定的xml文档定义,定义相应的数据java bean,不是叶子节点的元素要定义成类对象,并且是其父节点元素的属性,如果叶子节点含有属性,也需要定义成类对象。
根节点元素对应的对象就是相当于整个xml文档。
在我们的例子中,定义了一个xml文档。
<trans>
<trans-header>
<socket-id>12345</socket-id>
</trans-header>
<trans-envelop>
<trans-code>cp0002</trans-code>
<operate-mode>01</operate-mode>
<trans-result>1</trans-result>
<trans-client>000001</trans-client>
<trans-game>123450</trans-game>
<trans-issue>200505</trans-issue>
</trans-envelop>
<trans-body>
<client-flow-no>00001</client-flow-no>
<ticket-bet-sum>3</ticket-bet-sum>
<draw-entry>1</draw-entry>
<multi-issue-flag>0</multi-issue-flag>
<total-amount>0.20</total-amount>
<bet-detail>007060102030405060107</bet-detail>
<log-gt-id>100000022</log-gt-id>
<operator-id>100002</operator-id>
</trans-body>
</trans>

根据文档,定义相应的对象,
Header.java
public class Header
{
/**
*
*/
private String socketId;

public String getSocketId()
{
return socketId;
}

public void setSocketId(String socketId)
{
this.socketId = socketId;
}

public String toString()
{
return "/n header " + "/n socketId :" + socketId;
}
}

Envelop.java

public class Envelop
{

/**
* 交易代码
*/
private String code;

/**
* 销售方式
*/
private String operateMode;

/**
* 是否返回结果: 1--返回,0--不返回
*/
private String result;

/**
* 交易终端号码
*/
private String client;

/**
* 游戏编号
*/
private String game;

/**
* 期号
*/
private String issue;

public String getClient()
{
return client;
}

/**
* @param client
*/
public void setClient(String client)
{
this.client = client;
}

public String getCode()
{
return code;
}

public void setCode(String code)
{
this.code = code;
}

public String getGame()
{
return game;
}

public void setGame(String game)
{
this.game = game;
}

public String getIssue()
{
return issue;
}

public void setIssue(String issue)
{
this.issue = issue;
}

public String getOperateMode()
{
return operateMode;
}

public void setOperateMode(String operateMode)
{
this.operateMode = operateMode;
}

public String getResult()
{
return result;
}

public void setResult(String result)
{
this.result = result;
}

public String toString()
{
StringBuffer buffer = new StringBuffer();

buffer.append("/n envelop ");
buffer.append("/n code: " + code);
buffer.append("/n operateMode: " + operateMode);
buffer.append("/n result: " + result);
buffer.append("/n client: " + client);
buffer.append("/n game: " + game);
buffer.append("/n issue: " + issue);

return buffer.toString();
}
}

Body.java(我们暂时不需要使用,所以只是声明了接口)
public interface Body extends Serializable
{

}

根元素对应的对象,是解析器返回的结果对象
public class TransInfo
{
/**
* 消息头
*/
private Header header;

/**
* 消息信封
*/
private Envelop envelop;

/**
* 消息体
*/
private Body body;

public Body getBody()
{
return body;
}

public void setBody(Body body)
{
this.body = body;
}

public Envelop getEnvelop()
{
return envelop;
}

public void setEnvelop(Envelop envelop)
{
this.envelop = envelop;
}

public Header getHeader()
{
return header;
}

public void setHeader(Header header)
{
this.header = header;
}

}
需要说明的是,在我们的类定义中,不需要类名,以及属性名称和xml文档一一对应,命名可以不同。

定义解析类
public class XmlParser
{
Digester digester;

/**
* 初始化解析器,设置解析模板
*/
private void initDigester()
{
digester = new Digester();
digester.setValidating(false);// 不验证xml格式的有效性

digester.addObjectCreate("trans", TransInfo.class); // 声明创建TransInfo对象

/* 设置解析头部模板 */
digester.addObjectCreate("trans/trans-header", Header.class);// 创建头部信息对象
// 设置解析头部属性
digester.addBeanPropertySetter("trans/trans-header/socket-id",
"socketId");
// 增加解析后产生的Header对象到结果对象TransInfo中
digester.addSetNext("trans/trans-header", "setHeader");

/* 解析信封信息,产生信封对象 */
digester.addObjectCreate("trans/trans-envelop", Envelop.class);
digester
.addBeanPropertySetter(
"trans/trans-envelop/trans-code",
"code");
digester.addBeanPropertySetter("trans/trans-envelop/operate-mode",
"operateMode");
digester.addBeanPropertySetter("trans/trans-envelop/trans-result",
"result");
digester.addBeanPropertySetter("trans/trans-envelop/trans-client",
"client");
digester
.addBeanPropertySetter(
"trans/trans-envelop/trans-game",
"game");
digester.addBeanPropertySetter("trans/trans-envelop/trans-issue",
"issue");
digester.addSetNext("trans/trans-envelop", "setEnvelop");
}

/**
* 以输入流为参数解析
* @param is
* 输入流
* @return
*/
public TransInfo parse(InputStream is)
{
if (is == null)
{
System.out.println(" not found xml file ");
return null;
}
TransInfo transInfo = null;
try
{
initDigester();
transInfo = (TransInfo) digester.parse(is);
/**
* parse body Body body = BodyHelper.getBody(is,
* transInfo.getEnvelop().getCode()); transInfo.setBody(body);
*/

} catch (IOException ioe)
{
System.out.println(" io exception");
ioe.printStackTrace();
} catch (SAXException saxe)
{
System.out.println(" sax exception");
saxe.printStackTrace();
}
return transInfo;
}

/**
* 以xml格式的字符串为参数解析
* @param xmlStr
* xml格式的字符串
* @return
*/
public TransInfo parse(String xmlStr)
{
if (xmlStr == null || xmlStr.length() < 1)
{
System.out.println(" not xml string ");
return null;
}
TransInfo transInfo = null;
try
{
initDigester();
transInfo = (TransInfo) digester.parse(xmlStr);

/**
* Body body = BodyHelper.getBody(xmlStr,
* transInfo.getEnvelop().getCode()); transInfo.setBody(body);
*/
} catch (IOException ioe)
{
System.out.println(" io exception");
ioe.printStackTrace();
} catch (SAXException saxe)
{
System.out.println(" sax exception");
saxe.printStackTrace();
}
return transInfo;
}

/**
* @param args
*/
public static void main(String args[])
{
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("touzhu.xml");

XmlParser parser = new XmlParser();
TransInfo info = parser.parse(is);
System.out.print(info.getHeader());
System.out.print(info.getEnvelop());
}

}

addObjectCreate()方法创建对象,配置遇到什么属性时创建什么对象
digester.addObjectCreate("trans/trans-header", Header.class)

addBeanPropertySetter()方法设置对象属性,配置什么节点元素对应什么属性,注意的是,digester设置属性时是用java反射的方式,所以一定要与相应的getter方法一致。
digester.addBeanPropertySetter("trans/trans-envelop/operate-mode",
"operateMode");
addSetNext()方法,使一个对象成为父对象的属性,这里增加解析后产生的Header对象到结果对象TransInfo中
digester.addSetNext("trans/trans-header", "setHeader");

使用该类的序列图如下:

BodyHelper类是一个辅助类,负责根据不同的头部信息中的消息类型,返回不同的Body类型。

上边的几个常用方式实际上是在配置解析规则,解析规则的配置,还可以采用xml配置文件的方式。
关于其他更详细的用法,请参考Digester相关的文档。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: