383 lines
22 KiB
XML
383 lines
22 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<chapter id="xml">
|
|
<title>Dealing with XML Payloads</title>
|
|
|
|
<section id="xml-intro">
|
|
<title>Introduction</title>
|
|
<para>
|
|
Spring Integration's XML support extends the Spring Integration Core with
|
|
implementations of splitter, transformer, selector and router designed
|
|
to make working with xml messages in Spring Integration simple. The provided messaging
|
|
components are designed to work with xml represented in a range of formats including
|
|
instances of
|
|
<classname>java.lang.String</classname>, <interfacename>org.w3c.dom.Document</interfacename>
|
|
and <interfacename>javax.xml.transform.Source</interfacename>. It should be noted however that
|
|
where a DOM representation is required, for example in order to evaluate an XPath expression,
|
|
the <classname>String</classname> payload will be converted into the required type and then
|
|
converted back again to <classname>String</classname>. Components that require an instance of
|
|
<interfacename>DocumentBuilder</interfacename> will create a namespace aware instance if one is
|
|
not provided. Where greater control of the document being created is required an appropriately
|
|
configured instance of <interfacename>DocumentBuilder</interfacename> should be provided.
|
|
</para>
|
|
</section>
|
|
<section id="xml-transformation">
|
|
<title>Transforming xml payloads</title>
|
|
<para>
|
|
This section will explain the workings of
|
|
<classname>XmlPayloadUnmarshallingTransformer</classname>,
|
|
<classname>XmlPayloadMarshallingTransformer</classname>,
|
|
<classname>XsltPayloadTransformer</classname>
|
|
and how to configure them as
|
|
<emphasis>beans</emphasis>. All of the provided xml transformers extend
|
|
<classname>AbstractPayloadTransformer</classname> and therefore implement
|
|
<interfacename>Transformer</interfacename>. When configuring xml transformers as beans in
|
|
Spring Integration you would normally configure the transformer in conjunction with either
|
|
a <classname>MessageTransformingChannelInterceptor</classname> or a
|
|
<classname>MessageTransformingConsumer</classname>. This allows the transformer to be used as either an interceptor,
|
|
which transforms the message as it is sent or received to the channel, or as an endpoint. Finally the
|
|
namespace support will be discussed which allows for the simple configuration of the transformers as
|
|
<interfacename>MessageEndpoint</interfacename> instances.
|
|
</para>
|
|
<para>
|
|
<classname>XmlPayloadUnmarshallingTransformer</classname> allows an xml <interfacename>Source</interfacename>
|
|
to be unmarshalled using implementations of Spring OXM <interfacename>Unmarshaller</interfacename>.
|
|
Spring OXM provides several implementations supporting marshalling and unmarshalling using JAXB,
|
|
Castor and JiBX amongst others. Since the unmarshaller requires an instance of
|
|
<interfacename>Source</interfacename> where the message payload is not currently an instance of
|
|
<interfacename>Source</interfacename>, conversion will be attempted. Currently <classname>String</classname>
|
|
and <interfacename>org.w3c.dom.Document</interfacename> payloads are supported. Custom conversion to a
|
|
<interfacename>Source</interfacename> is also supported by injecting an implementation of
|
|
<interfacename>SourceFactory</interfacename>.
|
|
<programlisting language="xml"><![CDATA[<bean id="unmarshallingTransformer"
|
|
class="org.springframework.integration.xml.transformer.XmlPayloadUnmarshallingTransformer">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.oxm.jaxb.Jaxb1Marshaller">
|
|
<property name="contextPath" value="org.example" />
|
|
</bean>
|
|
</constructor-arg>
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
The <classname>XmlPayloadMarshallingTransformer</classname> allows an object graph to be converted
|
|
into xml using a Spring OXM <interfacename>Marshaller</interfacename>. By default the
|
|
<classname>XmlPayloadMarshallingTransformer</classname> will return a <classname>DomResult</classname>.
|
|
However the type of result can be controlled by configuring an alternative <interfacename>ResultFactory</interfacename>
|
|
such as <classname>StringResultFactory</classname>. In many cases it will be more convenient to transform
|
|
the payload into an alternative xml format. To achieve this configure a
|
|
<interfacename>ResultTransformer</interfacename>. Two implementations are provided, one which converts to
|
|
<classname>String</classname> and another which converts to <interfacename>Document</interfacename>.
|
|
<programlisting language="xml"><![CDATA[<bean id="marshallingTransformer"
|
|
class="org.springframework.integration.xml.transformer.XmlPayloadMarshallingTransformer">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.oxm.jaxb.Jaxb1Marshaller">
|
|
<property name="contextPath" value="org.example" />
|
|
</bean>
|
|
</constructor-arg>
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.transformer.ResultToDocumentTransformer" />
|
|
</constructor-arg>
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
<classname>XsltPayloadTransformer</classname> transforms xml payloads using xsl.
|
|
The transformer requires an instance of either <interfacename>Resource</interfacename> or
|
|
<interfacename>Templates</interfacename>. Passing in a <interfacename>Templates</interfacename> instance
|
|
allows for greater configuration of the <interfacename>TransformerFactory</interfacename> used to create
|
|
the template instance. As in the case of <classname>XmlPayloadMarshallingTransformer</classname>
|
|
by default <classname>XsltPayloadTransformer</classname> will create a message with a
|
|
<interfacename>Result</interfacename> payload. This can be customised by providing a
|
|
<interfacename>ResultFactory</interfacename> and/or a <interfacename>ResultTransformer</interfacename>.
|
|
<programlisting language="xml"><![CDATA[<bean id="xsltPayloadTransformer"
|
|
class="org.springframework.integration.xml.transformer.XsltPayloadTransformer">
|
|
<constructor-arg value="classpath:org/example/xsl/transform.xsl" />
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.transformer.ResultToDocumentTransformer" />
|
|
</constructor-arg>
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="xml-transformer-namespace">
|
|
|
|
<title>Namespace support for xml transformers</title>
|
|
<para>
|
|
Namespace support for all xml transformers is provided in the Spring Integration xml namespace,
|
|
a template for which can be seen below. The namespace support for transformers creates an instance of either
|
|
<classname>SubscribingConsumerEndpoint</classname> or <classname>PollingConsumerEndpoint</classname>
|
|
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
|
|
using one element.
|
|
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xmlns:integration="http://www.springframework.org/schema/integration"
|
|
xmlns:si-xml="http://www.springframework.org/schema/integration/xml"
|
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
http://www.springframework.org/schema/integration
|
|
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
|
http://www.springframework.org/schema/integration/xml
|
|
http://www.springframework.org/schema/integration/xml/spring-integration-xml-1.0.xsd">
|
|
</beans>]]></programlisting>
|
|
The namespace support for <classname>XmlPayloadUnmarshallingTransformer</classname> is shown below.
|
|
Since the namespace is now creating an instance of <interfacename>MessageEndpoint</interfacename> rather
|
|
than a transformer a poller can also be nested within the element to control the polling of the input channel.
|
|
<programlisting language="xml"><![CDATA[<si-xml:unmarshalling-transformer id="defaultUnmarshaller"
|
|
input-channel="input"
|
|
output-channel="output"
|
|
unmarshaller="unmarshaller"/>
|
|
|
|
<si-xml:unmarshalling-transformer id="unmarshallerWithPoller"
|
|
input-channel="input"
|
|
output-channel="output"
|
|
unmarshaller="unmarshaller">
|
|
<si:poller>
|
|
<si:interval-trigger interval="2000"/>
|
|
</si:poller>
|
|
<si-xml:unmarshalling-transformer/>
|
|
]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
The namespace support for the marshalling transformer requires an input channel, output channel and a
|
|
reference to a marshaller. The optional result-type attribute can be used to control the type of result created,
|
|
valid values are StringResult or DomResult (the default). Where the provided result types are not sufficient a
|
|
reference to a custom implementation of <interfacename>ResultFactory</interfacename> can be provided as an alternative
|
|
to setting the result-type attribute using the result-factory attrbitue. An optional result-transformer can also be
|
|
specified in order to convert the created <interfacename>Result</interfacename> after marshalling.
|
|
<programlisting language="xml"><![CDATA[<si-xml:marshalling-transformer
|
|
input-channel="marshallingTransformerStringResultFactory"
|
|
output-channel="output"
|
|
marshaller="marshaller"
|
|
result-type="StringResult" />
|
|
|
|
<si-xml:marshalling-transformer
|
|
input-channel="marshallingTransformerWithResultTransformer"
|
|
output-channel="output"
|
|
marshaller="marshaller"
|
|
result-transformer="resultTransformer" />
|
|
|
|
<bean id="resultTransformer"
|
|
class="org.springframework.integration.xml.transformer.ResultToStringTransformer"/>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Namespace support for the <classname>XsltPayloadTransformer</classname> allows either a resource to be passed in in order to create the
|
|
<interfacename>Templates</interfacename> instance or alternatively a precreated <interfacename>Templates</interfacename>
|
|
instance can be passed in as a reference. In common with the marshalling transformer the type of the result output can
|
|
be controlled by specifying either the result-factory or result-type attribute. A result-transfomer attribute can also
|
|
be used to reference an implementation of <interfacename>ResultTransfomer</interfacename> where conversion of the result
|
|
is required before sending.
|
|
<programlisting language="xml"><![CDATA[<si-xml:xslt-transformer id="xsltTransformerWithResource"
|
|
input-channel="withResourceIn"
|
|
output-channel="output"
|
|
xsl-resource="org/springframework/integration/xml/config/test.xsl"/>
|
|
<si-xml:xslt-transformer id="xsltTransformerWithTemplatesAndResultTransformer"
|
|
input-channel="withTemplatesAndResultTransformerIn"
|
|
output-channel="output"
|
|
xsl-templates="templates"
|
|
result-transformer="resultTransformer"/>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="xpath-splitting">
|
|
<title>Splitting xml messages</title>
|
|
<para>
|
|
<classname>XPathMessageSplitter</classname> supports messages with either
|
|
<classname>String</classname> or <interfacename>Document</interfacename> payloads.
|
|
The splitter uses the provided XPath expression to split the payload into a number of
|
|
nodes. By default this will result in each <interfacename>Node</interfacename> instance
|
|
becoming the payload of a new message. Where it is preferred that each message be a Document
|
|
the <methodname>createDocuments</methodname> flag can be set. Where a <classname>String</classname> payload is passed
|
|
in the payload will be converted then split before being converted back to a number of String
|
|
messages. The XPath splitter implements <interfacename>MessageConsumer</interfacename> and should
|
|
therefore be configured in conjunction with an appropriate endpoint.
|
|
<programlisting language="xml"><![CDATA[<bean id="splittingEndpoint"
|
|
class="org.springframework.integration.endpoint.SubscribingConsumerEndpoint">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.splitter.XPathMessageSplitter">
|
|
<constructor-arg value="/order/items" />
|
|
<property name="documentBuilder" ref="customisedDocumentBuilder" />
|
|
<property name="outputChannel" ref="orderItemsChannel" />
|
|
</bean>
|
|
</constructor-arg>
|
|
<constructor-arg ref="orderChannel" />
|
|
</bean>]]></programlisting>
|
|
|
|
</para>
|
|
</section>
|
|
|
|
<section id="xpath-routing">
|
|
<title>Routing xml messages using XPath</title>
|
|
<para>
|
|
Two Router implementations based on XPath are provided <classname>XPathSingleChannelRouter</classname> and
|
|
<classname>XPathMultiChannelRouter</classname>. The implementations differ in respect to how many channels
|
|
any given message may be routed to, exactly one in the case of the single channel version
|
|
or zero or more in the case of the multichannel router. Both evaluate an XPath
|
|
expression against the xml payload of the message, supported payload types by default
|
|
are <interfacename>Node</interfacename>, <interfacename>Document</interfacename> and
|
|
<interfacename>String</interfacename>. For other payload types a custom implementation
|
|
of <interfacename>XmlPayloadConverter</interfacename> can be provided. The router
|
|
implementations use <interfacename>ChannelNameResolver</interfacename> to convert the
|
|
result(s) of the XPath expression to a channel name. By default a
|
|
<classname>BeanFactoryChannelName</classname> strategy will be used, this means that the string returned by the XPath
|
|
evaluation should correspond directly to the name of a channel. Where this is not the case
|
|
an alternative implementation of <interfacename>ChannelNameResolver</interfacename> can
|
|
be used. Where there is a simple mapping from Xpath result to channel name
|
|
the provided <classname>MapBasedChannelName</classname> can be used.
|
|
<programlisting language="xml"><![CDATA[<!-- Expects a channel for each value of order type to exist -->
|
|
<bean id="singleChannelRoutingEndpoint"
|
|
class="org.springframework.integration.endpoint.SubscribingConsumerEndpoint">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.router.XPathSingleChannelRouter">
|
|
<constructor-arg value="/order/@type" />
|
|
</bean>
|
|
</constructor-arg>
|
|
<constructor-arg ref="orderChannel" />
|
|
</bean>
|
|
|
|
|
|
<!-- Multi channel router which uses a map channel resolver to resolve the channel name
|
|
based on the XPath evaluation result Since the router is multi channel it may deliver
|
|
message to one or both of the configured channels -->
|
|
<bean id="multiChannelRoutingEndpoint"
|
|
class="org.springframework.integration.endpoint.SubscribingConsumerEndpoint">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.router.XPathMultiChannelRouter">
|
|
<constructor-arg value="/order/recipient" />
|
|
<property name="channelResolver">
|
|
<bean class="org.springframework.integration.channel.MapBasedChannelResolver">
|
|
<constructor-arg>
|
|
<map>
|
|
<entry key="accounts"
|
|
value-ref="accountConfirmationChannel" />
|
|
<entry key="humanResources"
|
|
value-ref="humanResourcesConfirmationChannel" />
|
|
</map>
|
|
</constructor-arg>
|
|
</bean>
|
|
</property>
|
|
</bean>
|
|
</constructor-arg>
|
|
<constructor-arg ref="orderChannel" />
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="xpath-selector">
|
|
<title>Selecting xml messages using XPath</title>
|
|
<para>
|
|
Two <interfacename>MessageSelector</interfacename> implementations are provided,
|
|
<classname>BooleanTestXPathMessageSelector</classname> and <classname>StringValueTestXPathMessageSelector</classname>.
|
|
<classname>BooleanTestXPathMessageSelector</classname> requires an XPathExpression which evaluates to a boolean,
|
|
for example <emphasis>boolean(/one/two)</emphasis> which will only select messages which have an element named
|
|
two which is a child of a root element named one. <classname>StringValueTestXPathMessageSelector</classname>
|
|
evaluates any XPath expression as a <classname>String</classname> and compares the result with the provided value.
|
|
</para>
|
|
|
|
|
|
<programlisting language="xml"><![CDATA[<!-- Interceptor which rejects messages that do not have a root element order -->
|
|
<bean id="orderSelectingInterceptor"
|
|
class="org.springframework.integration.channel.interceptor.MessageSelectingInterceptor">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.selector.BooleanTestXPathMessageSelector">
|
|
<constructor-arg value="boolean(/order)" />
|
|
</bean>
|
|
</constructor-arg>
|
|
</bean>
|
|
|
|
<!-- Interceptor which rejects messages that are not version one orders -->
|
|
<bean id="versionOneOrderSelectingInterceptor"
|
|
class="org.springframework.integration.channel.interceptor.MessageSelectingInterceptor">
|
|
<constructor-arg>
|
|
<bean class="org.springframework.integration.xml.selector.StringValueTestXPathMessageSelector">
|
|
<constructor-arg value="/order/@version" index="0"/>
|
|
<constructor-arg value="1" index="1"/>
|
|
</bean>
|
|
</constructor-arg>
|
|
</bean>]]></programlisting>
|
|
</section>
|
|
|
|
|
|
<section id="xpath-namespace-support">
|
|
<title>XPath components namespace support</title>
|
|
<para>All XPath based components have namespace support allowing them to be configured as instances of
|
|
<interfacename>MessageEndpoint</interfacename> with the exception of the XPath selectors which are not designed to act as
|
|
endpoints. Each component allows the XPath to either be referenced at the top level or configured via a nested
|
|
xpath-expression element. So the following configurations of an xpath-selector are all valid and represent the general
|
|
form of XPath namespace support. All forms of XPath expression result in the creation of an
|
|
<interfacename>XPathExpression</interfacename> using the Spring <classname>XPathExpressionFactory</classname>
|
|
<programlisting language="xml"><![CDATA[<si-xml:xpath-selector id="xpathRefSelector"
|
|
xpath-expression="refToXpathExpression"
|
|
evaluation-result-type="boolean" />
|
|
|
|
<si-xml:xpath-selector id="selectorWithNoNS" evaluation-result-type="boolean" >
|
|
<si-xml:xpath-expression expression="/name"/>
|
|
</si-xml:xpath-selector>
|
|
|
|
<si-xml:xpath-selector id="selectorWithOneNS" evaluation-result-type="boolean" >
|
|
<si-xml:xpath-expression expression="/ns1:name"
|
|
ns-prefix="ns1" ns-uri="www.example.org" />
|
|
</si-xml:xpath-selector>
|
|
|
|
<si-xml:xpath-selector id="selectorWithTwoNS" evaluation-result-type="boolean" >
|
|
<si-xml:xpath-expression expression="/ns1:name/ns2:type">
|
|
<map>
|
|
<entry key="ns1" value="www.example.org/one" />
|
|
<entry key="ns2" value="www.example.org/two" />
|
|
</map>
|
|
</si-xml:xpath-expression>
|
|
</si-xml:xpath-selector>
|
|
|
|
<si-xml:xpath-selector id="selectorWithNamespaceMapRef" evaluation-result-type="boolean" >
|
|
<si-xml:xpath-expression expression="/ns1:name/ns2:type"
|
|
namespace-map="defaultNamespaces"/>
|
|
</si-xml:xpath-selector>
|
|
|
|
<util:map id="defaultNamespaces">
|
|
<util:entry key="ns1" value="www.example.org/one" />
|
|
<util:entry key="ns2" value="www.example.org/two" />
|
|
</util:map>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
XPath splitter namespace support allows the creation of a MessageEndpoint with an input channel and output channel.
|
|
<programlisting language="xml"><![CDATA[<!-- Split the order into items creating a new message for each item node -->
|
|
<si-xml:xpath-splitter id="orderItemSplitter"
|
|
input-channel="orderChannel"
|
|
output-channel="orderItemsChannel">
|
|
<si-xml:xpath-expression expression="/order/items"/>
|
|
</si-xml:xpath-selector>
|
|
|
|
<!-- Split the order into items creating a new document for each item-->
|
|
<si-xml:xpath-splitter id="orderItemDocumentSplitter"
|
|
input-channel="orderChannel"
|
|
output-channel="orderItemsChannel"
|
|
create-documents="true">
|
|
<si-xml:xpath-expression expression="/order/items"/>
|
|
<si:poller>
|
|
<si:interval-trigger interval="2000"/>
|
|
</si:poller>
|
|
</si-xml:xpath-selector>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
XPath router namespace support allows for the creation of a MessageEndpoint with an input channel but no output channel
|
|
since the output channel is determined dynamically. The multi-channel attribute causes the creation of a multi channel router capable of
|
|
routing a single message to many channels when true and a single channel router when false.
|
|
<programlisting language="xml"><![CDATA[<!-- route the message according to exactly one order type channel -->
|
|
<si-xml:xpath-router id="orderTypeRouter" input-channel="orderChannel" multi-channel="false">
|
|
<si-xml:xpath-expression expression="/order/type"/>
|
|
</si-xml:xpath-selector>
|
|
|
|
<!-- route the order to all responders-->
|
|
<si-xml:xpath-router id="responderRouter" input-channel="orderChannel" multi-channel="true">
|
|
<si-xml:xpath-expression expression="/request/responders"/>
|
|
<si:poller>
|
|
<si:interval-trigger interval="2000"/>
|
|
</si:poller>
|
|
</si-xml:xpath-selector>]]></programlisting>
|
|
</para>
|
|
|
|
|
|
</section>
|
|
|
|
</chapter> |