DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> Web 服務編程技巧和訣竅: 將 <xsd:any/> 元素用於自定義序列化
Web 服務編程技巧和訣竅: 將 <xsd:any/> 元素用於自定義序列化
編輯:XML詳解     

大多數情況下,JAX-RPC 假定出現在 SOAP 消息中的 XML 元素都應該映射到 Java 對象中去。對於簡單類型和復雜類型如何映射各有其規則說明,JAX-RPC 實現通常都提供了生成處理映射所需代碼的工具。好消息就是,如果您要處理應用程序中的 Java 對象,您不必擔心數據的類型映射以及序列化和反序列化。也就是說,您不需要知道如何解析 XML 元素,如何將它交給適當的 Java 對象,反之亦然。然而,在某些情況下,您可能想掌握(反)序列化是如何實現的。或者您根本就不想將 XML 數據映射到 Java 對象中去。幸運的是,在 JAX-RPC 中就有辦法能做到,本文將為您展示如何去做的技巧。

  SOAP with Attachments API for Java(SAAJ)

  JAX-RPC 規范依賴於 SAAJ 來處理 SOAP 消息的。SAAJ 定義了 SOAP 消息中各個部分的類與接口。首先介紹 javax.xml.soap.SOAPMessage 類,您可以通過這個類訪問 javax.xml.soap.SOAPEnvelope 實例,緊接著又可以通過這個實例獲取 javax.xml.soap.SOAPHeader 實例和 javax.XML.soap.SOAPBody 實例,等等。所有這些實例都是對 Javax.XML.soap.SOAPElement 接口的擴展與繼承,而這個接口本身也是對 W3C DOM Node 接口的擴展。

  換句話說,SAAJ 給您提供了以 XML 為中心的角度來看待 SOAP 消息中的元素。JAX-RPC 將所有的消息處理都委托給了 SAAJ。請注意此處我並不打算全面地介紹 SAAJ,我只想討論一些本文主題所需要的方面。

  <xsd:any/> 元素

  <xsd:any/> 元素是表示 XML 文檔中任意 XML 內容的元素。顧名思義,它可以是任何一種 XML。這使您可以在 XML Schema 中創建復雜類型定義,而不用描述復雜類型的某些部分的具體結構。下面是一個示例(請參見 清單 1)展示了一個名為 Order 類型的定義。它包含兩個普通元素和一個 <xsd:any/> 元素。

清單 1. 帶有 <xsd:any/> 的 XML Schema

<schema elementFormDefault="qualifIEd"
  targetNamespace="http://anytip.webservices.ibm.com"
  xmlns="http://www.w3.org/2001/XMLSchema">
  <complexType name="Order">
   <sequence>
     <element name="createDate" nillable="true" type="xsd:dateTime"/>
     <element name="customer" nillable="true" type="xsd:string"/>
     <xsd:any maxOccurs="unbounded"/>
   </sequence>
  </complexType>
</schema>

  這種類型的實例可以包含任意多個附加 XML 元素同時卻不違反 schema 定義。這樣一來,您就可以將附加信息添加到 Order 元素,而不用在 Schema 中定義它的格式。

  組合在一起

  那麼,JAX-RPC 如何處理包含 <xsd:any/> 元素的 XML Schema 呢?最新發布的 JAX-RPC 1.1規范中定義了這種元素被映射到 SAAJ 的 javax.xml.soap.SOAPElement 接口(請參閱 參考資料)。這意味著服務端點接口將會包含有一個參數或者在 schema 中用到 <xsd:any/> 的每個地方返回 javax.XML.soap.SOAPElement 類型的值,如果 maxOccurs 屬性值大於1,就分別返回 Javax.XML.soap.SOAPElement[] 類型的值。

  因此,JAX-RPC 工具將從上面的樣本 Schema 中生成以下類(請參見 清單 2)(與通常的情況一樣,這個樣本沒有什麼意義,僅僅只是說明了概念;如常,您也可以在 參考資料部分找到本文中的完整源代碼):

清單 2. 生成的 Order 類

public class Order implements Java.io.Serializable {
  private Java.util.Calendar createDate;
  private Java.lang.String customer;
  private Javax.XML.soap.SOAPElement[] _any;
  ...
}

  所有這些與自定義序列化有什麼關系呢?假定您的 Web 服務使用了一些您並不想映射到 Java 類中的數據,而是想讓 JAX-RPC 引擎以 XML 形式將這些數據交給實現。該實現然後就就能夠解析數據或者簡單地將它作為 XML 傳遞到後端應用程序以進行進一步的處理。類似地,您可以創建一個客戶端代理,這個代理允許您在 SOAPElement 而不是 Java 對象中傳送。

  示例

  這個示例在您預先知道 XML 數據結構的情況下也能夠正常運行。設想您使用的是一個 OrderManager Web 服務,它是基於某些搜索標准來返回 Order 數據的。每個 Order 實例都包含有很多行式項目(line items)。 清單 3 中是對 WSDL 的摘錄。假定這是一個非常簡單易懂的 Web 服務,我們將只關注此處的 <types> 部分。

  清單 3. 用於 Web 服務的 WSDL

<?XML version="1.0" encoding="UTF-8"?>
<wsdl:definitions ...>
<wsdl:types>
 <schema elementFormDefault="qualifIEd"
     targetNamespace="http://any.webservices.ibm.com"
     xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="getOrder">
  <complexType>
   <sequence>
   <element name="searchCriteria"
        nillable="true" type="xsd:string"/>
   </sequence>
  </complexType>
  </element>
  <complexType name="Order">
  <sequence>
   <element name="createDate" nillable="true" type="xsd:dateTime"/>
   <element name="customer" nillable="true" type="xsd:string"/>
   <element name="lineItems" nillable="true" type="impl:LineItem"
       maxOccurs="unbounded"/>
  </sequence>
  </complexType>
  <complexType name="LineItem">
  <sequence>
   <element name="itemDesc" nillable="true" type="xsd:string"/>
   <element name="itemNumber" nillable="true" type="xsd:string"/>
  </sequence>
  </complexType>
  <element name="getOrderResponse">
  <complexType>
   <sequence>
   <element name="getOrderReturn"
        nillable="true" type="impl:Order"/>
   </sequence>
  </complexType>
  </element>
 </schema>
</wsdl:types>
...
</definitions>

現在想象一下您不想讓 JAX-RPC 引擎來生成與結構相映射的 LineItem Java 類(如 XML Schema 中所定義的),而想自己來處理 XML (或許因為您要將它直接作為 XML 存儲在數據庫中,以致於解析數據就顯得毫無必要了)。因此,在此 Web 服務中生成客戶端代碼之前,您要更改 WSDL 文件,⒁? <xsd:any/> 元素替換掉表示 lineItem 的元素。這樣現在的 Order 復雜類型看起來就跟您之前看到的完全一樣了。JAX-RPC 工具現在將生成一個包含有 SOAPElement 屬性的客戶端 Order 類,而不是 lineItem 類。上面的示例已經展示該類。

  現在,您可以創建將從 Web 服務檢索 Order 的客戶端代碼,並以 XML 的格式使用行式項目信息。 清單 4 中是一個示例測試客戶端,這個示例是使用 WebSphere Application Server V5.0.2 生成的,您可以看到它可以看起來是什麼樣的:

  清單 4. 樣本客戶端代碼

public class TestMain {
public static void main(String[] args) throws Exception {
 OrderManager om =
         new OrderManagerServiceLocator().getOrderManager();
 Order order = om.getOrder("whatever");
 SOAPElement lineItem = order.get_any()[0];
 System.out.println("Line item is : "+lineItem.toString());
}
}

  此客戶端應用程序將檢索作為 Java 對象的 Order ,但行式項目信息是以 XML 的格式作為 SOAPElement 的一個數組返回的。

  總結

  JAX-RPC 提供了以 Java 為中心的角度來看待 Web 服務。如果您想自己處理 SOAP 消息中的某些 XML 結果,您可以使用 SAAJ API 並結合 <xsd:any/> 元素來實現。您可以期待著未來版本的 JAX-RPC 引擎實現將會使這一切更加容易。事實上,JAX-RPC 1.1 規范要求符合規范的工具對每種類型都提供是映射到 Java 類還是映射到 Javax.XML.soap.SOAPElement 的選項。


 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved