2014年2月20日 星期四

如何以dom4j使用XPATH尋找擁有namespace的node節點?




<ns0:ServiceEnvelope
xmlns:ns0="http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/EMF/ServiceEnvelope">
<ns1:ServiceHeader
xmlns:ns1="http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/EMF/ServiceHeader">
<ns1:StandardType>BSMF</ns1:StandardType>
<ns1:StandardVersion>01</ns1:StandardVersion>
<ns1:ServiceName>ccMrchntProfileInq</ns1:ServiceName>
<ns1:ServiceVersion>01</ns1:ServiceVersion>
<ns1:SourceID>TWINMI</ns1:SourceID>
<ns1:TransactionID>INMI201402071434225</ns1:TransactionID>
<ns1:RqTimestamp>2014-02-07T14:34:25.11+08:00</ns1:RqTimestamp>
</ns1:ServiceHeader>

<ns1:ServiceBody
xmlns:ns1="http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/EMF/ServiceHeader">
<ns2:ccMrchntProfileInqRq
xmlns:ns2="http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/BSMF/ccMrchntProfileInqRq/01">
<ns2:REQHDR>
<ns2:TrnNum>INMI201402071434239</ns2:TrnNum>
<ns2:TrnCode>JCMI</ns2:TrnCode>
</ns2:REQHDR>
<ns2:REQBDY>
<ns2:FunCode>I</ns2:FunCode>
<ns2:MerchNBR>010100028</ns2:MerchNBR>
</ns2:REQBDY>
</ns2:ccMrchntProfileInqRq>
</ns1:ServiceBody>
</ns0:ServiceEnvelope>

(上述XML不知道要怎麼在blog中下語法如之前那樣貼...只好貼無排版純文字了...)

因為上述的<ServiceBody>我需要將其中的namespace換成xmlns:ns1="http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/EMF/ServiceBody,原先我依照以前使用xPath的方式如下:


      
Node  nodeB = root.selectSingleNode("//ns0:ServiceEnvelope/ns1:ServiceBody");


然而,光直行道selectSingleNode(..)就跳出了exception:

org.dom4j.XPathException: Exception occurred evaluting XPath: /ns0:ServiceEnvelope/ns1:ServiceBody. Exception: XPath expression uses unbound namespace prefix ns1

,參考上述的網站說明,原來這種擁有namespace的,要先告知namespace實際上代表的位置在哪,才能做搜尋,修改後方式如下:

        DefaultXPath xpath = new DefaultXPath("//ns0:ServiceEnvelope/ns1:ServiceBody");
Map uris = new HashMap();
uris.put("ns0","http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/EMF/ServiceEnvelope");
uris.put("ns1", "http://ns.chinatrust.com.tw/XSD/CTCB/ESB/Message/EMF/ServiceHeader");
xpath.setNamespaceURIs(uris); 
Node nodeB = xpath.selectSingleNode(root.getDocument());  

因為此節點,在//ns0:ServiceEnvelope/ns1:ServiceBody的位置,一共使用了ns0與ns1的namespace,因此在setNamespaceURIs(Map)中要將兩個namespace都置入,才能找到,
若一次要找的是多個Node,使用selectNodes()即可(本例因為ServiceBody只會有一個,因此使用selectSingleNode()即可.


p.s:XML其實不是很好懂呢...這兩天花了不少時間看XSD,XML關於namespace的問題...

沒有留言:

張貼留言