跳到主要内容
版本:7.0.2

转换 XML 负载

DeepSeek V3 中英对照 Transforming XML Payloads

本节介绍如何转换 XML 负载

配置转换器为Bean

本节将解释以下转换器的工作原理以及如何将它们配置为Bean:

所有 XML 转换器都继承自 AbstractTransformerAbstractPayloadTransformer,因此实现了 Transformer 接口。在 Spring Integration 中将 XML 转换器配置为 Bean 时,通常会将 TransformerMessageTransformingHandler 结合配置,从而使转换器能够作为端点使用。最后,我们将讨论命名空间支持,它允许将转换器配置为 XML 中的元素。

UnmarshallingTransformer

UnmarshallingTransformer 允许使用 Spring OXM Unmarshaller 的实现来解组 XML Source。Spring 的对象/XML 映射支持提供了多种实现,支持使用 JAXBCastorJiBX 等进行编组和解组。解组器需要一个 Source 的实例。如果消息负载不是 Source 的实例,仍会尝试进行转换。目前支持 StringFilebyte[]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 负载。该转换器的构造函数需要传入一个 ResourceTemplates 的实例。传入一个 Templates 实例允许对用于创建模板实例的 TransformerFactory 进行更详细的配置。

UnmarshallingTransformer 类似,XsltPayloadTransformerSource 实例执行实际的 XSLT 转换。因此,即使消息负载不是 Source 实例,系统仍会尝试进行转换。StringDocument 类型的负载可直接支持。

要创建自定义转换到 Source,你可以注入一个 SourceFactory 的实现。

备注

如果未显式设置 SourceFactory,默认情况下,XsltPayloadTransformer 上的属性将设置为 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 工厂类名。在使用命名空间时,你可以通过 transformer-factory-class 属性来实现这一点。

使用 ResultTransformer 实现

MarshallingTransformerXsltPayloadTransformer 都允许您指定一个 ResultTransformer。因此,如果编组或 XSLT 转换返回一个 Result,您可以选择同时使用 ResultTransformerResult 转换为另一种格式。Spring Integration 提供了两种具体的 ResultTransformer 实现:

默认情况下,MarshallingTransformer 始终返回一个 Result 对象。通过指定 ResultTransformer,您可以自定义返回的负载类型。

对于 XsltPayloadTransformer 来说,其行为稍微复杂一些。默认情况下,如果输入负载是 StringDocument 的实例,那么 resultTransformer 属性将被忽略。

然而,如果输入负载是 Source 或任何其他类型,则会应用 resultTransformer 属性。此外,您可以将 alwaysUseResultFactory 属性设置为 true,这同样会导致使用指定的 resultTransformer

更多信息和示例,请参阅命名空间配置与结果转换器

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

marshalling 转换器的命名空间支持需要一个 input-channel、一个 output-channel 以及对 marshaller 的引用。你可以使用可选的 result-type 属性来控制创建的结果类型。有效值为 StringResultDomResult(默认值)。以下示例配置了一个 marshalling 转换器:

<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 的实现。

important

如果你指定了 result-factoryresult-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***xxxxxx*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 属性来指定转换器工厂类名。

命名空间配置与结果转换器

我们在使用 ResultTransformer 实现中介绍了结果转换器的使用。本节中的示例使用 XML 命名空间配置来说明几种特殊用例。首先,我们定义 ResultTransformer,如下例所示:

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

这个 ResultTransformer 接受 StringResultDOMResult 作为输入,并将输入转换为 Document

现在我们可以如下声明 transformer:

<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

important

指定的 ResultTransformerStringDocument 类型负载无效。若传入消息的负载为 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"/>

由于我们使用了 ResultFactoryXsltPayloadTransformer 类的 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 属性时,此行为才可用。