java Xml 编程 简洁方案【Xpath + XStream】

对于Java操作XML数据,通常分为局部节点获取和整体文档操作两中方式;

一、Xpath 查询

对于一个xml文档,有时候我们只关心两三个节点的值,比如:错误返回码,返回信息等等;
这个时候我们可以利用Xpath来查询Xml文档,如下:
<!-- 正确的返回 -->
<?xml version=\"1.0\" encoding=\"GB2312\"?>
<yhjx_result>
    
<response>
        
<type>muti_exact_locate</type>
        
<result>
            
<result_id>3001</result_id>
            
<result_info>定位手机成功</result_info>
            
<datetime>2011-06-13 11:25:42</datetime>
            
<msid>15127119433</msid>
            
<area_name>中国河北省石家庄市桥西区南二环西路</area_name>
            
<img_url>
                http://60.217.33.201/infoservlet2/googleMap.html?longitude=114.49555
&amp;latitude=37.99993&amp;area=中国河北省石家庄市桥西区南二环西路
            
</img_url>
            
<external_note>*****</external_note>
        
</result>
    
</response>
</yhjx_result>

<!-- 带异常的返回 -->
<?xml version=\"1.0\" encoding=\"GB2312\"?>
<yhjx_result>
    
<response>
        
<type>muti_exact_locate</type>
        
<result>
            
<result_id>0004</result_id>
            
<result_info>手机号码未在该组织注册</result_info>
            
<datetime>2011-06-13 13:46:38</datetime>
            
<msid>15127119432</msid>
            
<area_name></area_name>
            
<img_url></img_url>
            
<external_note>*****</external_note>
        
</result>
    
</response>
</yhjx_result> 
我们只关心返回码 result_id ,result_info 和 img_url

所以,我们使用 Xpath 就可以很好解决:

  1 @Test

 2     public void testXml() throws ParserConfigurationException{
 3         HashMap<String,Object> msg = new HashMap<String,Object>();
 4         parseRespXml(msg,respXml);
 5         assertEquals("3001",msg.get("resultId"));
 6         System.out.println(msg.get("url"));
 7     }
 8     
 9     /**
10      * 解析返回的Xml
11      * 
12      * @param msg
13      * @param respXml
14      * @throws ParserConfigurationException 
15      */
16     private void parseRespXml(HashMap<String,Object> msg,String respXml) throws ParserConfigurationException{
17         XPathFactory xfactory = XPathFactory.newInstance();
18         XPath xpath = xfactory.newXPath();
19         try {
20             
21             Document doc = stringToDoc(respXml);
22             
23             XPathExpression resultIdPath = xpath.compile("//yhjx_result/response/result/result_id");
24             XPathExpression resultInfoPath = xpath.compile("//yhjx_result/response/result/result_info");
25             XPathExpression urlPath = xpath.compile("//yhjx_result/response/result/img_url");
26             
27             String resultId = (String)resultIdPath.evaluate(doc,XPathConstants.STRING);
28             
29             //返回成功
30             if("3001".equals(resultId)){
31                 String url = (String)urlPath.evaluate(doc,XPathConstants.STRING);
32                 msg.put("ok",true);
33                 msg.put("url", url);
34                 
35             }else{//返回错误信息
36                 String resultInfo = (String)resultInfoPath.evaluate(doc,XPathConstants.STRING);
37                 msg.put("ok",false);
38                 msg.put("msg", resultInfo);
39             }
40             
41         } catch (XPathExpressionException e) {
42             e.printStackTrace();
43         }
44     }
45     
46     /**
47      * String 转 XML org.w3c.dom.Document
48      */
49     public static Document stringToDoc(String xmlStr) {
50         //字符串转XML
51         Document doc = null;
52         try {
53             xmlStr = new String(xmlStr.getBytes(),"gb2312");
54             StringReader sr = new StringReader(xmlStr);
55             InputSource is = new InputSource(sr);
56             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
57             DocumentBuilder builder;
58             builder = factory.newDocumentBuilder();
59             doc = builder.parse(is);
60             
61         } catch (ParserConfigurationException e) {
62             System.err.println(xmlStr);
63             // TODO Auto-generated catch block
64             e.printStackTrace();
65         } catch (SAXException e) {
66             System.err.println(xmlStr);
67             // TODO Auto-generated catch block
68             e.printStackTrace();
69         } catch (IOException e) {
70             System.err.println(xmlStr);
71             // TODO Auto-generated catch block
72             e.printStackTrace();
73         }
74         return doc;
75     }

 单元测试代码!


2、XStream 使用

另一些情况下,我们对待一个 XML文档(报文)就相当于对实体类操作一下,需要关注xml每个节点、每个属性以及Value;

此时如果能够拥有一个类能够透明的转换实体类和Xml,那事情就会变得简单很多了!

以下这个例子就是一个较完整的XML应用;

 <!-- 请求报文 -->

<tvss>
    
<head>
        
<accessCode>TEST_CLIENT</accessCode>
        
<identify>AKDKJDKDKKAHDKSSHJAIDGAK</identify>
        
<businessType>GPS_CONTROLSENDMSG</businessType>
    
</head>
    
<body>
        
<reqMsg>
            
<car seq="1">
                
<controlType>1</controlType>
                
<carNo>京A22346</carNo>
            
</car>
            
<car seq="2">
                
<controlType>2</controlType>
                
<carNo>京B33488</carNo>
            
</car>
            
<car seq="3">
                
<controlType>2</controlType>
                
<carNo>京B33456</carNo>
            
</car>
            
<car seq="4">
                
<controlType>1</controlType>
                
<carNo>京B33459</carNo>
            
</car>
        
</reqMsg>
    
</body>
</tvss>

<!-- 应答报文 -->
<tvss>
    
<head>
        
<accessCode>TEST_CLIENT</accessCode>
        
<businessType>GPS_CONTROLSENDMSG</businessType>
        
<respCode>3001</respCode>
        
<respDesc>请求内容存在错误</respDesc>
    
</head>
    
<body>
        
<respMsg>
            
<fdbk seq="1">
                
<reqSeq>2</reqSeq>
                
<fcer seq="1">
                    
<erlc>carNo</erlc>
                    
<errs>该车未注册</errs>
                
</fcer>
            
</fdbk>
        
</respMsg>
    
</body>
</tvss>

 此时,XStream就是一个非常好的工具了 http://xstream.codehaus.org/

我可以根据Xml的结构来反向分析,建立我们的实体类,令人的兴奋的是,XStream也支持 Attribute的映射。

而且对Annotation的支持,也让代码变得非常简洁! 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

@XStreamAlias(
"tvss")
public class TvssReqMsg {
    
    
public TvssReqMsg() {
    }

    
public TReqHead head;
    
public TReqBody body;
    
    
public static class TReqHead {
        
        
public String accessCode;
        
public String identify;
        
public String businessType;
        
        
public TReqHead(){
            
        }
        
        
public TReqHead(String asCode,String idty,String bssType){
            
this.accessCode = asCode;
            
this.identify = idty;
            
this.businessType = bssType;
        }
    }
    
    
public static class TReqBody {
        
        
public ReqMsg reqMsg = new ReqMsg();
        
        
public TReqBody(){}
        
        
public TReqBody(Car...cars){
            reqMsg 
= new ReqMsg();
            reqMsg.cars 
= Arrays.asList(cars);
        }
        
        
public void addCar(int seq,String ctrlType,String carNo){
            
            Car car 
= new Car();
            car.seq 
= seq;
            car.controlType 
= ctrlType;
            car.carNo 
= carNo;
            
            reqMsg.cars.add(car);
        }
    }
    
    
public static class ReqMsg {
        @XStreamImplicit(itemFieldName
="car")
        
public List<Car> cars = new ArrayList<Car>();
    }
    
    
public static class Car {
        @XStreamAsAttribute
        
public int seq;
        
public String controlType;
        
public String carNo;
    }

}

 

/**
 * 应答 P&G 请求控制, 正确返回 0000; 错误返回3001或者其他代码
 * 
 * 
@author zx
 * 
 
*/
@XStreamAlias(
"tvss")
public class TvssRespMsg {

    
public static final String CONTROL_BSS_TYPE = "GPS_CONTROLSENDMSG";
    
    
public static final String LOCATION_BSS_TYPE = "GPS_LOCATION";
    
    
/**
     * 正常返回
     
*/
    
public static final String RC_0000 = "0000";
    
    
public static final String RC_1002 = "1002";

    
/**
     * 报文错误
     
*/
    
public static final String RC_3001 = "3001";

    
public static final String RC_9999 = "9999";

    
public RespHead head = new RespHead();

    
public RespBody body = new RespBody();

    
public TvssRespMsg() {
        
    }

    
/**
     * create a head in the constructor
     * 
     * 
@param acCode
     * 
@param bssType
     * 
@param rsCode
     * 
@param rsDesc
     
*/
    
public TvssRespMsg(String acCode, String bssType, String rsCode,
            String rsDesc) {
        
this.head.accessCode = acCode;
        
this.head.businessType = bssType;
        
this.head.respCode = rsCode;
        
this.head.respDesc = rsDesc;
    }

    
/**
     * 
     * 
@param seq
     * 
@param fcer
     * 
     
*/
    
public void addFdbk(int seq, String reqSeq, Fcer... fcer) {

        
if (RC_3001.equals(this.head.respCode)) {

            Fdbk fdbk 
= new Fdbk();
            fdbk.seq 
= seq;
            fdbk.reqSeq 
= reqSeq;
            fdbk.fcers 
= Arrays.asList(fcer);

            
this.body.respMsg.fdbks.add(fdbk);
        }
    }

    
public static class RespHead {
        
public String accessCode;
        
public String businessType;
        
public String respCode;
        
public String respDesc;
    }

    
/**
     * 包含一个 respMsg
     * 
     * 
@author zx
     * 
     
*/
    
public static class RespBody {
        
public RespMsg respMsg = new RespMsg();
    }

    
/**
     * 返回消息主体
     * 
     * 
@author zx
     * 
     
*/
    
public static class RespMsg {

        
/**
         * 错误反馈数据
         
*/
        @XStreamImplicit(itemFieldName 
= "fdbk")
        
public List<Fdbk> fdbks = new ArrayList<Fdbk>();
    }

    
/**
     * 错误反馈数据,包含1 ~ n个 Fcer
     * 
     * 
@author zx
     * 
     
*/
    
public static class Fdbk {

        @XStreamAsAttribute
        
public int seq;

        
public String reqSeq;

        @XStreamImplicit(itemFieldName 
= "fcer")
        
public List<Fcer> fcers = new ArrayList<Fcer>();
    }

    
/**
     * 错误描述
     * 
     * 
@author zx
     * 
     
*/
    
public static class Fcer {

        
public Fcer() {
        }

        
public Fcer(int seq, String erlc, String errs) {
            
this.seq = seq;
            
this.erlc = erlc;
            
this.errs = errs;
        }

        @XStreamAsAttribute
        
public int seq;

        
/**
         * 明细字段定位
         
*/
        
public String erlc;

        
/**
         * 错误描述
         
*/
        
public String errs;
    }
    
    @Override
    
public String toString(){
        
return this.head.businessType + ":" + this.head.respCode + ":" + this.head.respDesc;
    }
}

下面是单元测试,So easy!

public class TvssReqTest {
    XStream xstream 
= new XStream(new DomDriver());
    
    @Before
    
public void before(){
        xstream.processAnnotations(TvssReqMsg.
class);
    }

    @Test
    
public void toXmlThenFromXml() {
        
        TvssReqMsg tvss 
= new TvssReqMsg();
        
        TReqHead head 
= new TReqHead("annto","CB12A6C6020879AEFEBE7EF2A1B3F2BA""GPS_CONTROLSENDMSG");

        TReqBody body 
= new TReqBody();
        
        body.addCar(
1"1""京A22346");
        body.addCar(
2"2""京B33488");
        body.addCar(
3"2""京B33456");
        body.addCar(
4"1""京B33459");

        tvss.head 
= head;
        tvss.body 
= body;
        
        
//oneline out
        StringWriter sw = new StringWriter();
        xstream.marshal(tvss,  
new CompactWriter(sw));
        String strXML 
= sw.toString();
        
        System.out.print(strXML);
        
        TvssReqMsg obj 
= (TvssReqMsg) xstream.fromXML(strXML);

        assertNotNull(obj);
        assertEquals(
4,obj.body.reqMsg.cars.size());
        
    }

    
/**
     * 
     
*/
    @Test
    
public void xmlReaderTest() {
        
        String reqXml 
= "<?xml version=\"1.0\" encoding=\"GBK\"?><tvss><head><accessCode>annto</accessCode><identify>CB12A6C6020879AEFEBE7EF2A1B3F2BA</identify><businessType>GPS_CONTROLSENDMSG</businessType></head><body><reqMsg><car seq=\"1\"><controlType>1</controlType><carNo>京A22346</carNo></car><car seq=\"2\">    <controlType>2</controlType><carNo>京B33488</carNo></car><car seq=\"3\">    <controlType>2</controlType><carNo>京B33456</carNo></car><car seq=\"4\">    <controlType>1</controlType><carNo>京B33459</carNo></car></reqMsg></body></tvss>";

        TvssReqMsg obj 
= (TvssReqMsg) xstream.fromXML(reqXml);

        assertNotNull(obj);
        assertEquals(
4,obj.body.reqMsg.cars.size());
    }
}

 


总之,解决问题的办法多种多样,但是代码的可维护性却各不相同,只要我们善于思考和发现,优雅的办法总是有的!

posted on 2011-06-13 20:23  Herist  阅读(3772)  评论(0编辑  收藏  举报

导航