Routing XML Messages with XPath

Similar to SpEL-based routers, Spring Integration provides support for routing messages based on XPath expressions, which lets you create a message endpoint with an input channel but no output channel. Instead, one or more output channels are determined dynamically. The following example shows how to create such a router:

<int-xml:xpath-router id="orderTypeRouter" input-channel="orderChannel">
    <int-xml:xpath-expression expression="/order/type"/>
</int-xml:xpath-router>
For an overview of attributes that are common among Routers, see Common Router Parameters.

Internally, XPath expressions are evaluated as type NODESET and converted to a List<String> that represents channel names. Typically, such a list contains a single channel name. However, based on the results of an XPath Expression, the XPath router can also take on the characteristics of a recipient list router if the XPath expression returns more than one value. In that case, the List<String> contains more than one channel name. Consequently, messages are sent to all the channels in the list.

Thus, assuming that the XML file passed to the following router configuration contains many responder sub-elements that represent channel names, the message is sent to all of those channels:

<!-- route the order to all responders-->
<int-xml:xpath-router id="responderRouter" input-channel="orderChannel">
    <int-xml:xpath-expression expression="/request/responders"/>
</int-xml:xpath-router>

If the returned values do not represent the channel names directly, you can specify additional mapping parameters to map those returned values to actual channel names. For example if the /request/responders expression results in two values (responderA and responderB), but you do not want to couple the responder names to channel names, you can provide additional mapping configuration, such as the following:

<!-- route the order to all responders-->
<int-xml:xpath-router id="responderRouter" input-channel="orderChannel">
    <int-xml:xpath-expression expression="/request/responders"/>
    <int-xml:mapping value="responderA" channel="channelA"/>
    <int-xml:mapping value="responderB" channel="channelB"/>
</int-xml:xpath-router>

As already mentioned, the default evaluation type for XPath expressions is NODESET, which is converted to a List<String> of channel names, which handles single channel scenarios as well as multiple channel scenarios.

Nonetheless, certain XPath expressions may evaluate as type String from the very beginning. Consider, for example, the following XPath Expression:

name(./node())

This expression returns the name of the root node. If the default evaluation type NODESET is being used, it results in an exception.

For these scenarios, you can use the evaluate-as-string attribute, which lets you manage the evaluation type. It is FALSE by default. However, if you set it to TRUE, the String evaluation type is used.

XPath 1.0 specifies 4 data types:

  • Node-sets

  • Strings

  • Number

  • Boolean

When the XPath Router evaluates expressions by using the optional evaluate-as-string attribute, the return value is determined by the string() function, as defined in the XPath specification. This means that, if the expression selects multiple nodes, it return the string value of the first node.

For further information, see:

For example, if we want to route based on the name of the root node, we can use the following configuration:

<int-xml:xpath-router id="xpathRouterAsString"
        input-channel="xpathStringChannel"
        evaluate-as-string="true">
    <int-xml:xpath-expression expression="name(./node())"/>
</int-xml:xpath-router>

XML Payload Converter

For XPath Routers, you can also specify the Converter to use when converting payloads prior to XPath evaluation. As such, the XPath Router supports custom implementations of the XmlPayloadConverter strategy, and when configuring an xpath-router element in XML, a reference to such an implementation may be provided via the converter attribute.

If this reference is not explicitly provided, the DefaultXmlPayloadConverter is used. It should be sufficient in most cases, since it can convert from Node, Document, Source, File, and String typed payloads. If you need to extend beyond the capabilities of that default implementation, then an upstream Transformer is generally a better option in most cases, rather than providing a reference to a custom implementation of this strategy here.