跳到主要内容

转换 XML 负载

QWen Plus 中英对照 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 的实现。

备注

如果你没有显式设置 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>
xml

使用 MarshallingTransformer

MarshallingTransformer 允许使用 Spring OXM Marshaller 将对象图转换为 XML。默认情况下,MarshallingTransformer 返回一个 DomResult。但是,您可以通过配置替代的 ResultFactory(例如 StringResultFactory)来控制结果类型。在许多情况下,将负载转换为替代的 XML 格式会更方便。为此,请配置一个 ResultTransformer。Spring 集成提供了两种实现,一种是转换为 String,另一种是转换为 Document。以下示例配置了一个将转换为文档的 marshalling 转换器:

<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>
xml

默认情况下,MarshallingTransformer 将有效负载对象传递给 Marshaller。但是,如果其布尔属性 extractPayload 被设置为 false,则整个 Message 实例将被传递给 Marshaller。这可能对 Marshaller 接口的某些自定义实现有用,但通常来说,在你委托给各种 Marshaller 实现中的任何一个时,有效负载是用于编组的适当源对象。

XsltPayloadTransformer

XsltPayloadTransformer 使用 可扩展样式语言转换 (XSLT) 来转换 XML 负载。转换器的构造函数需要传入 ResourceTemplates 的一个实例。传入 Templates 实例可以对用于创建模板实例的 TransformerFactory 进行更详细的配置。

UnmarshallingTransformer 一样,XsltPayloadTransformerSource 的实例执行实际的 XSLT 转换。因此,如果消息有效负载不是 Source 的实例,仍然会尝试进行转换。直接支持 StringDocument 类型的有效负载。

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

备注

如果未显式设置 SourceFactoryXsltPayloadTransformer 上的属性将默认设置为 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>
xml

从 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

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

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

使用 MarshallingTransformer

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

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

当提供的结果类型不足以满足需求时,你可以提供对自定义 ResultFactory 实现的引用,作为设置 result-type 属性的替代方案,使用 result-factory 属性即可。result-typeresult-factory 属性是互斥的。

备注

在内部,StringResultDomResult 结果类型由 ResultFactory 实现表示:StringResultFactoryDomResultFactory 分别。

使用 XsltPayloadTransformer

命名空间支持 XsltPayloadTransformer 让你可以传递一个 Resource(用于创建 Templates 实例)或传递一个预先创建的 Templates 实例作为引用。与编组转换器一样,你可以通过指定 result-factoryresult-type 属性来控制结果输出的类型。当你需要在发送前转换结果时,可以使用 result-transformer 属性引用 ResultTransformer 的实现。

important

如果您指定了 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"/>
xml

你可能需要访问 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>
xml

如果消息头名称与参数名称一对一匹配,你可以使用 xslt-param-headers 属性。在其中,你可以使用通配符进行简单的模式匹配。它支持以下简单的模式样式:xxx***xxx***xxxxxx*yyy

您也可以通过使用 <xslt-param/> 元素来配置单个 XSLT 参数。在该元素上,您可以设置 expression 属性或 value 属性。expression 属性应该是任何有效的 SpEL 表达式,其中 Message 是表达式求值上下文的根对象。value 属性(如同 Spring beans 中的任何 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"/>
xml

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

现在我们可以声明转换器,如下所示:

<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"/>
xml

如果传入消息的有效载荷是 Source 类型,那么作为第一步,Result 通过使用 ResultFactory 来确定。因为我们没有指定 ResultFactory,所以默认使用 DomResultFactory,这意味着转换会产生一个 DomResult

但是,由于我们指定了一个 ResultTransformer,所以它被使用了, resulting Message payload 的类型是 Document

important

指定的 ResultTransformer 在使用 StringDocument 类型的有效负载时将被忽略。如果传入消息的有效负载类型为 String,则 XSLT 转换后的有效负载将是一个 String。同样地,如果传入消息的有效负载类型为 Document,则 XSLT 转换后的有效负载将是一个 Document

如果消息的有效负载不是 SourceStringDocument,作为回退选项,我们尝试通过使用默认的 SourceFactory 来创建一个 `Source`。由于我们没有使用 source-factory 属性显式指定一个 SourceFactory,因此会使用默认的 DomSourceFactory。如果成功,XSLT 转换将被执行,就像有效负载是 Source 类型一样,如前几段所述。

备注

DomSourceFactory 支持从 DocumentFileString 负载创建 DOMSource

下一个 transformer 声明添加了一个 result-type 属性,其值使用 StringResultresult-type 在内部由 StringResultFactory 表示。因此,你也可以通过使用 result-factory 属性添加对 StringResultFactory 的引用,这将是相同的。以下示例显示了该 transformer 声明:

<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"
result-type="StringResult"/>
xml

因为使用了 ResultFactory,所以 XsltPayloadTransformer 类的 alwaysUseResultFactory 属性被隐式设置为 true。因此,引用的 ResultToDocumentTransformer 被使用。

因此,如果您转换类型为 String 的有效负载,则 resulting payload 的类型为 Document

[[XsltPayloadTransformer 和 <xsl:output method = text />]] === XsltPayloadTransformer<xsl:output method="text"/>

<xsl:output method="text"/> 告诉 XSLT 模板仅从输入源生成文本内容。在这种情况 下,我们没有理由使用 DomResult。因此,如果底层 javax.xml.transform.Transformeroutput property 中名为 method 的属性返回 textXsltPayloadTransformer 将默认为 StringResult。这种强制转换独立于传入的有效负载类型进行。只有当您为 <int-xml:xslt-transformer> 组件设置 result-type 属性或 result-factory 属性时,才会提供此行为。