diff --git a/docs/src/reference/docbook/xml.xml b/docs/src/reference/docbook/xml.xml index b76b34f84c..3be8fa93a2 100644 --- a/docs/src/reference/docbook/xml.xml +++ b/docs/src/reference/docbook/xml.xml @@ -485,20 +485,61 @@ ]]> + + XPath router namespace support allows for the creation of a Message Endpoint 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. - - + since the output channel(s) is determined dynamically. + - - - - + +]]> + + + + Internally XPath expression will be evaluated as NODESET type and converted to a + List<String> representing channel names. Typically such list will contain a single channel name. + However, based on the result of an XPath Expression XPath router can also take on the characteristics of the Recipient List Router + if XPath Expression returns more then one value, thus resulting in the List<String> containing more + then one channel name. In that case Message will be sent to all channels in the list. + So assuming that the xml file passed to the router configured below contains many responder sub-elements representing channel names, + the message will be sent to all of those channels. + + + - -]]> + +]]> + + If the returned values do not represent the channel names additional mapping could be specified. For example if + the /request/responders expression results in two values responderA and responderB but + you don't want to couple the responder names to channel names you may provide additional mapping as such: + + + + + + +]]> + + + + As we already said the default evaluation type for XPath expressions is NODESET which is converted + to a List<String> of channel names, thus handling single channel scenarios as well as multiple. + However certain XPath expressions may evaluate as String type from the very + beginning (e.g., 'name(./node())' - which will return the name of the root node) thus resulting in + the exception if default evaluation type (NODESET) is used. + For these scenarious you may use evaluate-as-string attribute which will allow you to manage the + evaluation type. It is FALSE by default, however if set to TRUE, the String evaluation type will be used. + For example if we want to route based on the name of the root node we can have use the following configuration: + + + + +]]> diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathRouterParser.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathRouterParser.java index 33a09013e3..caeada5fd7 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathRouterParser.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathRouterParser.java @@ -47,7 +47,7 @@ public class XPathRouterParser extends AbstractRouterParser { element.getNamespaceURI(), "xpath-expression"); Assert.isTrue(xPathExpressionNodes.getLength() <= 1, "At most one xpath-expression child may be specified."); String xPathExpressionRef = element.getAttribute("xpath-expression-ref"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(xpathRouterBuilder, element, "evaluate-as-node"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(xpathRouterBuilder, element, "evaluate-as-string"); boolean xPathExpressionChildPresent = (xPathExpressionNodes.getLength() == 1); boolean xPathReferencePresent = StringUtils.hasText(xPathExpressionRef); Assert.isTrue(xPathExpressionChildPresent ^ xPathReferencePresent, diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java index 5c3a7ea09a..3814aac8b0 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java @@ -47,7 +47,7 @@ public class XPathRouter extends AbstractMessageRouter { private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); - private volatile boolean evaluateAsNode = true; + private volatile boolean evaluateAsString = false; /** * Create a router that uses an XPath expression. The expression may @@ -97,8 +97,8 @@ public class XPathRouter extends AbstractMessageRouter { this.xPathExpression = expression; } - public void setEvaluateAsNode(boolean evaluateAsNode) { - this.evaluateAsNode = evaluateAsNode; + public void setEvaluateAsString(boolean evaluateAsString) { + this.evaluateAsString = evaluateAsString; } /** @@ -117,11 +117,11 @@ public class XPathRouter extends AbstractMessageRouter { @SuppressWarnings("unchecked") protected List getChannelIdentifiers(Message message) { Node node = this.converter.convertToNode(message.getPayload()); - if (this.evaluateAsNode){ - return this.xPathExpression.evaluate(node, this.nodeMapper); + if (this.evaluateAsString){ + return Collections.singletonList((Object)this.xPathExpression.evaluateAsString(node)); } else { - return Collections.singletonList((Object)this.xPathExpression.evaluateAsString(node)); + return this.xPathExpression.evaluate(node, this.nodeMapper); } } diff --git a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd index 6dc663f50a..c4c66153c5 100644 --- a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd +++ b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd @@ -369,11 +369,11 @@ - + of channel names, thus handling single channel scenarios as well as multiple. + to a List of channel names, thus handling single channel scenarios as well as multiple. However certain XPath expressions may evaluate as String type from the very beginning (e.g., 'name(./node())' - which will return the name of the root node) thus resulting in the exception if default evaluation type (NODESET) is used. This flag will allow you to manage the diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml index 6d7c19afb7..cd5f805613 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml @@ -12,7 +12,7 @@ - + diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XPathRouterTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XPathRouterTests.java index 3ee46b15a7..e2de69e94b 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XPathRouterTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XPathRouterTests.java @@ -52,7 +52,7 @@ public class XPathRouterTests { Document doc = XmlTestUtil.getDocumentForString(""); XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/@type"); XPathRouter router = new XPathRouter(expression); - router.setEvaluateAsNode(false); + router.setEvaluateAsString(true); Object[] channelNames = router.getChannelIdentifiers(new GenericMessage(doc)).toArray(); assertEquals("Wrong number of channels returned", 1, channelNames.length); assertEquals("Wrong channel name", "one", channelNames[0]); @@ -64,7 +64,7 @@ public class XPathRouterTests { Document doc = XmlTestUtil.getDocumentForString("olegbang"); XPathExpression expression = XPathExpressionFactory.createXPathExpression("name(./node())"); XPathRouter router = new XPathRouter(expression); - router.setEvaluateAsNode(false); + router.setEvaluateAsString(true); Object[] channelNames = router.getChannelIdentifiers(new GenericMessage(doc)).toArray(); assertEquals("Wrong number of channels returned", 1, channelNames.length); assertEquals("Wrong channel name", "doc", channelNames[0]); @@ -95,7 +95,7 @@ public class XPathRouterTests { public void multipleNodeValuesAsString() throws Exception { XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/book"); XPathRouter router = new XPathRouter(expression); - router.setEvaluateAsNode(false); + router.setEvaluateAsString(true); Object[] channelNames = router.getChannelIdentifiers(new GenericMessage("bOnebTwo")).toArray(); assertEquals("Wrong number of channels returned", 1, channelNames.length); assertEquals("Wrong channel name", "bOne", channelNames[0]);