转换 XML 负载

本节介绍如何转换 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 作为传入负载。 当我们收到带有 MTOM 附件的原始 WebServiceMessage(通过 SOAP)时,这会很有用。 有关更多信息,请参阅 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-factory-class 属性来完成此操作。

使用 ResultTransformer 实现

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

默认情况下,MarshallingTransformer 总是返回 Result。 通过指定 ResultTransformer,您可以自定义返回的负载类型。

XsltPayloadTransformer 的行为略微复杂。 默认情况下,如果输入负载是 StringDocument 的实例,则 resultTransformer 属性将被忽略。

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

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

XML 转换器的命名空间支持

所有 XML 转换器的命名空间支持都在 Spring Integration XML 命名空间中提供,其模板已在 xpath-namespace-support。 转换器的命名空间支持根据所提供输入通道的类型创建 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

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

<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-typeresult-factory 属性是互斥的。

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

使用 XsltPayloadTransformer

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

如果您指定 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

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

<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,它将被使用,并且最终的 Message 负载将是 Document 类型。

对于 StringDocument 负载,指定的 ResultTransformer 将被忽略。 如果传入消息的负载类型是 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"/>

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

因此,如果您转换 String 类型的负载,则生成的负载将是 Document 类型。

[[xsltpayloadtransformer-and-<xsl:output-method=-text-/>]] === 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 属性时可用。