WebSphere Integration Developer V7 中的 XML 對映,第 2 部分: 處理複雜的 XML 結構

CloudSpace發表於2010-09-21
Shane Cartledge, 服務分析師, IBM
Peter Cinat, 軟體開發人員,WebSphere Integration Developer, WSO2 Inc
David Lauzon, 顧問軟體開發人員, IBM
Andrea Rice, 高階軟體開發人員,WebSphere Integration Developer, WSO2 Inc
Dave Spriet, 對映和轉換工具架構師, IBM

簡介: 這個共兩部分的系列的第 2 部分將介紹在 WebSphere® Integration Developer V7.0.0 中建立 XML 對映的高階方法,包括對映陣列和其他複雜的結構以及定製轉換的執行。

簡介

這個共兩部分的系列的第 1 部分,使用 Mapping Editor 開發對映,向您展示瞭如何使用 IBM® WebSphere Integration Developer V7.0.0(此後簡稱為 Integration Developer)快速建立健壯且結構良好的 XML 對映。另外還描述了用於測試和除錯對映的工具,從而及早作出問題診斷。第 2 部分將向您展示如何執行更復雜的 XML 對映。

使用陣列

源或目標中的某些欄位可重複使用,在這種情況下有一個特定元素陣列。一般來說,當您在使用陣列時,通常先將輸入陣列對映到輸出陣列,這會建立如 圖 1 所示的 For-each 轉換。


圖 1. 陣列的處理
陣列的處理

我們不建議您直接對映一個陣列元素的子陣列而不使用父陣列上的 For-each,例如 圖 2 就不應該完成類似於上面 圖 1 中所示的對映。


圖 2. 陣列的處理
陣列的處理

預設情況下,當您將一個輸入陣列連線到一個 For-each 轉換時,它會對輸入陣列中所有元素進行迭代處理,而每個陣列元素將會根據 For-each 對映內定義的巢狀對映得到對映。

類似於一個 Local map,For-each 是一個不生成任何結果的容器對映,除非有巢狀對映定義瞭如何操作輸入陣列的每個迭代。因此,您必須具體指定將源中的哪些欄位對映到目標中的哪些欄位,從而完成 For-each 實現。例如,圖 3 顯示了一個 For-each 對映內的巢狀對映。


圖 3. For-each 巢狀對映
For-each 巢狀對映

處理陣列時,這裡是一些您可能會遇到的其他場景。

場景 1. 從一個源陣列到一個單一目標欄位的對映

與處理陣列的一般情況一樣,首先在源陣列元素和目標欄位之間建立一個對映。在該場景中,頂級對映將會是一個 Local map 或 Move,因為一個 For-each 僅在源和目標是陣列時才適用。在這種具體情況下,您需要決定要使用哪個輸入陣列元素。您可以在 Properties 頁面的 Cardinality 選項卡上為 Local map 或 Move 轉換設定適用的陣列索引。在 Cardinality 選項卡上指定一個索引時,索引號從 1 而非從 0 開始。

為闡釋這種情況,考慮 圖 4 中帶以下源和目標的以下示例。


圖 4. 對映前的單一目標
對映前的單一目標

在本例中,源包含帶城市名和國家名的目標物件陣列,而目標預期僅有一個城市名和一個國家名。在這種情況下,您需要選取目標陣列的第一個條目並將其城市和國家名對映到目標單例。第一步是要在陣列和包含想填充的欄位的目標項之間建立一個 Local map,如圖 5 所示。


圖 5. 對映後的單一目標
對映後的單一目標

建立好 Local map 之後,設定基數以表明第一個陣列條目將是 Local map 轉換的輸入。在 Local map 內,目標元素的欄位被匹配到 GetWeather 元素的合適欄位,如圖 6 所示。


圖 6. 區域性巢狀對映
區域性巢狀對映

場景 2. 從一個單一源欄位到目標中一個陣列的對映

在該場景中,假定目標陣列僅包含一個元素,您再次需要在源欄位和目標陣列之間建立一個 Local map。在 Local map 內,詳細填寫將源中的哪些欄位對映到目標中的哪些欄位。

您可以在目標陣列中填充多個元素,只需建立到陣列的多個 Local map 並在 Properties 頁面的 Cardinality 選項卡上指定不同的索引。您還可使用一個 Merge 轉換,從而使用源中來自兩個或多個不同單例的資訊來填充目標中的一個陣列元素。在 Cardinality 選項卡上指定輸出陣列索引時,索引號從 1 而非從 0 開始。

場景 3. 從源中多個陣列到目標中單一陣列的對映

在某些情況下,您可能在源中有兩個或多個陣列,可用於建立目標中的單一陣列。在這種情況下可能會獲得兩種結果。第一種結果就是合併輸入陣列中的條目來為目標陣列形成單一條目。另一種希望的結果就是將來自輸入陣列的條目附加在一起形成更長的輸出陣列。這兩種情況將在下面詳細描述。

情況 1 — Merge

在這種情況下,您要將來自源的兩個陣列合併為目標上的單一陣列。例如,假設源包含兩個獨立的陣列:姓名陣列和電話號碼陣列。假定電話號碼列表與姓名列表一一對應,且輸出陣列包含需要一個姓名和電話號碼的元素,您可以將來自兩個獨立陣列的資訊合併為目標上的一個單一陣列。

在該情況下,您可以使用 Merge 轉換完成所需的結果。類似於一個 For-each,Merge 轉換是一個不生成任何結果的容器對映,除非有巢狀對映定義瞭如何操作輸入陣列的每個迭代。因此,您必須具體指定將源中的哪些欄位併入目標中的哪些欄位,從而完成 Merge 實現。注意,迭代是在一個 Merge 中執行的:整個流程首先選取所有 輸入陣列的第一個索引並將這些欄位併入目標陣列中的第一個索引。然後選取所有輸入陣列的第二個索引來生成目標陣列的第二個索引,以此類推。看待合併的一種簡單方式是,假如您選取兩個大小相同的陣列並將它們合併在一起,您會獲得與原始陣列大小相同的一個目標陣列。圖 7 就顯示了這樣一個例子。


圖 7. Merge 對映
Merge 對映

如果一個 Merge 轉換的輸入陣列大小不同,您可以指定在 Cardinality 屬性頁面上迭代哪個輸入。預設情況下會將迭代設定為 Merge 轉換的第一個輸入。不過,在輸入陣列大小不同時指定要迭代的輸入陣列會在目標陣列上產生不同的結果。圖 8圖 9 通過示例闡釋了在已知輸入陣列大小不同時產生的不同結果。


圖 8. 陣列大小不同時的合併
陣列大小不同時的合併

圖 9. 陣列大小不同時的合併
陣列大小不同時的合併

在上述示例中,生成的目標陣列的大小直接取決於所選擇的要進行迭代的輸入陣列。如果已知輸入陣列的大小在執行對映的過程中是相同的,那麼不管選擇進行迭代的輸入是哪個,產生的結果都一樣。

情況 2 - Append

在這種情況下,您要選取一個源陣列和另一個源陣列上的所有元素,在目標上建立一個包含兩個源陣列所有元素的陣列。例如,假定您在源上有兩列旅行目的地,且您希望在目標上建立一個包含所有目的地的單一列表。

在該情況下,您可以使用 Append 轉換完成所需的結果。看待 Append 的一種簡單方式是,如果您選取任何大小的兩個陣列將其附加在一起,您獲得的目標陣列就是輸入陣列大小的總和。圖 10 就顯示了這樣一個例子。


圖 10. Append 對映
Append 對映

類似於一個 For-each,Append 轉換是一個不生成任何結果的容器對映,除非有巢狀對映定義瞭如何操作輸入陣列的每個迭代。因此,您必須具體指定將源中的哪些欄位附加到目標中的哪些欄位,從而完成 Append 實現。在實現 Append 轉換時,通過 For-each 和 Move 對映會自動生成巢狀對映的第一層。在巢狀的 For-each 對映內需要進一步對映來完成實現。

在一個 Append 對映中執行迭代的方法是:首先選取第一個輸入陣列的第一個索引來生成目標陣列中的第一個索引。然後選取第一個輸入陣列的第二個索引來生成目標陣列的第二個索引。該過程一直持續到第一個輸入的所有元素執行完畢為止,之後處理第二個輸入陣列的所有元素(一個接一個),以此類推。附加輸入陣列的次序基於其進入 Append 轉換的次序。必要時,您可以在 Append 轉換上的 Order Property 頁面中修改該次序。

為陣列排序

在將源陣列用作轉換的一個輸入時,您可以選擇對輸入陣列元素排序,使其位於任何其他對映之前。這可以使用 For-each 轉換的 Properties 頁面完成。您可在要進行排序的陣列中指定欄位。還可以指定是使用詞彙搜尋還是數值搜尋,是按升序排列還是按降序排列。例如,假定您有一個目的地陣列,其中每個目的地都有一個城市名和一個國家名。假定您希望基於城市名按字母升序排列列表。您可以使用 For-each 轉換的 Properties 頁面來指定如 圖 11 所示的排序。


圖 11. 為陣列排序
為陣列排序

篩選陣列

有時在處理陣列輸入時,您可能只想使用陣列中的特定元素。如果是這樣,您可以在 Properties 檢視的 Cardinality 選項卡上指定適用的陣列索引或應用一個篩選表示式到轉換。

Cardinality

您可使用 Cardinality 來確定哪些陣列索引會被用作轉換的輸入。您可以指定單個索引,索引範圍或逗號分隔的索引列表。表 1 顯示了公認的特殊字元。


表 1. Cardinality 語義

字元 含義
: 用於指定值域
, 用於分隔索引和/或範圍列表的分隔符
* 直到陣列末尾的所有索引

表 2 顯示瞭如何使用上述特殊字元指定基數的一些示例。


表 2. Cardinality 語義示例

含義
1 僅為 1 的元素
1:3 從 1 到 3 的元素
2:* 2 及其以上的元素
1,3,5:* 1、3、5 及其以上的元素

陣列索引號從 1 而非 0 開始。

使用 XPath 表示式進行篩選

在處理輸入陣列時,您可以對轉換使用一個篩選表示式,以從源陣列中篩選需要的元素。在這種情況下,篩選表示式決定要選擇源陣列中的哪些元素。編寫篩選表示式是為了返回 For-each 將操作的節點集。要返回合適的節點集,應將篩選表示式編寫為一個謂語,而非真或假條件。例如,假定您有一個旅行目的地陣列,其中每個目的地都有一個城市名和國家名。假定您希望刪除國家名為 North Pole 的任何目的地。在這種情況下,您可以新增一個篩選表示式到如 圖 12 所示的 For-each 轉換。


圖 12. 使用 XPath 表示式進行篩選
使用 XPath 表示式進行篩選

未設定為 North Pole 的所有目的地將作為 For-each 對映的輸入。而設定為 North Pole 的目的地會被忽略且不屬於 For-each 對映輸入的一部分。

巢狀陣列

Group 細分支援將一個陣列轉化為一個巢狀陣列。例如,假定您有一個旅行目的地陣列,其中列表中的每個目的地都有一個類別,用於表明旅行目的地的型別。如果您想通過這些目的地建立一個巢狀陣列(其中類別構成頂級陣列且每個類別中的目的地構成巢狀陣列),那麼可以使用一個 Group 轉換。圖 13 顯示了 Group 轉換,它將目的地按類別分成巢狀陣列。注意,在 圖 13 中 Group 轉換的 Properties 頁面中,指定將類別欄位作為分組標準。


圖 13. Group 對映
Group 對映

類似於一個 Local map,Group 是一個不生成任何結果的容器對映,除非有巢狀對映定義瞭如何操作輸入陣列的每個迭代。因此,您必須具體指定將源中的哪些欄位對映到目標中的哪些欄位,從而完成 Group 實現。

目前沒有轉換會允許您將巢狀陣列分解為單個陣列。不過,您可以使用一個定製的 XSLT 轉換來將巢狀陣列轉化為單個陣列。欲瞭解如何實現該轉換,請參見本文的 Custom XSLT 部分。

Custom

在有些情況下,您可能會發現,沒有現成的細分適用於執行正確填充目標所需的資料操作。在這種情況下,您可以使用一個定製轉換。以下幾節將解釋三種 Custom 轉換:Custom XPath、Custom XSLT 和 Custom Java™。

Custom XPath

在某些情況下,可能需要用到不能作為內建功能細分使用的 XPath 表示式或 XPath 表示式組合。在這種情況下,您可以編寫一個定製的 XPath 表示式來實現所需的結果。在編寫 XPath 表示式時,定製轉換的輸入可作為變數使用。您可以使用這個語義引用它們:$

例如,如果轉換有一個名為 currentTemperature 的輸入元素,那麼您可使用 $currentTemperature 引用該元素。

要想了解如何在一個表示式中使用一個 XPath 運算子,可以考慮這樣一個場景:假如您希望使用 xsd:int 型別的兩個輸入的總和來生成一個 xsd:int 結果。您可以使用連線到轉換的兩個 int 輸入建立一個 Custom 轉換,然後使用類似下面的表示式計算兩個輸入的總和:$inputx + $inputy

在 XPath 表示式條目欄位中(使用 CTRL+Space)呼叫內容輔助將顯示一個可用變數列表和一個 XPath 函式列表,如 圖 14 所示,可將這些函式輕易插入表示式中。


圖 14. XPath 內容輔助
XPath 內容輔助

Custom XSLT

您可以通過使用 XSLT 實現定製轉換。使用 XSLT 時,呼叫外部檔案中一個指定的模板來生成目標輸出。將 Custom 轉換的輸入作為引數傳送到定製的 XSLT。通用 XSLT 模板儲存在一個庫中,由多個對映共享。Custom XSLT 可用於在目標中建立源中沒有的元素。您一般可使用一個 Submap 來完成該操作,但也有 Submap 不可行的時候。在使用 Custom XSLT 時要記住:

  • 預設情況下,Custom 對映的目標元素會得到自動建立,且被呼叫的模板僅填充目標元素的內容。如果您需要使用 Custom XSLT 來建立整個目標元素(例如,您想在目標元素上設定一個屬性),就必須選擇 Custom XSLT Properties 頁面上的 Include target element within the template 核取方塊。
  • 在一個定製的 XSLT 模板內,如果您需要來自節點而非輸入節點的資料來完成模板,可將節點作為一個附加輸入連線到 Custom 轉換。 另一種方式就是使用一個絕對 XPath 表示式。

要了解如何使用 Custom XSLT,可考慮這樣一個場景:在源上有一個巢狀陣列。如 圖 15 所示的外部陣列是一個類別列表,且每個類別包含一個與類別匹配的旅行目的地列表。


表 3. 樣例資料

旅行類別:沙灘
Acapulco,Mexico
Veradero,Cuba
Miami,United States
旅行類別:歷險
Whitehorse,Canada
Grand Canyon,United States


圖 15. 帶定製 XSLT 轉換的樣例對映
帶定製 XSLT 轉換的樣例對映

上述定製轉換會呼叫以下 XSLT 模板,將每個類別傳遞給模板,如清單 1 所示。


清單 1. 帶引數的定製 XSLT



模板使用一個 xsl:for-each 選取每個類別的目的地,如清單 2 所示。


清單 2. travelDestination 迴圈


模板還基於巢狀陣列的父類別在輸出目的地中設定類別值,如清單 3 所示。


清單 3. 父類別


對於樣例輸入資料,availableDestinations 輸出陣列如清單 4 所示。


清單 4. 生成的輸出 XML



 
  
   Acapulco
   Mexico
  
  Beach
  8
 

 
  
   Veradero
   Cuba
  
  Beach
  7
 

 
  
   Miami
   United States
  
  Beach
  7
 

 
  
   Whitehorse
   Canada
  
  Adventure
  7
 

 
  
   Grand Canyon
   United States
  
  Adventure
  9
 


為繼續示例,假定您實際上不需要選取所有類別的目的地並將其展平為單個列表,而是希望使用單一類別的目的地並將其展平為一個列表。讓我們假定客戶打算讓您知道他們對哪些類別的目的地感興趣。圖 16 中的以下對映顯示了客戶選中旅行類別和傳遞到定製的 XSLT 轉換中的分類目的地列表。


圖 16. 帶 XSLT 轉換的樣例對映
帶 XSLT 轉換的樣例對映

上述對映呼叫以下 XSLT 模板來查詢適當類別的目的地,如清單 5 所示。


清單 5. CategoriesToAvailableDestinations 模板


在上述示例中,注意以下要點:

  • travelCateogory 元素是作為 Custom 轉換上的第二個輸入新增的,因此它的值在定製模板中可作為引數使用。
  • 清單 6 中所示的 If 語句確保僅選中適當類別的目的地。


清單 6. customerTravelCategory 條件

test="../categoryName=$customerTravelCategory">

注意:每一次為一個定製的 XSLT 引用一個 XSLT 檔案時,都會將對該 XSLT 檔案的匯入新增到對映檔案中。如果要新增和移除 XSLT 檔案到特定的對映中,不妨使用 Properties 頁面中的 “XSLT Imports” 選項卡來清理未使用的匯入。

使用 XSLT 中的內建擴充套件

當在 WebSphere Process Server 和 WebSphere Enterprise Server Bus 執行時執行的時候,XSL Transformation 原語使用的 XSLT 處理器基於 Apache Xalan-Java XSLTC 處理器,該處理器提供 EXSLT 擴充套件函式,包括 string 函式、math 函式、set 函式以及 date and time 函式。欲獲取 EXSLT 函式列表,請參閱 Apache XML Project

有時 IBM XSLTC 處理器可能不同於 Apache Xalan-Java XSLTC 處理器,因此上面提到的所有函式未必都可用。以下示例顯示了正在定製的 XSLT 模板中使用的 ExstlString:split 函式。在示例中,GetWeather 服務返回了一個 XML 字串,在字串中存在一個您要提取的溫度值。例如:


清單 7. 溫度輸出 XML

...
...
 55 F (13 C) 
...
...


清單 8. GetWeatherResultToCurrentTemperature XSL 模板
...
xmlns:str="http://exslt.org/strings"
...

注意:

  • str 名稱空間在樣式表上按如下方式定義:xmlns:str="http://exslt.org/strings"
  • 帶兩個字串引數的 split 函式按如下方式呼叫:select="str:split($GetWeatherResult, '<Temperature>')[2]"

使用位於庫中的通用 XSL 檔案

我們建議您將通用 XSL 模板放在位於庫專案中的通用 XSL 檔案中。通過使用庫,多箇中介模組可訪問通用 XSL 模板。

在將一個通用 XSL 檔案匯入到一個位於中介模組中的 XSL 檔案中時,使用一個 xsltcl URI。例如,如果中介模組中的 XSL 檔案是 MediationModule1/xslt/MyMap-custom.xsl,且您希望匯入的 XSL 檔案是 /Library1/common/CommonXSLLibrary.xsl,則匯入將是:

Library1 的庫名不包含在 URI 中。

Custom Java

實現 Custom 轉換的第三個方法是使用對靜態 Java 方法的呼叫。您可以使用一個 Java 呼叫填充任何簡單或複雜元素的值。您可以將輸入連線到 Custom Java 轉換並將這些輸入作為方法引數使用。輸入可以是簡單或複雜型別的輸入。在將複雜型別的輸入作為方法引數使用時,相應的方法型別會為複雜型別的陣列使用 org.w3c.dom.Node 或 org.w3c.dom.NodeList 型別的引數。在處理 Custom Java 轉換時,Custom 轉換的 Properties 頁面允許您選擇所需的類和方法,並將 Custom 轉換的輸入對映到 Java 方法的引數。

為闡述一個 Custom Java 呼叫的基本使用方法,以清單 9 為例。在中介流期間,對一個 Web 服務進行呼叫來檢查特定目的地的天氣狀況。天氣服務返回一個 XML 結果,目的地的溫度就包含在該結果中。一個靜態 Java 方法可用於解析 XML 資料並將溫度作為一個 int 值提取出來。


清單 9. Web 服務返回的 XML 輸出


  Toronto Pearson Int'L. Ont., Canada (CYYZ) 
   43-40N 079-38W 173M
  
  from the ESE (110 degrees) at 9 MPH (8 KT):0
  15 mile(s):0
  overcast
  50 F (10 C)
  41 F (5 C)
  71%
  30.14 in. Hg (1020 hPa)
  Success

假定您關注於提取攝氏溫度,在上述示例中即為 21。以上述資料為基礎,清單 10 中所示的 Java 方法將通過在 output. 中查詢 標記來提取攝氏溫度。


清單 10. getCelsiusTemperature Java 方法

  public static int getCelsiusTemperature(String originalWeatherReport) {

    int temperature = -99; // Error - Can't find temperature
    if (originalWeatherReport != null)
    {
      int temperatureStartIndex = originalWeatherReport
          .indexOf(TEMPERATURE_START_TAG);
      int temperatureEndIndex = originalWeatherReport
          .indexOf(TEMPERATURE_END_TAG);
      if ((temperatureStartIndex >= 0)
          && (temperatureEndIndex > temperatureStartIndex))
      {
        temperatureStartIndex = temperatureStartIndex
            + TEMPERATURE_START_TAG.length();
        String temperatureString = originalWeatherReport.substring(
            temperatureStartIndex, temperatureEndIndex);
        int startBracketIndex = temperatureString.indexOf('(');
        int endBracketIndex = temperatureString.indexOf(')');
        if (startBracketIndex >= 0 && endBracketIndex >= 0
            && (startBracketIndex < endBracketIndex))
        {
          String celsiusString = temperatureString.substring(
              startBracketIndex + 1, endBracketIndex);
          if (celsiusString.endsWith("C"))
          {
            celsiusString = celsiusString.substring(0,
                celsiusString.length() - 1);
            celsiusString = celsiusString.trim();
            try {
              double doubleValue = Double.parseDouble(celsiusString);
              temperature = (int) Math.round(doubleValue);
            } catch (NumberFormatException e) {
            }
          }
        }
      }
    }

    return temperature;

  }

要在一個 Custom 轉換中使用上述方法,請執行以下操作:

  • 確保包含對映檔案的庫或模組對包含 Java 檔案(內含方法)的專案有一定的依賴性。
  • 在適當的對映檔案中建立 Custom Java 轉換,如 圖 17 所示。

    圖 17. Custom Java 對映
    Custom Java 對映

  • 在 Custom Java 轉換的 General 屬性頁面上,使用 Class 欄位旁邊的 Browse 按鈕來瀏覽包含方法的類。在 Select Type 對話方塊中輸入類名時,可用選項列表會更新為包含與所鍵入字首相匹配的類。
  • 在 Method 下拉框中,選擇所需的方法。
  • 在引數部分,選擇合適的輸入欄位以對映到每個方法引數。例如,圖 18 中的以下屬性將 GetWeatherResult 值作為一個變數引用。

    圖 18. Custom Java 對映屬性頁面
    Custom Java 對映屬性頁面

在上一個例子中,Custom Java 轉換的輸入和輸出都是簡單型別。下面考慮另一個例子,假設您希望使用複雜型別輸入的陣列來填充目標上覆雜型別的陣列。Java 方法會將 NodeList 作為一個輸入引數,並將 NodeList 作為一個結果返回。

在該例中,假定您在源中有一個目的地陣列,且希望在填充目標上的目的地列表之前使用一個 Java 方法新增額外的目的地到列表中。第一步是要建立一個實現以下功能的定製 Java 類:

  1. 生成額外目的地列表。
  2. 合併現有目的地與額外目的地。
  3. 返回 NodeList 中合併後的列表。

在該例中,將會建立一個 DestinationCreationUtility 類。該類將包含清單 11 中所示的以下方法。


清單 11. appendCreatedDestinations Java 方法

public static NodeList appendCreatedDestinations(NodeList 
 arrayOfTravelDestinations)

該方法會接受一個 TravelDestination 節點陣列,並解析這些節點來確定現有目的地列表。該方法會將現有目的地轉換為 TravelDestination 物件,從而簡化它們與額外目的地列表的合併,如清單 12 所示。


清單 12. getAdditionalDestinations Java 方法

public static ArrayList getAdditionalDestinations()

這是一個生成額外目的地列表的方法。您可以將該列表與現有目的地列表合併來建立 TravelDestination 物件的一個特有列表,如清單 13 所示。


清單 13. convertToNodeList Java 方法

private static NodeList convertToNodeList(ArrayList allDestinations)

該方法會選取 TravelDestination 物件列表並構建一個 NodeList。convertToNodeList 方法按清單 14 所示實現。


清單 14. DestinationCreationUtility Java 類

import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.xpath.NodeSet;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

public class DestinationCreationUtility {	
  ...
  private static NodeList convertToNodeList(
    ArrayList allDestinations) {
		
    NodeSet resultSet = new NodeSet();

    try {

      Document doc = DocumentBuilderFactory.newInstance()
        .newDocumentBuilder().newDocument();

      for (int i = 0; i < allDestinations.size(); i++) {
        TravelDestination next = allDestinations.get(i);
        Element nextAvailableDestination = doc.createElement("availableDestination");
        Element destinationElement = doc.createElement("destination");
        Element cityName = doc.createElement("cityName");
        Text cityNameText = doc.createTextNode(next.cityName);
        cityName.appendChild(cityNameText);
        Element countryName = doc.createElement("countryName");
        Text countryNameText = doc.createTextNode(next.countryName);
        countryName.appendChild(countryNameText);
        Element categoryElement = doc.createElement("category");
        Text categoryText = doc.createTextNode(next.category);
        categoryElement.appendChild(categoryText);
        Element popularityElement = doc.createElement("popularity");
        Text popularityText = doc.createTextNode(next.popularity + "");
        popularityElement.appendChild(popularityText);
        destinationElement.appendChild(cityName);
        destinationElement.appendChild(countryName);
        nextAvailableDestination.appendChild(destinationElement);
        nextAvailableDestination.appendChild(categoryElement);
        nextAvailableDestination.appendChild(popularityElement);
        resultSet.addElement(nextAvailableDestination);
      }
    } catch (DOMException e) {
        throw new org.apache.xml.utils.WrappedRuntimeException(e);
    } catch (ParserConfigurationException e) {
        throw new org.apache.xml.utils.WrappedRuntimeException(e);
    }
    return resultSet;
  }
  ...
}

為完成任務,一旦 DestinationCreationUtility 類被建立,使用 Custom Java 轉換將源目的地對映到目標目的地的對映也會被建立,如 圖 19 所示。


圖 19. 帶屬性集的 Custom Java 對映
帶屬性集的 Custom Java 對映

除錯定製 Java 呼叫

當您有一個使用定製 Java 呼叫的對映時,可以在對映執行於伺服器中時除錯正被呼叫的 Java。使用 Test Map 檢視或使用 Integration Test Client 本地測試一個對映檔案時,在 Java 程式碼中設定斷點不會產生任何影響。然而,如果您使用 Integration Test Client 執行一個元件測試,且伺服器在 Debug 模式下執行,在被呼叫的 Java 方法中設定的斷點會促使執行中止,從而可以單步除錯 Java 方法。

萬用字元的使用

萬用字元是一種機制,它使一個 XML Schema 定義變得很靈活。由於萬用字元的結構在 XML Schema 中未作定義,XML Mapping Editor 不能自動顯示萬用字元的結構。自 V7.0.0 以來,XML Mapping Editor 支援將萬用字元投射(cast)為一個具體型別,允許顯示並輕鬆對映結構。在 Mediation Flow 中工作時,投射的另一種方法是在使用 XSL Transform. 原語之前使用一個 Set Message Type 原語。Set Message Type 原語允許您指定用於萬用字元的具體型別。

識別萬用字元

基於 XML Schema 定義,萬用字元有以下三種形式:

萬用字元

在這種情況下,任何名稱和型別的元素都適用。在 XML Mapping Editor 中,可通過使用 Any                     icon 圖示查詢欄位來識別 萬用字元,其名稱為 any 且輸入欄中未指定型別,如 圖 20 所示。


圖 20. XML Schema any 元素
XML Schema any 元素

在上述示例中, 萬用字元也可重複使用,此時目標可包含任意名稱和型別的元素陣列。像任何其他欄位一樣,基數欄將表明一個 萬用字元是否可重複使用。

萬用字元

在這種情況下,帶任何名稱和值的零個或更多屬性都可接受。在 XML Mapping Editor 中,可通過使用 anyAttribute icon 圖示尋找欄位來識別 萬用字元,其名稱為 anyAttribute 且在輸入欄中未指定型別,如 圖 21 所示。


圖 21. XML Schema any attribute
XML Schema any attribute

anyType 型別

這種情況適合帶指定名稱的元素,但元素可以是任何型別。下面是一個名為 correlation 的 anyType 型別元素示例,如 圖 22 中的 XML Mapping Editor 中所示。


圖 22. XML Schema any anyType
XML Schema any anyType

當預期目標是 anyType 型別時,我們建議使用 xsi:type 屬性設定最終目標元素中的型別。在處理過程中執行時使用 xsi:type 屬性。如果不為 anyType 目標設定 xsi:type 屬性,可能會出現錯誤。

從源中的一個萬用字元進行對映

當您的源是一個萬用字元或有 anyType 型別時,您可以使用以下方法中的一種將該輸入的內容對映到目標:

Cast

New icon 當您知道源總是包含相同的型別或全域性元素/屬性時,Cast 是首選方法。Cast 是通過右鍵單擊萬用字元並選擇 Cast 選單來完成的。

萬用字元:當您可以將潛在的 萬用字元輸入列表縮小為全域性元素集時,就可將 萬用字元輸入投射到每個潛在的全域性元素。一經投射,通過 cast 全域性元素建立的轉換僅在相應的全域性元素在執行時真正屬於輸入文件的一部分時才執行。

萬用字元:當您可以將潛在的 萬用字元輸入列表縮小為全域性屬性集時,就可將 萬用字元輸入投射到每個潛在的全域性屬性。一經投射,通過 cast 全域性屬性建立的轉換僅在相應的全域性元素在執行時真正屬於輸入文件的一部分時才執行。

anyType type:當您可以將潛在的輸入列表縮小為具體型別的集合時,就可將 anyType 輸入元素投射到每個潛在的具體型別。一經投射,通過 cast 型別建立的轉換僅在相應型別在執行時真正屬於輸入文件的一部分時才執行。

Move

當不需要對輸入進行任何操作時,您可以使用 Move 轉換將確切的輸入複製到目標文件。

萬用字元:如果您希望原封不動地複製源元素,可以使用 Move 轉換將 萬用字元表示的源元素移動到目標。要使源元素的名稱和型別在執行時有效,就需要將其與目標的要求相匹配。

萬用字元:您不能使用 Move 從一個 萬用字元源進行對映。

anyType 型別:如果源元素和目標元素都有一個 anyType 型別,您只能對源元素使用 Move 轉換。從帶 anyType 型別的源元素到帶具體型別的目標元素的 Move 轉換不受支援。

Submap

當決定所需投射的邏輯複雜且可重用時,考慮使用 Submap。

萬用字元:如果源中有一個 萬用字元包含填充目標元素所需的資料,但與目標元素所需的元素結構不精確匹配時,可使用 Submap 對映這兩個元素或這些元素的兩個型別。建立 Submap 時,指定源的預期元素或型別為 Submap 輸入。設定好 Submap 輸入之後,輸入的完整結構在 Submap 中顯示,且源欄位與匹配的目標欄位一一對映。

萬用字元 萬用字元源不支援 Submap。

Custom

當 Cast、Move 或 Submap 不能實現所需的效果時,可以使用帶萬用字元輸入的 Custom XPath、Custom XSLT 或 Custom Java 轉換。一個 Custom 轉換允許您以任意形式細分一個源萬用字元。它還允許您將兩個獨立的萬用字元源對映到一個單一目標。

在使用 Custom 轉換從一個 萬用字元執行對映時,建議您將 萬用字元的父級作為轉換輸入。這可以使您根據名稱或位置訪問屬性。例如,如果您有一個 Custom XPath 轉換使用一個名為 luggage 的元素的輸入,且您希望訪問一個名為 passengerName 的屬性以將其賦給輸出屬性時,您可以使用一個 Custom XPath 轉換,其 XPath 表示式類似於 $luggage/@passengerName

對映到目標中的一個萬用字元

如果您的目標是一個萬用字元或含有 anyType 型別,您可以使用以下方法中的一種對映到萬用字元目標。

Cast

New icon 當您知道目標總是包含相同的型別或全域性元素/屬性時,Cast 是首選方法。Cast 是通過右鍵單擊萬用字元並選擇 Cast 選單來完成的。

萬用字元:通過 Cast 方法,您可以將一個 萬用字元投射到一個或多個特定全域性元素。如果您確定會一直使用相同的全域性元素或元素來填充目標 萬用字元,可以將 萬用字元投射到期望的全域性元素。當目標僅限於單一元素且存在多個 cast 全域性元素時,我們建議您在 cast 全域性元素的頂級建立對映。例如,假如有一個單例 萬用字元被投射到兩個不同的全域性元素,即 GlobalElementA 和 GlobalElementB。該例的目的在於,根據某些輸入的存在狀況,在執行時 GlobalElementA 和 GlobalElementB 中僅有一個在目標中得到建立。為確保在執行時僅建立其中一個全域性元素,一定要做到:

  • 只有其中一個全域性元素的輸入在執行時存在於輸入 XML 文件中。
  • 目標全域性元素在最頂級被對映。

圖 23 闡釋了到最頂級的對映,以下對映是在 cast 全域性元素的最頂級建立的,且它們是正確的。


圖 23. 有效的 Cast 對映
有效的 Cast 對映

以下對映不是 在最頂級建立的,且導致在執行時建立空元素,不管輸入元素是否存在。圖 24 中所示的對映是不正確的。


圖 24. 無效的 Cast 對映
無效的 Cast 對映

萬用字元:通過 Cast 方法,您可以將一個 萬用字元投射到一個或多個特定全域性屬性。如果您確定會一直使用相同的全域性屬性填充目標 萬用字元,可以將 萬用字元投射到預期的全域性屬性。

anyType 型別:如果目標 anyType 的型別是已知的,那麼使用 anyType 的首選方法是將其投射到一個具體型別。

Move

萬用字元:如果有一個源元素恰好就是您希望用來填充目標的元素,Move 會將元素從源複製到目標 萬用字元。

當對映到目標中的一個 萬用字元時,您要確保不違反名稱空間和處理約束。當您選擇目標欄中的一個 萬用字元時,Properties 檢視會顯示名稱空間和處理約束,不過沒有相關的驗證檢查來確保不違反約束。

萬用字元:如果要包含在目標中的屬性與源中所需的名稱和值一同出現,您可以使用一個或多個 Move 轉換將屬性從源複製到目標。當屬性不存在於源中或需要對屬性名作更改時,就需要一個 Custom 轉換。圖 25 顯示瞭如何將多個源屬性對映到目標上的一個 萬用字元。


圖 25. 將多個源屬性對映到一個目標
將多個源屬性對映到一個目標 </FONT> <BR></P>
<P><STRONG>anyType 型別</STRONG>:如果有一個源元素恰好是您想用來填充目標的型別,Move 會將元素內容從源複製到目標。Move 轉換自動將推薦的 xsi:type 屬性新增到目標元素,這樣就可在執行時準確識別型別。</P>
<P><STRONG>Submap</STRONG> </P>
<P>如果您有複雜的邏輯可以確定使用的型別是什麼,且您希望該邏輯可重用,這時就可使用一個 Submap。</P>
<P><STRONG><any> 萬用字元</STRONG>:使用 Submap 對映到目標中的一個 <any> 萬用字元時,您要確保不違反名稱空間和處理約束。在目標欄中選擇 <any> 萬用字元時,Properties 檢視會顯示名稱空間和處理約束,但沒有相關的驗證檢查來確保不違反約束。</P>
<P><STRONG><anyAttribute> 萬用字元</STRONG>:您不能使用一個 Submap 來填充目標中的 <anyAttribute> 萬用字元。</P>
<P><STRONG>anyType 型別</STRONG>:在使用 anyType 型別的目標時,Submap 轉換為目標元素使用正確的元素名,另外新增推薦的 xsi:type 屬性來確保在執行時正確識別目標元素。</P>
<P><STRONG>Custom</STRONG> </P>
<P>當 Cast、Move 轉換或 Submap 轉換不適用時,您可以使用 Custom XPath、Custom XSLT 或 Custom Java 轉換來為目標構建合適的元素或屬性。如果使用一個 Custom 轉換對映到擁有 anyType 型別的一個元素,記住一定要為該元素設定 xsi:type 屬性。</P>
<P><A name=Casting><SPAN class=atitle><STRONG><FONT size=5>使用通過擴充套件和限制定義的派生型別</FONT></STRONG></SPAN></A></P>
<P><STRONG><FONT size=5><IMG height=11 alt= 當對基本型別進行了擴充套件或限制之後,您可以使用 cast 轉換顯示源或目標中的派生結構。當輸入包含派生型別的基本型別時,您可以將該基本型別投射到其任何派生型別,如 圖 26 所示。


圖 26. 投射派生型別
投射派生型別

在上述示例中,Address 是基本型別,且是在模式中被定義為 field2 型別的型別。在本例中,field2 被同時投射到 USAddress 和 UKAddress,它們都是 Address 型別的擴充套件型別。

為防止在執行時在目標中建立不需要的副本或空元素,我們建議您遵循以下約定:

  • 在將源或目標元素投射到派生型別之後,我們建議您僅建立與派生型別之間的來回對映,而不要建立到基本型別的對映。
  • 要在目標上一直建立到可選元素最頂級的對映。例如,假定在目標中有型別 Address 的一個單一元素,該元素分別投射到兩個派生型別 USAddress 和 UKAddress。該例的目的在於,基於某些輸入的存在狀況,僅有一個派生型別將存在於目標文件中。為確保一個目標只有在被對映的輸入存在於輸入文件時得到建立,在對映任何子級之前要對映到頂級。圖 27 解釋了頂級對映,且該對映是正確的。

    圖 27. 有效的派生型別投射
    有效的派生型別投射

    圖 28 顯示了直接到 cast 元素子級的對映,且該對映是不正確的。

    圖 28. 無效的派生型別投射
    無效的派生型別投射

投射可通過右鍵單擊源或目標中的欄位然後選擇 Cast 按鈕完成。在呼叫投射動作時只顯示有效的派生型別。如果選中欄位沒有有效的派生型別,會顯示一個對話方塊表示無型別可用。如果找不到所需型別,確保所需的派生型別包含在引用的專案中。

使用 choice 元素

預設情況下,xsd:sequence 和 xsd:choice 等 XSD 模型組不在 XML Mapping Editor 中顯示。更改顯示組的檢視首選項就會顯示 XSD 模型組的資訊,從而允許您識別 choice 組元素的位置。單擊本地工具欄上的 Open 首選項按鈕(Open preferences button)可更改檢視首選項。

您不能直接對映 choice 元素,但可以對映一個 choice 組內包含的元素。一個例項文件任何時候都只能包含一個不可重複的 choice 模型組內的其中一個元素,不能包含多個元素。因此,通過一個不可重複的 choice 組的成員建立轉換時,只有與存在於執行時例項文件的這些成員元素連線的轉換才得到執行。與連線到其他元素的任何轉換都將被忽略。

在建立以 choice 組元素為目標的轉換時,要確保對映邏輯只產生一個 choice 組元素。如果一個 choice 組中預備有多個元素,就會產生意料之外的結果,因為所生成的 XSL 會試圖建立一個有效的 XML 輸出文件。使用 If、Else If 和 Else 轉換,或使用 XPath、Custom XSLT 或 Custom Java 轉換來確保一個 choice 組中只有一個元素得到建立,從而確保對映執行過程中獲得預期結果。

使用 substitution 組

預設情況下,substitution 組不在 XML Mapping Editor 中顯式顯示。不過,您可以通過一個元素上的以下圖示識別包含在一個 substitution 組內的頭元素:Substitution 組圖示。更改顯示組的檢視首選項可顯式地顯示 substitution 組。單擊本地工具欄上的 Open 首選項按鈕(Open preferences button)可更改顯示組首選項。

如同所顯示的實際 xsd:sequence 和 xsd:choice 元素,您不能直接對映 sbstitution 組節點,但是可以對映一個 substitution 組內包含的元素。同樣地,像 choice 元素一樣,關鍵要記住,一個示例文件一次只能包含可替代元素的一個成員,而不能包含多個成員。

Business Object Mapper 將其對映基於泛類,與此不同,XSLT Mapper 在執行期間僅執行與例項文件中的元素精確匹配的轉換。因此,在一個 substitution 組中的頭元素上建立一個 “常規” 轉換來處理例項文件中可能存在的任何派生元素不能處理所有情況。相反地,如果打算轉換每個元素,在特定轉換中必須包含涉及的元素,以處理特有情況。如果必要,該方法允許篩選包含在 substitution 組中的某些元素(即不將資料移動到目標)。

在建立以 substitution 組成員為目標的轉換時,確保對映邏輯僅產生其中一個成員。如果一個 substitution 組中預備有多個元素,就會產生意料之外的結果,因為所生成的 XSL 會試圖產生一個有效的 XML 輸出文件。

SOAP 頭

下面內容將解釋使用 SOAP 頭時發生的一些常見用例。SOAP 頭元素中的值元素是一個名為 value 的 anyType 型別元素,可使用 對映到目標中的一個萬用字元 部分解釋的方法進行設定。使用值元素的最簡單的方法是將其投射到所需輸出型別的一個元素。

另一種情況發生在當您基於 SOAP 頭名執行一個條件對映時。在該情況下,您可以建立 if、Else If 或 Else 對映。欲瞭解如何執行 if-else 邏輯,請參見本系列的第 1 部分 條件對映

SOAP 編碼的陣列

當您的源或目標包含一個經 SOAP 編碼的陣列時,您可能會希望將陣列元素從一個 SOAP 編碼的陣列移動到一個標準陣列,反之亦然。XML Mapping Editor 不識別一個 SOAP 編碼陣列內的元素型別,且將元素作為 萬用字元元素的一個陣列顯示。與 SOAP 編碼陣列的相互轉化將在本節介紹。

情況 1. 從一個 SOAP 編碼的源陣列複製到一個常規目標陣列

在該情況下,您可以使用 For-each 和 Submap 對映。For-each 用於迭代源陣列中的每個 萬用字元元素,而 Submap 用於將這些元素投射到所需的型別。例如,在源上有 Destination 元素的一個 SOAP 編碼陣列,您希望使用它在目標上填充 Destination 元素的常規陣列,如 圖 29 所示。


圖 29. SOAP 編碼陣列的 Foreach 對映
SOAP 編碼陣列的 Foreach 對映

在 For-each 對映內,Submap 對映用於將 萬用字元元素(它實際上是本例中的 Destination 元素)對映到 Destination 元素,如 圖 30 所示。


圖 30. SOAP 編碼陣列的 Submap 對映
SOAP 編碼陣列的 Submap 對映

上面的 Submap 轉換呼叫將 Destination 同時作為源和目標型別的一個 Submap。

情況 2. 從一個常規源陣列複製到一個 SOAP 編碼的目標陣列

這種情況需要編寫定製的 XSLT 來為 SOAP 陣列建立陣列元素。定製的 XSLT 必須執行以下操作來建立一個一致的 SOAP 陣列:

  • 為每個陣列元素使用名稱項。因而可以在 Integration Test Client 中工作的同時檢視 SOAP 陣列內容。例如:<item xsi:type="in:Destination">
  • 在 SOAP 陣列內的每個專案上使用 xsi:type 屬性。否則會發生執行時錯誤,因為陣列元素的型別無法確定:xsi:type="in:Destination">

為展示將常規陣列轉化為 SOAP 編碼陣列的場景,假定在源中有一個 Destination 元素列表,您希望使用這些元素填充目標上 Destination 的 SOAP 編碼列表。如 圖 31 所示,在對映中建立了一個 Custom 轉換。


圖 31. SOAP 編碼陣列的 Custom 對映
SOAP 編碼陣列的 Custom 對映

Custom XSLT 轉換的目標是可重複使用的 萬用字元。在 Custom XSLT Properties 頁面上,模板核取方塊內的 Include 目標元素處於選中狀態,從而允許您建立完全在 Custom XSLT 內的 萬用字元陣列元素。目標元素的外部 shell 總是在 Custom XSLT 轉換上被預設建立,除非選擇模板核取方塊內的 Include 目標元素。清單 15 顯示了定製的 XSLT。


清單 15. DestinationToSOAPDestination XSL 模板


高階提示和技巧

建立新目標節點

新節點可通過各種方式引入目標。其中一種方式是應用一個 Submap 或 Custom 轉換到一個可替換的目標節點(例如,一個萬用字元、一個派生型別或一個 substitution 組成員)。然後您可以用特定 Submap 或 Custom 節點中的一個合適節點或節點集替換該目標節點。此外,您可以直接將新節點引入對映編輯器,只需用一個 substitution 組成員替換另一個或將一個基本型別投射到其一個或多個派生型別。欲瞭解更多資訊,請參見 Custom使用通過擴充套件和限制定義的派生型別 部分。

確保一個完整的目標 XML 文件

使用 XML Mapping Editor 建立對映時,沒有自動驗證機制來確保所建立的對映會產生一個完整的目標 XML 文件。驗證機制試圖確保每個目標欄位都填充有有效資料,但它不能檢測出必需的目標欄位根本未得到填充的情況。如果一個必需的目標欄位未得到對映,最終的目標元素根據其模式是無效的。您可以通過檢視目標的基數欄來識別必需的目標欄位。如果基數顯示為 [1..1] 或 [1…n] 或 [1…*],欄位就是必需的。如果一個欄位是必需的,且該欄位的父級存在於輸出中,則該必需欄位也會存在於輸出中。要確定一個欄位是否必須存在於輸出中很棘手,因為它取決於所有欄位的上級。例如,如果所有欄位上級都是必需的,則欄位就是必需的。再例如,如果欄位是必需的但欄位父級是可選的且未被對映,欄位就不需存在於輸出文件中。

在確定欄位是必需的且需要存在於輸出 XML 文件中之後,確保以下內容:

  • 有一個到必需欄位的對映。
  • 如果從一個以可選欄位作為輸入的對映開始對映必需欄位,那麼一定要使用第二個條件對映來彌補源欄位不存在於輸入 XML 中的情況。通常在使用一個可選源填充必需目標時會出現這種情況。在這種情況下,您需要為源不存在的情況制定一個應急計劃。為建立一個應急對映,考慮使用 If 和 Else 對映,以確保不管是否有可選輸入,總是至少有一個到必需目標的對映。欲瞭解有關條件對映的更多資訊,請參見本系列第 1 部分中的 條件對映

對映到目標頭元素的相關注意事項

有時,您會發現執行到一個目標頭元素(即對映或巢狀對映內的頂級目標元素)的對映很有必要,或至少很有益處。 圖 32圖 33 分別是對映和巢狀對映內的頭元素示例。


圖 32. 根頭元素
根頭元素

圖 33. 巢狀頭元素
巢狀頭元素

到頭元素的對映並非在任何情況下都受支援。下面內容是對映到頭元素目標應遵循的一般規則:

  • 一般而言,容器對映(If、Else if、Else、Local、For-each、Merge 和 Append)對於頭元素目標來說是不允許的。惟一的例外是,在 If、Else if 或 Else 對映內可使用 Local、Foreach、Merge 和 Append。
  • Move、Convert、Submap、Custom、Substring、Normalize 和 Concat 對映在適當情況下可用於頭元素目標。
  • 在使用 Append 時,到頭元素目標的對映是自動被建立的。這些生成的對映是 Append 內允許的惟一頭元素對映。
  • Submap 和 Custom 是兩個常用於對映到頭元素目標的轉換,因為它們允許重用。使用 Submap 執行到頭元素目標的對映時,Submap 必須是一個型別對映。

確保在 Custom XSLT 中使用的名稱空間字首在輸出 XML 中能被識別

有一個已知問題:

  • 一個 XSL 檔案(比如為一個 .map 檔案生成的那個檔案)呼叫另一個 XSL 模板(比如一個 Custom XSLT 對映)。
  • 呼叫的 XSL 檔案使用 exclude-result-prefixes 屬性排除某些字首。例如:
    xmlns:in="http://TravelDestinationsLibrary"
    ...
    exclude-result-prefixes="in xalan"			
    

  • 被呼叫的 XSL 檔案重用被排除的字首,但不宣告將其排除。例如:
    xmlns:in="http://TravelDestinationsLibrary"
    ...
    exclude-result-prefixes="xalan"			
    

  • 輸出 XML 檔案不會包含被呼叫的 XSL 檔案所需的名稱空間宣告。對該名稱空間的使用將導致執行時錯誤,因為它未被識別。

如果伺服器在除錯模式下執行,該問題在 local map 測試或執行時期間不會發生。該問題僅在伺服器在非除錯模式下執行時發生。會發生這種情況的一個常見場景是在 Custom XSLT 中使用 xsi:type 屬性時。有一個變通方案可確保名稱空間包含其中。該方案使用的示例與用於解釋從常規陣列到 SOAP 編碼陣列的對映的場景相同。場景中使用了 Custom XSLT 且 Custom XSLT 使用 xsi:type 屬性,如清單 16 所示。


清單 16. DestinationToSOAPEncodedDestinationArray XSL 模板


item 元素由使用 in 名稱空間的一個 xsi:type 屬性宣告,如清單 17 所示。


清單 17. item xsi:type 屬性


上述 XSLT 在進行區域性測試的同時會生成正確的結果,但如果伺服器不在除錯模式下執行則會在執行時出錯,因為 in 名稱空間不會被識別出來。為解決該問題,使用 將名稱空間宣告新增到元素標記,如清單 18 所示。


清單 18. DestinationToSOAPEncodedDestinationArray XSL 模板


item 元素的初始和結束標記由 nxsi:text 包圍,目的是強制包含 in 名稱空間宣告。

組織匯入

New icon在向一個對映新增 Custom XSLT、Custom Java 或 Lookup 轉換時,同時會將對已引用 XSLT 或 Java 檔案的相應匯入新增到對映。如果稍後刪除導致新增匯入的轉換,匯入不會被自動刪除。為保持匯入的組織性,您可以檢視所有匯入並使用對映檔案屬性頁面手動刪除未使用的匯入。為訪問一個對映檔案的屬性,在編輯器中開啟檔案時選擇對映背景畫布,然後開啟 Properties 檢視。選擇對映背景可確保無特定元素或轉換被選中,且顯示的屬性將應用於對映檔案,而非對映中的特定元素。在屬性檢視中,可以使用 XSLT Imports 和 Java Imports 頁面處理對映檔案匯入。

還有一個名為 Namespaces 的屬性頁面,它允許為給定名稱空間定義定製字首。當在執行時特定名稱空間不帶字首或如果有必要在整個應用程式內為一個給定名稱空間使用統一字首時,可以使用這個屬性頁面。

結束語

在本文中,我們學習瞭如何處理複雜陣列、通過 Java、XSLT 模板和 XPath 實現的定製轉換,以及用於處理 XML Schema any、anyType 和派生型別的最佳實踐。文中還討論瞭如何在 WebSphere Enterprise Service Bus 內處理 SOAP 頭和 SOAP 編碼陣列。這些關鍵對映技能是在 WebSphere Integration Developer 內建立更多複雜 XML 對映的一個重要部分。

原文連結:http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1003_spriet2/1003_spriet2.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-674572/,如需轉載,請註明出處,否則將追究法律責任。

相關文章