转换 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作为传入负载。当我们通过 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。以下示例配置一个转换为文档的编组转换器。

<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一样,XsltPayloadTransformer针对Source实例执行实际的 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 命名空间中提供,其模板前面已显示。转换器的命名空间支持根据提供的输入通道的类型创建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-channeloutput-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-factory属性设置result-type属性的替代方法。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,则首先使用ResultFactory确定Result。由于我们没有指定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属性时才可用。