转换 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 集成提供了两种实现,一种是转换为 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>
默认情况下,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 转换器的命名空间支持
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
命名空间支持需要为 marshalling transformer 配置一个 input-channel
,一个 output-channel
,以及对 marshaller
的引用。你可以使用可选的 result-type
属性来控制创建的结果类型。有效的值是 StringResult
或 DomResult
(默认值)。以下示例配置了一个 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"/>
当提供的结果类型不足以满足需求时,你可以提供对自定义 ResultFactory
实现的引用,作为设置 result-type
属性的替代方案,使用 result-factory
属性即可。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 beans 中的任何 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
类型,那么作为第一步,Result
通过使用 ResultFactory
来确定。因为我们没有指定 ResultFactory
,所以默认使用 DomResultFactory
,这意味着转换会产生一个 DomResult
。
但是,由于我们指定了一个 ResultTransformer
,所以它被使用了, resulting Message
payload 的类型是 Document
。
指定的 ResultTransformer
在使用 String
或 Document
类型的有效负载时将被忽略。如果传入消息的有效负载类型为 String
,则 XSLT 转换后的有效负载将是一个 String
。同样地,如果传入消息的有效负载类型为 Document
,则 XSLT 转换后的有效负载将是一个 Document
。
如果消息的有效负载不是 Source
、String
或 Document
,作为回退选项,我们尝试通过使用默认的 SourceFactory 来创建一个 `Source`。由于我们没有使用 source-factory
属性显式指定一个 SourceFactory
,因此会使用默认的 DomSourceFactory。如果成功,XSLT 转换将被执行,就像有效负载是 Source
类型一样,如前几段所述。
DomSourceFactory
支持从 Document
、File
或 String
负载创建 DOMSource
。
下一个 transformer 声明添加了一个 result-type
属性,其值使用 StringResult
。result-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"/>
因为使用了 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.Transformer
的 output property 中名为 method
的属性返回 text
,XsltPayloadTransformer 将默认为 StringResult
。这种强制转换独立于传入的有效负载类型进行。只有当您为 <int-xml:xslt-transformer>
组件设置 result-type
属性或 result-factory
属性时,才会提供此行为。