轉換 XML 載荷

本節介紹如何轉換 XML 載荷

將 Transformer 配置為 Bean

本節將解釋以下轉換器的工作原理以及如何將它們配置為 Bean

所有 XML 轉換器都擴充套件了 AbstractTransformerAbstractPayloadTransformer,因此實現了 Transformer。在 Spring Integration 中將 XML 轉換器配置為 Bean 時,通常會結合 MessageTransformingHandler 配置 Transformer。這使得轉換器可以用作端點。最後,我們將討論名稱空間支援,它允許將轉換器配置為 XML 中的元素。

UnmarshallingTransformer

一個 UnmarshallingTransformer 允許使用 Spring OXMUnmarshaller 實現來解組 XML Source。Spring 的物件/XML 對映支援提供了多種實現,支援使用 JAXBCastorJiBX 等進行編組和解組。解組器需要一個 Source 例項。如果訊息載荷不是 Source 例項,仍然會嘗試轉換。目前支援 StringFilebyte[]org.w3c.dom.Document 載荷。要建立自定義轉換為 Source 的功能,可以注入 SourceFactory 的實現。

如果未顯式設定 SourceFactoryUnmarshallingTransformer 上的屬性預設為 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 使用 Extensible Stylesheet Language Transformations (XSLT) 來轉換 XML 載荷。轉換器的建構函式需要傳入 ResourceTemplates 例項。傳入 Templates 例項可以更好地配置用於建立模板例項的 TransformerFactory

UnmarshallingTransformer 類似,XsltPayloadTransformerSource 例項執行實際的 XSLT 轉換。因此,如果訊息載荷不是 Source 例項,仍然會嘗試轉換。直接支援 StringDocument 載荷。

要建立自定義轉換為 Source 的功能,可以注入 SourceFactory 的實現。

如果未顯式設定 SourceFactoryXsltPayloadTransformer 上的屬性預設為 DomSourceFactory

預設情況下,XsltPayloadTransformer 會建立一個訊息,其載荷為 Result,類似於 XmlPayloadMarshallingTransformer。您可以透過提供 ResultFactoryResultTransformer 來定製此行為。

以下示例配置了一個用作 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 實現

MarshallingTransformerXsltPayloadTransformer 都允許您指定一個 ResultTransformer。因此,如果編組或 XSLT 轉換返回一個 Result,您可以選擇使用 ResultTransformerResult 轉換為另一種格式。Spring Integration 提供了兩個具體的 ResultTransformer 實現

預設情況下,MarshallingTransformer 總是返回一個 Result。透過指定 ResultTransformer,您可以自定義返回的載荷型別。

對於 XsltPayloadTransformer,行為稍微複雜一些。預設情況下,如果輸入載荷是 StringDocument 的例項,則會忽略 resultTransformer 屬性。

但是,如果輸入載荷是 Source 或其他任何型別,則會應用 resultTransformer 屬性。此外,您可以將 alwaysUseResultFactory 屬性設定為 true,這也會導致使用指定的 resultTransformer

有關更多資訊和示例,請參閱名稱空間配置和 Result Transformer

XML 轉換器的名稱空間支援

Spring Integration XML 名稱空間中提供了所有 XML 轉換器的名稱空間支援,其模板之前已展示。轉換器的名稱空間支援根據提供的輸入通道的型別建立 EventDrivenConsumerPollingConsumer 例項。名稱空間支援旨在透過允許使用一個元素建立端點和轉換器來減少 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-channeloutput-channel 和對 marshaller 的引用。您可以使用可選的 result-type 屬性來控制建立的結果型別。有效值為 StringResultDomResult(預設)。以下示例配置了一個編組轉換器

<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"/>

如果提供的結果型別不滿足需求,您可以使用 result-factory 屬性提供對 ResultFactory 自定義實現的引用,作為設定 result-type 屬性的替代方案。result-typeresult-factory 屬性互斥。

在內部,StringResultDomResult 結果型別分別由 ResultFactory 實現 StringResultFactoryDomResultFactory 表示。

使用 XsltPayloadTransformer

XsltPayloadTransformer 的名稱空間支援允許您傳入 Resource(以便建立 Templates 例項)或將預先建立的 Templates 例項作為引用傳入。與編組轉換器一樣,您可以透過指定 result-factoryresult-type 屬性來控制結果輸出的型別。當需要在傳送之前轉換結果時,您可以使用 result-transformer 屬性引用 ResultTransformer 的實現。

如果您指定了 result-factoryresult-type 屬性,則底層 XsltPayloadTransformeralwaysUseResultFactory 屬性將被 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})。因此,透過 expressionvalue 屬性,您可以將 XSLT 引數對映到 Message 的任何可訪問部分以及任何文字值。

從 Spring Integration 3.0 開始,您現在可以透過設定 transformer-factory-class 屬性來指定轉換器工廠類名。

名稱空間配置和 Result Transformer

我們在使用 ResultTransformer 實現中介紹了使用結果轉換器。本節中的示例使用 XML 名稱空間配置來說明幾個特殊用例。首先,我們定義 ResultTransformer,如下例所示

<beans:bean id="resultToDoc" class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>

ResultTransformer 接受 StringResultDOMResult 作為輸入,並將輸入轉換為 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,它會被使用,並且生成的 Message 載荷型別為 Document

對於 StringDocument 載荷,指定的 ResultTransformer 會被忽略。如果入站訊息的載荷型別為 String,則 XSLT 轉換後的載荷是一個 String。同樣,如果入站訊息的載荷型別為 Document,則 XSLT 轉換後的載荷是一個 Document

如果訊息載荷不是 SourceStringDocument,則作為備選方案,我們嘗試使用預設的 SourceFactory 建立一個 Source。由於我們沒有透過 source-factory 屬性顯式指定 SourceFactory,因此使用了預設的 DomSourceFactory。如果成功,XSLT 轉換將執行,如同載荷是 Source 型別一樣,如前幾段所述。

DomSourceFactory 支援從 DocumentFileString 載荷建立 DOMSource

下一個轉換器宣告添加了一個 result-type 屬性,其值為 StringResultresult-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-and-<xsl:output-method=-text-/>]] === 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 屬性時可用。