xml 解析之digester

来源:互联网 发布:淘宝助理客服电话 编辑:程序博客网 时间:2024/04/29 20:17

Javaxml解析,有很多名词,domjdomsaxxsltjaxpjaxbxercesdom4jcastor等等,使用它们都能解析xml文档。要选择合适的解析方式,就要了解它们之间的关系,它们各自的分工。

domjdomsaxxslt提供了不同的解析方式的体系结构定义(接口的定义),xercesdom4j提供了xml语法分析器实现。

jaxpj2ee的一部分,它只有很少类的一组api,对domsax提供了更高层的抽象,使我们可以比较容易的在这些方式上切换。

Jaxbcastor是更高级的api,他们可以根据xmldtd或者scheme定义来生成相应的对象,并只需调用35行代码就可以把xml文档中的数据绑定到对象中,单从编程的角度上讲,使用非常方便。但是它们需要xml文档有一个明确的定义,那就是要么用dtd定义,要么用scheme定义。而我们很多xml文档只是口头上约定了xml文档的格式,并没有作这个步骤。

在此,我们选用另一个简单、高级的实用工具,这也是很多著名的开源项目采用的xml解析工具,apachedigester工具,它原是struts项目的的一部分,后来由于其通用性,成为jakarta commons里面的一个包。实际上它的工作方式和jaxbcastor很类似。

首先,需要根据约定的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相关的文档。

 
原创粉丝点击