|
如需使用最新稳定版本,请使用 Spring Integration 7.0.4! |
转换 XML 负载
本节介绍如何转换 XML 负载
配置转换器为 Bean
本节将解释以下转换器的运作方式,并说明如何将其配置为 Bean:
所有 XML 转换器都扩展自 AbstractTransformer 或 AbstractPayloadTransformer,因此实现了 Transformer。
在 Spring Integration 中将 XML 转换器配置为 Bean 时,通常会将 Transformer 与 MessageTransformingHandler 一起配置。
这使得转换器可以作为端点使用。
最后,我们讨论命名空间支持,它允许将转换器配置为 XML 中的元素。
反序列化转换器
一个 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
The MarshallingTransformer 允许通过使用 Spring OXM Marshaller 将对象图转换为 XML。
默认情况下,MarshallingTransformer 返回 DomResult。
然而,您可以通过配置替代的 ResultFactory(例如 StringResultFactory)来控制结果类型。
在许多情况下,将有效负载转换为替代的 XML 格式更为方便。
为此,请配置一个 ResultTransformer。
Spring 集成提供了两种实现:一种用于转换为 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
The XsltPayloadTransformer通过使用可扩展样式表语言转换(XSLT)来转换XML负载。
transformer的构造函数需要传入一个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实现
Both the MarshallingTransformer and the XsltPayloadTransformer let you specify a ResultTransformer.
Thus, if the marshalling or XSLT transformation returns a Result, you have the option to also use a ResultTransformer to transform the Result into another format.
Spring Integration provides two concrete ResultTransformer implementations:
默认情况下,MarshallingTransformer 始终返回一个 Result。
通过指定 ResultTransformer,您可以自定义返回的负载类型。
对于 XsltPayloadTransformer,其行为稍微复杂一些。
默认情况下,如果输入负载是 String 的实例或 Document,则 resultTransformer 属性将被忽略。
然而,如果输入负载是 Source 或任何其他类型,则应用 resultTransformer 属性。
此外,您可以将 alwaysUseResultFactory 属性设置为 true,这也会导致使用指定的 resultTransformer。
有关更多信息和示例,请参阅 命名空间配置和结果转换器。
XML 转换器的命名空间支持
Spring Integration XML 命名空间为所有 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"/>
当提供的结果类型不足以满足需求时,您可以使用result-factory属性来引用自定义的ResultFactory实现,以此替代设置result-type属性。result-type和result-factory属性是互斥的。
在内部,StringResult和DomResult结果类型分别由ResultFactory实现表示:StringResultFactory和DomResultFactory。 |
使用XsltPayloadTransformer
命名空间支持允许您传入一个 XsltPayloadTransformer(用于创建 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,它被使用,生成的 Message 负载类型为 Document。
指定的 ResultTransformer 在 String 或 Document 负载下将被忽略。
如果传入消息的负载类型为 String,则经过 XSLT 转换后的负载为 String。
同样地,如果传入消息的负载类型为 Document,则经过 XSLT 转换后的负载为 Document。 |
如果消息负载不是 Source、String 或 Document,作为回退选项,我们将尝试使用默认的 SourceFactory 来创建 `Source`。
由于我们未通过 source-factory 属性显式指定 SourceFactory,因此使用了默认的 DomSourceFactory。
如果成功,XSLT 转换将如同消息负载为 Source 类型一样执行,如前文所述。
The DomSourceFactory supports the creation of a DOMSource from a Document, a File, or a String payload. |
下一个转换器声明添加了一个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-and-<xsl:output-method=-text-/>]]
=== XsltPayloadTransformer and <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 属性时,才可使用此行为。