轉換 XML 有效負載
本節介紹如何轉換XML負載
配置作為Bean的轉換器
本節將解釋以下轉換器的工作原理以及如何將其配置為Bean
所有XML轉換器都繼承自 AbstractTransformer 或 AbstractPayloadTransformer,因此實現了 Transformer。在Spring Integration中將XML轉換器配置為Bean時,通常會將 Transformer 與 MessageTransformingHandler 結合配置。這允許轉換器用作端點。最後,我們將討論名稱空間支援,它允許將轉換器配置為XML中的元素。
UnmarshallingTransformer
UnmarshallingTransformer 允許使用 Spring OXM Unmarshaller 的實現來解組XML Source。Spring的物件/XML對映支援提供了多種實現,它們支援使用 JAXB、Castor、JiBX 等進行編組和解組。解組器需要一個 Source 例項。如果訊息負載不是 Source 例項,則仍會嘗試轉換。目前,支援 String、File、byte[] 和 org.w3c.dom.Document 負載。要建立自定義的 Source 轉換,您可以注入 SourceFactory 的實現。
如果您沒有顯式設定 SourceFactory,則 UnmarshallingTransformer 上的屬性預設設定為 DomSourceFactory。 |
從5.0版本開始,UnmarshallingTransformer 還支援 org.springframework.ws.mime.MimeMessage 作為傳入負載。當透過SOAP接收帶有MTOM附件的原始 WebServiceMessage 時,這可能很有用。有關更多資訊,請參閱 MTOM 支援。
以下示例顯示如何定義解組轉換器
<bean id="unmarshallingTransformer" class="o.s.i.xml.transformer.UnmarshallingTransformer">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="org.example" />
</bean>
</constructor-arg>
</bean>
使用 MarshallingTransformer
MarshallingTransformer 允許使用Spring OXM Marshaller 將物件圖轉換為XML。預設情況下,MarshallingTransformer 返回 DomResult。但是,您可以透過配置替代的 ResultFactory(例如 StringResultFactory)來控制結果的型別。在許多情況下,將負載轉換為替代XML格式更方便。為此,請配置一個 ResultTransformer。Spring Integration提供了兩種實現,一種轉換為 String,另一種轉換為 Document。以下示例配置了一個轉換為文件的編組轉換器
<bean id="marshallingTransformer" class="o.s.i.xml.transformer.MarshallingTransformer">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="org.example"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>
</constructor-arg>
</bean>
預設情況下,MarshallingTransformer 將負載物件傳遞給 Marshaller。但是,如果其布林屬性 extractPayload 設定為 false,則將整個 Message 例項傳遞給 Marshaller。這對於 Marshaller 介面的某些自定義實現可能很有用,但是,通常,當委託給各種 Marshaller 實現時,負載是編組的適當源物件。
XsltPayloadTransformer
XsltPayloadTransformer 使用 可擴充套件樣式表語言轉換 (XSLT) 轉換XML負載。轉換器的建構函式需要傳入 Resource 或 Templates 的例項。傳入 Templates 例項可以更靈活地配置用於建立模板例項的 TransformerFactory。
與 UnmarshallingTransformer 一樣,XsltPayloadTransformer 對 Source 例項執行實際的XSLT轉換。因此,如果訊息負載不是 Source 例項,則仍會嘗試轉換。直接支援 String 和 Document 負載。
要建立自定義的 Source 轉換,您可以注入 SourceFactory 的實現。
如果未顯式設定 SourceFactory,則 XsltPayloadTransformer 上的屬性預設設定為 DomSourceFactory。 |
預設情況下,XsltPayloadTransformer 建立一個帶有 Result 負載的訊息,類似於 XmlPayloadMarshallingTransformer。您可以透過提供 ResultFactory 或 ResultTransformer 來定製此行為。
以下示例配置了一個作為XSLT負載轉換器工作的Bean
<bean id="xsltPayloadTransformer" class="o.s.i.xml.transformer.XsltPayloadTransformer">
<constructor-arg value="classpath:org/example/xsl/transform.xsl"/>
<constructor-arg>
<bean class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>
</constructor-arg>
</bean>
從Spring Integration 3.0開始,您可以使用建構函式引數指定轉換器工廠類名。當您使用名稱空間時,可以透過使用 transformer-factory-class 屬性來實現。
使用 ResultTransformer 實現
MarshallingTransformer 和 XsltPayloadTransformer 都允許您指定 ResultTransformer。因此,如果編組或XSLT轉換返回 Result,您可以選擇也使用 ResultTransformer 將 Result 轉換為另一種格式。Spring Integration提供了兩個具體的 ResultTransformer 實現
預設情況下,MarshallingTransformer 總是返回一個 Result。透過指定 ResultTransformer,您可以自定義返回的負載型別。
對於 XsltPayloadTransformer,行為略微複雜。預設情況下,如果輸入負載是 String 或 Document 的例項,則 resultTransformer 屬性將被忽略。
但是,如果輸入負載是 Source 或任何其他型別,則會應用 resultTransformer 屬性。此外,您可以將 alwaysUseResultFactory 屬性設定為 true,這也會導致使用指定的 resultTransformer。
有關更多資訊和示例,請參閱 名稱空間配置和結果轉換器。
XML轉換器的名稱空間支援
所有XML轉換器的名稱空間支援都在Spring Integration XML名稱空間中提供,其模板 之前已顯示。轉換器的名稱空間支援根據所提供輸入通道的型別建立 EventDrivenConsumer 或 PollingConsumer 例項。名稱空間支援旨在透過允許使用一個元素建立端點和轉換器來減少XML配置的數量。
使用 UnmarshallingTransformer
下面顯示了 UnmarshallingTransformer 的名稱空間支援。由於名稱空間建立的是端點例項而不是轉換器,您可以在元素中巢狀一個輪詢器以控制輸入通道的輪詢。以下示例顯示瞭如何操作
<int-xml:unmarshalling-transformer id="defaultUnmarshaller"
input-channel="input" output-channel="output"
unmarshaller="unmarshaller"/>
<int-xml:unmarshalling-transformer id="unmarshallerWithPoller"
input-channel="input" output-channel="output"
unmarshaller="unmarshaller">
<int:poller fixed-rate="2000"/>
<int-xml:unmarshalling-transformer/>
使用 MarshallingTransformer
編組轉換器的名稱空間支援需要 input-channel、output-channel 和對 marshaller 的引用。您可以使用可選的 result-type 屬性來控制建立的結果型別。有效值為 StringResult 或 DomResult(預設值)。以下示例配置了一個編組轉換器
<int-xml:marshalling-transformer
input-channel="marshallingTransformerStringResultFactory"
output-channel="output"
marshaller="marshaller"
result-type="StringResult" />
<int-xml:marshalling-transformer
input-channel="marshallingTransformerWithResultTransformer"
output-channel="output"
marshaller="marshaller"
result-transformer="resultTransformer" />
<bean id="resultTransformer" class="o.s.i.xml.transformer.ResultToStringTransformer"/>
如果提供的結果型別不足以滿足需求,您可以提供對 ResultFactory 的自定義實現的引用,作為透過使用 result-factory 屬性設定 result-type 屬性的替代方案。result-type 和 result-factory 屬性互斥。
在內部,StringResult 和 DomResult 結果型別分別由 ResultFactory 實現:StringResultFactory 和 DomResultFactory 表示。 |
使用 XsltPayloadTransformer
XsltPayloadTransformer 的名稱空間支援允許您傳入 Resource(以便建立 Templates 例項)或傳入預先建立的 Templates 例項作為引用。與編組轉換器一樣,您可以透過指定 result-factory 或 result-type 屬性來控制結果輸出的型別。當您需要在傳送之前轉換結果時,可以使用 result-transformer 屬性來引用 ResultTransformer 的實現。
如果您指定 result-factory 或 result-type 屬性,則底層 XsltPayloadTransformer 上的 alwaysUseResultFactory 屬性將由 XsltPayloadTransformerParser 設定為 true。 |
以下示例配置了兩個XSLT轉換器
<int-xml:xslt-transformer id="xsltTransformerWithResource"
input-channel="withResourceIn" output-channel="output"
xsl-resource="org/springframework/integration/xml/config/test.xsl"/>
<int-xml:xslt-transformer id="xsltTransformerWithTemplatesAndResultTransformer"
input-channel="withTemplatesAndResultTransformerIn" output-channel="output"
xsl-templates="templates"
result-transformer="resultTransformer"/>
您可能需要訪問 Message 資料(例如 Message 頭部)以協助轉換。例如,您可能需要訪問某些 Message 頭部並將它們作為引數傳遞給轉換器,例如 transformer.setParameter(..)。Spring Integration提供了兩種便捷的方法來完成此操作,如下例所示
<int-xml:xslt-transformer id="paramHeadersCombo"
input-channel="paramHeadersComboChannel" output-channel="output"
xsl-resource="classpath:transformer.xslt"
xslt-param-headers="testP*, *foo, bar, baz">
<int-xml:xslt-param name="helloParameter" value="hello"/>
<int-xml:xslt-param name="firstName" expression="headers.fname"/>
</int-xml:xslt-transformer>
如果訊息頭名稱與引數名稱一對一匹配,您可以使用 xslt-param-headers 屬性。在該屬性中,您可以使用萬用字元進行簡單的模式匹配。它支援以下簡單的模式樣式:xxx*、*xxx*、*xxx 和 xxx*yyy。
您還可以使用 <xslt-param/> 元素配置單個XSLT引數。在該元素上,您可以設定 expression 屬性或 value 屬性。expression 屬性應該是任何有效的SpEL表示式,其中 Message 是表示式評估上下文的根物件。value 屬性(與Spring Bean中的任何 value 一樣)允許您指定簡單的標量值。您還可以使用屬性佔位符(例如 ${some.value})。因此,透過 expression 和 value 屬性,您可以將XSLT引數對映到 Message 的任何可訪問部分以及任何字面值。
從Spring Integration 3.0開始,您現在可以透過設定 transformer-factory-class 屬性來指定轉換器工廠類名。
名稱空間配置和結果轉換器
我們在 使用 ResultTransformer 實現 中介紹了結果轉換器的使用。本節中的示例使用XML名稱空間配置來演示幾個特殊用例。首先,我們定義 ResultTransformer,如下例所示
<beans:bean id="resultToDoc" class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>
此 ResultTransformer 接受 StringResult 或 DOMResult 作為輸入,並將輸入轉換為 Document。
現在我們可以宣告轉換器,如下所示
<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"/>
如果傳入訊息的負載型別是 Source,則第一步是使用 ResultFactory 確定 Result。由於我們沒有指定 ResultFactory,因此使用預設的 DomResultFactory,這意味著轉換會生成 DomResult。
然而,由於我們指定了 ResultTransformer,它將被使用,並且生成的訊息負載型別為 Document。
對於 String 或 Document 負載,指定的 ResultTransformer 將被忽略。如果傳入訊息的負載型別是 String,則XSLT轉換後的負載是 String。類似地,如果傳入訊息的負載型別是 Document,則XSLT轉換後的負載是 Document。 |
如果訊息負載不是 Source、String 或 Document,作為備用選項,我們嘗試使用預設的 SourceFactory 建立 Source。由於我們沒有透過 source-factory 屬性顯式指定 SourceFactory,因此使用預設的 DomSourceFactory。如果成功,則執行XSLT轉換,就好像負載型別是 Source 一樣,如前幾段所述。
DomSourceFactory 支援從 Document、File 或 String 負載建立 DOMSource。 |
下一個轉換器宣告添加了一個 result-type 屬性,其值為 StringResult。result-type 在內部由 StringResultFactory 表示。因此,您也可以透過使用 result-factory 屬性新增對 StringResultFactory 的引用,結果將是相同的。以下示例顯示了該轉換器宣告
<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"
result-type="StringResult"/>
由於我們使用了 ResultFactory,XsltPayloadTransformer 類的 alwaysUseResultFactory 屬性被隱式設定為 true。因此,引用的 ResultToDocumentTransformer 將被使用。
因此,如果您轉換型別為 String 的負載,則生成的負載型別為 Document。
XsltPayloadTransformer 和 <xsl:output method="text"/>
<xsl:output method="text"/> 告訴XSLT模板僅從輸入源生成文字內容。在這種特殊情況下,我們沒有理由使用 DomResult。因此,如果底層 javax.xml.transform.Transformer 的 輸出屬性 中名為 method 的屬性返回 text,則 XsltPayloadTransformer 預設使用 StringResult。此強制轉換與入站負載型別無關。此行為僅在為 <int-xml:xslt-transformer> 元件設定了 result-type 屬性或 result-factory 屬性時可用。