Transforming XML Payloads
本节介绍如何转换 XML 有效负载
Configuring Transformers as Beans
本节将解释以下转换器的作用以及如何将其配置为 bean:
所有 XML 转换器都扩展 AbstractTransformer
或 AbstractPayloadTransformer
,因此实现了 Transformer
。在 Spring Integration 中将 XML 转换器配置为 bean 时,通常会将 Transformer
与 MessageTransformingHandler
一起配置。这让转换器能够用作端点。最后,我们将讨论命名空间支持,它允许将转换器配置为 XML 中的元素。
UnmarshallingTransformer
UnmarshallingTransformer
允许使用 Spring OXM Unmarshaller
的实现对 XML Source
进行非编组。Spring 的 Object/XML Mapping 支持提供了一些实现,支持使用 JAXB、 Castor、 JiBX 等进行编组和非编组。解编组器需要 Source
的实例。如果消息有效负载不是 Source
的实例,仍然会尝试转换。目前,支持 String
、File
、byte[]
和 org.w3c.dom.Document
有效负载。若要创建到 Source
的自定义转换,可以注入 SourceFactory
的实现。
如果您没有明确设置 |
从 5.0 版本开始,UnmarshallingTransformer
还支持 org.springframework.ws.mime.MimeMessage
作为传入有效负载。当我们收到带有 SOAP 的 MTOM 附件的原始 WebServiceMessage
时,这可能有用。有关详细信息,请参见 MTOM Support。
以下示例显示了如何定义一个取消编组转换器:
<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>
Using MarshallingTransformer
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
XsltPayloadTransformer
使用 Extensible Stylesheet Language Transformations(XSLT)转换 XML 有效负载。转换器的构造函数需要传递 Resource 或 Templates 实例。传递 Templates
实例允许对用于创建模板实例的 TransformerFactory
进行更高级别的配置。
与 UnmarshallingTransformer
一样,XsltPayloadTransformer
对 Source
实例执行实际 XSLT 转换。因此,如果消息有效负载不是 Source
的实例,系统仍会尝试转换。直接支持 String
和 Document
有效负载。
若要创建到 Source
的自定义转换,可以注入 SourceFactory
的实现。
如果未明确设置`SourceFactory`,则`XsltPayloadTransformer`上的属性默认设置为 link:https://docs.spring.io/spring-integration/api/org/springframework/integration/xml/source/DomSourceFactory.html[ |
默认情况下,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
属性来执行此操作。
Using ResultTransformer
Implementations
MarshallingTransformer
和 XsltPayloadTransformer
都允许您指定 ResultTransformer
。因此,如果编组或 XSLT 转换返回 Result
,您可以选择还使用 ResultTransformer
将 Result
转换为另一种格式。Spring Integration 提供了两个具体的 ResultTransformer
实现:
默认情况下,MarshallingTransformer
始终返回 Result
。通过指定 ResultTransformer
,您可以自定义返回的有效负载类型。
对于 XsltPayloadTransformer
,该行为稍微复杂一些。默认情况下,如果输入有效负载是 String
或 Document
的实例,则将忽略 resultTransformer
属性。
但是,如果输入有效负载是 Source
或任何其他类型,则将应用 resultTransformer
属性。此外,您可以将 alwaysUseResultFactory
属性设置为 true
,这还会导致使用指定的 resultTransformer
。
有关更多信息和示例,请参阅 Namespace Configuration and Result Transformers。
Namespace Support for XML Transformers
Spring Integration XML 命名空间中提供了对所有 XML 变换器的命名空间支持,该命名空间的模板前面已经[显示,xpath-namespace-support]。针对变换器的命名空间支持会根据提供的输入通道的类型创建一个 EventDrivenConsumer
或 PollingConsumer
实例。命名空间支持旨在通过允许创建端点和使用一个元素的变换器来减少 XML 配置量。
Using an 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/>
Using a 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"/>
如果没有足够提供的结果类型,则可以提供对 ResultFactory
自定义实现的引用,而不是使用 result-type
属性设置 result-type
属性 result-factory
属性。result-type
和 result-factory
属性是互斥的。
在内部, |
Using an XsltPayloadTransformer
XsltPayloadTransformer
的命名空间支持允许您传入 Resource
(以创建 Templates
实例)或作为引用传入一个预先创建的 Templates
实例。与编组转换器一样,您可以通过指定 result-factory
或 result-type
属性来控制结果输出的类型。在发送之前需要转换结果时,可以使用 result-transformer
属性来引用 ResultTransformer
的实现。
如果您指定 result-factory`或`result-type`属性,`alwaysUseResultFactory`在底层 link:https://docs.spring.io/spring-integration/api/org/springframework/integration/xml/transformer/XsltPayloadTransformer.html[`XsltPayloadTransformer`上的属性由 link:https://docs.spring.io/spring-integration/api/org/springframework/integration/xml/config/XsltPayloadTransformerParser.html[`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
属性来指定变换器工厂类名。
Namespace Configuration and Result Transformers
我们在 Using ResultTransformer
Implementations 中介绍了结果转换器的使用方法。本部分中的示例使用 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
,如前几段所述。
|
下一个转换器声明添加了 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`和 `<xsl:output method="text"/>
<xsl:output method="text"/>
告诉 XSLT 模板仅从输入源生成文本内容。在这种特殊情况下,我们没有理由使用 DomResult
。因此,如果叫做 method
的 javax.xml.transform.Transformer
的 output property 返回 text
,则 XsltPayloadTransformer
默认为 StringResult
。此强制转换独立于入站负载类型执行。此行为只有在您为 <int-xml:xslt-transformer>
组件设置了 result-type
属性或 result-factory
属性时才可用。