转换 XML 负载

本节介绍如何转换 XML 负载

将转换器配置为 Bean

本节将解释以下转换器的运作方式以及如何将它们配置为 Bean

所有 XML 转换器都扩展了 AbstractTransformerAbstractPayloadTransformer,因此实现了 Transformer。在 Spring Integration 中将 XML 转换器配置为 Bean 时,通常会将 TransformerMessageTransformingHandler 结合配置。这使得转换器可以作为端点使用。最后,我们将讨论命名空间支持,它允许将转换器配置为 XML 中的元素。

UnmarshallingTransformer

一个 UnmarshallingTransformer 允许使用 Spring OXMUnmarshaller 实现来反序列化 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 作为传入有效负载。当我们通过 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

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 转换器的命名空间支持

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

使用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` 接受 `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` 一样,如前几段所述。

`DomSourceFactory` 支持从 `Document`、`File` 或 `String` 有效负载创建 `DOMSource`。

下一个转换器声明添加了一个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。因此,XsltPayloadTransformer在以下情况下默认使用StringResult:如果底层javax.xml.transform.Transformermethod输出属性返回text。这种强制转换独立于入站有效负载类型执行。此行为仅在您设置<int-xml:xslt-transformer>组件的result-type属性或result-factory属性时才可用。