spring-integration icon indicating copy to clipboard operation
spring-integration copied to clipboard

XPath Router. Conditional routing based on the value of the xpath expression. [INT-2808]

Open spring-operator opened this issue 13 years ago • 9 comments

Janis Kazakovs opened INT-2808 and commented

As a developer I would like to be able to configure XPath Router to do conditional routing based on the XPath value.

For example, when having a message

<passener>
  <age>2</age>
</passenger>

a router should be able to route the message to one of the configured channels based on the evaluated expression, e.g.

<xpath-router id="passengerRouter" input-channel="passengerChannel">
    <recipient channel="infantChannel" expression="/passenger/age le 1"/>
    <recipient channel="adultChannel" expression="/passenger/age gt 12"/>
</xpath-router>

Reference URL: http://forum.springsource.org/showthread.php?131607-EAI-Content-Based-Filter-with-Spring-Integration&p=429293#post429293

1 votes, 4 watchers

spring-operator avatar Nov 04 '12 03:11 spring-operator

Oleg Zhurakousky commented

I would personally rephrase this issue as I believe the requirement is more general and goes beyond the XPath (even though it was originated from the XPath related forum post). The main point of this requirement is to be able to use more complex evaluation of the routing result during its mapping to a channel. Today mapping is simply done based on 'equals' thus eliminating the possibility of mapping result based on let's say its range (e.g., from 1 to 20 go to channel A)

spring-operator avatar Nov 04 '12 07:11 spring-operator

Janis Kazakovs commented

Does make sense to me. Frankly, I do no have prior knowledge of Spring Integration. The above case was the first one I was trying to implement.

I know that Apache Camel uses the notion of Predicate, which can be integrated into the Message Filter of Content Based Filter for various data format. I do not know the architecture of the Spring Integration, but it makes sense to abstract the notion of predicate, otherwise you end up building XPath, JSON, bean, map and etc. content based routers.

Also, looking at the example from the post with the recipient-list-router (i.e. ``` <int:recipient channel="infant" selector-expression="headers['passengerAge'] le 1" />

```selector-expression="/passenger/age le 1" />
```), rather then using content enricher to store a temporary variable. This seems to me unnecessary step or a workaround that a user of a framework should make in order to implement a uses case. Instead it should be supported by framework itself.

spring-operator avatar Nov 04 '12 09:11 spring-operator

Mark Fisher commented

One advantage even in the workaround is that the XPath expression itself is only evaluated ONE time. Ideally we would like to preserve that advantage while also removing the need for exposing any temporary variable to the end-user (as the workaround does unfortunately).

Also, as you have pointed out in the forum, we should provide a way to do this on the simple <xpath-router> itself, but I do like the idea of also having an XPath version of recipient-list-router where multiple XPath expressions may be evaluated instead-of/in-addition-to any SpEL expressions as done on the "simple" (non-xpath) recipient-list-router.

spring-operator avatar Nov 05 '12 06:11 spring-operator

Mark Fisher commented

Just to add... if we go with Oleg's suggestion of adding "expression" (as an alternative to simple "value" matching) on the <mapping> sub-elements, then this type of behavior could also be reused for any router. For the XPath case, it would satisfy the 2 points I made above (not requiring multiple XPath expression evaluations AND not exposing any new variables/headers to the end-user directly). For example:

<xpath-router input-channel="passengers" expression="/passenger/age">
   <mapping expression="#result le 1" channel="infants"/>
   <mapping expression="#result gt 12" channel="adults"/>
</xpath-router>

spring-operator avatar Nov 05 '12 09:11 spring-operator

Janis Kazakovs commented

I will try to complicate the case. What if in order to evaluate a bolean-valued function I need to use more then one xpath expression. For example, the age of an infant may vary per country.

<passenger>
	<age/>
	<country/>
</passenger>

As a result, desired expression could look as follows:

(/passenger/age le 1 and /passeger/country = NL) or (/passenger/age le 2 and /passeger/country = UK)
```. In this case, having a single xpath expression on xpath-router declaration, the result of which is used later on route mapping, may not suffice. 

spring-operator avatar Nov 05 '12 13:11 spring-operator

Oleg Zhurakousky commented

I don't think you are complicating it at all. The only thing that has became more complex is an expression itself which still returns a boolean value. With SpEL (Spring Expression Language) if expression were to get to complex you may want to delegate to a bean (e.g., expression="@myBean.process(#result)"), thus making expression itself simple while what it does anything but.

spring-operator avatar Nov 05 '12 15:11 spring-operator

Artem Bilan commented

Hi, all! +1 to 'expression' attribute as boolean evaluation with '#result' as root element. With mutually exclusive to 'value' attribute. And enhanced with BeanFactoryResolver too...

spring-operator avatar Nov 05 '12 23:11 spring-operator

Artem Bilan commented

After introduction #xpath() SpEL function (https://jira.springsource.org/browse/INT-3140) a nested XPath 'Predicate' will be achieved with new expression attribute for router's mapping.

spring-operator avatar Sep 11 '13 03:09 spring-operator

Artem Bilan commented

The initial commit: https://github.com/artembilan/spring-integration/commit/400461b1978413978207c179ff26c25e065cca19

spring-operator avatar Feb 12 '14 11:02 spring-operator

According to the #xpath() SpEL function we don't need anything else:

<int:recipient-list-router input-channel="xpathRecipientsInput">
    <int:recipient channel="channelA" selector-expression="#xpath(payload, '/passenger/age/text() &lt;= 2', 'boolean')"/>
    <int:recipient channel="channelB" selector-expression="#xpath(payload, '/passenger/age/text() > 12', 'boolean')"/>
</int:recipient-list-router>

artembilan avatar Oct 07 '25 19:10 artembilan