Transforming XML Payloads

This section covers how to transform XML payloads

Configuring Transformers as Beans

This section will explain the workings of the following transformers and how to configure them as beans:

All the XML transformers extend either AbstractTransformer or AbstractPayloadTransformer and therefore implement Transformer. When configuring XML transformers as beans in Spring Integration, you would normally configure the Transformer in conjunction with a MessageTransformingHandler. This lets the transformer be used as an endpoint. Finally, we discuss the namespace support, which allows for configuring the transformers as elements in XML.

UnmarshallingTransformer

An UnmarshallingTransformer lets an XML Source be unmarshalled by using implementations of the Spring OXM Unmarshaller. Spring’s Object/XML Mapping support provides several implementations that support marshalling and unmarshalling by using JAXB, Castor, JiBX, and others. The unmarshaller requires an instance of Source. If the message payload is not an instance of Source, conversion is still attempted. Currently, String, File, byte[] and org.w3c.dom.Document payloads are supported. To create a custom conversion to a Source, you can inject an implementation of a SourceFactory.

If you do not explicitly set a SourceFactory, the property on the UnmarshallingTransformer is, by default, set to a DomSourceFactory.

Starting with version 5.0, the UnmarshallingTransformer also supports an org.springframework.ws.mime.MimeMessage as the incoming payload. This can be useful when we receive a raw WebServiceMessage with MTOM attachments over SOAP . See MTOM Support for more information.

The following example shows how to define an unmarshalling transformer:

<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

The MarshallingTransformer lets an object graph be converted into XML by using a Spring OXM Marshaller. By default, the MarshallingTransformer returns a DomResult. However, you can control the type of result by configuring an alternative ResultFactory, such as StringResultFactory. In many cases, it is more convenient to transform the payload into an alternative XML format. To do so, configure a ResultTransformer. Spring integration provides two implementations, one that converts to String and another that converts to Document. The following example configures a marshalling transformer that transforms to a 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>

By default, the MarshallingTransformer passes the payload object to the Marshaller. However, if its boolean extractPayload property is set to false, the entire Message instance is passed to the Marshaller instead. That may be useful for certain custom implementations of the Marshaller interface, but, typically, the payload is the appropriate source object for marshalling when you delegate to any of the various Marshaller implementations.

XsltPayloadTransformer

The XsltPayloadTransformer transforms XML payloads by using Extensible Stylesheet Language Transformations (XSLT). The transformer’s constructor requires an instance of either Resource or Templates to be passed in. Passing in a Templates instance allows for greater configuration of the TransformerFactory used to create the template instance.

As with the UnmarshallingTransformer, the XsltPayloadTransformer does the actual XSLT transformation against instances of Source. Therefore, if the message payload is not an instance of Source, conversion is still attempted. String and Document payloads are supported directly.

To create a custom conversion to a Source, you can inject an implementation of a SourceFactory.

If a SourceFactory is not set explicitly, the property on the XsltPayloadTransformer is, by default, set to a DomSourceFactory.

By default, the XsltPayloadTransformer creates a message with a Result payload, similar to the XmlPayloadMarshallingTransformer. You can customize this by providing a ResultFactory or a ResultTransformer.

The following example configures a bean that works as an XSLT payload transformer:

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

Starting with Spring Integration 3.0, you can specify the transformer factory class name by using a constructor argument. You can do so by using the transformer-factory-class attribute when you use the namespace.

Using ResultTransformer Implementations

Both the MarshallingTransformer and the XsltPayloadTransformer let you specify a ResultTransformer. Thus, if the marshalling or XSLT transformation returns a Result, you have the option to also use a ResultTransformer to transform the Result into another format. Spring Integration provides two concrete ResultTransformer implementations:

By default, the MarshallingTransformer always returns a Result. By specifying a ResultTransformer, you can customize the type of payload returned.

The behavior is slightly more complex for the XsltPayloadTransformer. By default, if the input payload is an instance of String or Document the resultTransformer property is ignored.

However, if the input payload is a Source or any other type, the resultTransformer property is applied. Additionally, you can set the alwaysUseResultFactory property to true, which also causes the specified resultTransformer to be used.

For more information and examples, see Namespace Configuration and Result Transformers.

Namespace Support for XML Transformers

Namespace support for all XML transformers is provided in the Spring Integration XML namespace, a template for which was shown earlier. The namespace support for transformers creates an instance of either EventDrivenConsumer or PollingConsumer, according to the type of the provided input channel. The namespace support is designed to reduce the amount of XML configuration by allowing the creation of an endpoint and transformer that use one element.

Using an UnmarshallingTransformer

The namespace support for the UnmarshallingTransformer is shown below. Since the namespace create an endpoint instance rather than a transformer, you can nest a poller within the element to control the polling of the input channel. The following example shows how to do so:

<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

The namespace support for the marshalling transformer requires an input-channel, an output-channel, and a reference to a marshaller. You can use the optional result-type attribute to control the type of result created. Valid values are StringResult or DomResult (the default). The following example configures a 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"/>

Where the provided result types do not suffice, you can provide a reference to a custom implementation of ResultFactory as an alternative to setting the result-type attribute by using the result-factory attribute. The result-type and result-factory attributes are mutually exclusive.

Internally, the StringResult and DomResult result types are represented by the ResultFactory implementations: StringResultFactory and DomResultFactory respectively.

Using an XsltPayloadTransformer

Namespace support for the XsltPayloadTransformer lets you either pass in a Resource (in order to create the Templates instance) or pass in a pre-created Templates instance as a reference. As with the marshalling transformer, you can control the type of the result output by specifying either the result-factory or the result-type attribute. When you need to convert result before sending, you can use a result-transformer attribute to reference an implementation of ResultTransformer.

If you specify the result-factory or the result-type attribute, the alwaysUseResultFactory property on the underlying XsltPayloadTransformer is set to true by the XsltPayloadTransformerParser.

The following example configures two XSLT transformers:

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

You may need to have access to Message data, such as the Message headers, in order to assist with transformation. For example, you may need to get access to certain Message headers and pass them on as parameters to a transformer (for example, transformer.setParameter(..)). Spring Integration provides two convenient ways to accomplish this, as the following example shows:

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

If message header names match one-to-one to parameter names, you can use the xslt-param-headers attribute. In it, you can use wildcards for simple pattern matching. It supports the following simple pattern styles: xxx*, xxx, *xxx, and xxx*yyy.

You can also configure individual XSLT parameters by using the <xslt-param/> element. On that element, you can set the expression attribute or the value attribute. The expression attribute should be any valid SpEL expression with the Message being the root object of the expression evaluation context. The value attribute (as with any value in Spring beans) lets you specify simple scalar values. You can also use property placeholders (such as ${some.value}). So, with the expression and value attributes, you can map XSLT parameters to any accessible part of the Message as well as any literal value.

Starting with Spring Integration 3.0, you can now specify the transformer factory class name by setting the transformer-factory-class attribute.

Namespace Configuration and Result Transformers

We cover using result transformers in Using ResultTransformer Implementations. The examples in this section use XML namespace configuration to illustrates several special use cases. First, we define the ResultTransformer, as the following example shows:

<beans:bean id="resultToDoc" class="o.s.i.xml.transformer.ResultToDocumentTransformer"/>

This ResultTransformer accepts either a StringResult or a DOMResult as input and converts the input into a Document.

Now we can declare the transformer, as follows:

<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
    xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"/>

If the incoming message’s payload is of type Source, then, as a first step, the Result is determined by using the ResultFactory. As we did not specify a ResultFactory, the default DomResultFactory is used, meaning that the transformation yields a DomResult.

However, as we specified a ResultTransformer, it is used and the resulting Message payload is of type Document.

The specified ResultTransformer is ignored with String or Document payloads. If the incoming message’s payload is of type String, the payload after the XSLT transformation is a String. Similarly, if the incoming message’s payload is of type Document, the payload after the XSLT transformation is a`Document`.

If the message payload is not a Source, a String, or a Document, as a fallback option, we try to create a`Source` by using the default SourceFactory. As we did not specify a SourceFactory explicitly by using the source-factory attribute, the default DomSourceFactory is used. If successful, the XSLT transformation is executed as if the payload was of type Source, as described in the previous paragraphs.

The DomSourceFactory supports the creation of a DOMSource from a Document, a File, or a String payload.

The next transformer declaration adds a result-type attribute that uses StringResult as its value. The result-type is internally represented by the StringResultFactory. Thus, you could have also added a reference to a StringResultFactory, by using the result-factory attribute, which would have been the same. The following example shows that transformer declaration:

<int-xml:xslt-transformer input-channel="in" output-channel="fahrenheitChannel"
		xsl-resource="classpath:noop.xslt" result-transformer="resultToDoc"
		result-type="StringResult"/>

Because we use a ResultFactory, the alwaysUseResultFactory property of the XsltPayloadTransformer class is implicitly set to true. Consequently, the referenced ResultToDocumentTransformer is used.

Therefore, if you transform a payload of type String, the resulting payload is of type Document.

[[xsltpayloadtransformer-and-<xsl:output-method=-text-/>]] === XsltPayloadTransformer and <xsl:output method="text"/>

<xsl:output method="text"/> tells the XSLT template to produce only text content from the input source. In this particular case, we have no reason to use a DomResult. Therefore, the XsltPayloadTransformer defaults to StringResult if the output property called method of the underlying javax.xml.transform.Transformer returns text. This coercion is performed independently from the inbound payload type. This behavior is available only you set the if the result-type attribute or the result-factory attribute for the <int-xml:xslt-transformer> component.