Some of our Mule ESB applications make use of content-based routing when processing a message. To implement this in Mule we use a filtering-router with a jaxen-filter. The most simple example looks like this:
... <outbound> <filtering-router> <vm:outbound-endpoint ref="out-queue" /> <xm:jaxen-filter pattern="//firstname" expectedValue="Pascal"/> </filtering-router> </outbound> ...
You can also use a XPath function in your jaxen-filter like this (if you want to check a certain element is in an XML message regardless the value of the element):
... <outbound> <filtering-router> <vm:outbound-endpoint ref="out-queue" /> <xm:jaxen-filter pattern="local-name(//Relations)" expectedValue="Relations"/> </filtering-router> </outbound> ...
The problem starts if you have to declare namespaces in your XPath expression. You can use namespaces in your XPath expression by declaring a namespace-manager in your mule-config, like this:
... <xm:namespace-manager includeConfigNamespaces="false"> <xm:namespace prefix="ns1" uri="http://www.redstream.nl/relations/v1_1"/> </xm:namespace-manager> ... <outbound> <filtering-router> <vm:outbound-endpoint ref="out-queue" /> <xm:jaxen-filter pattern="local-name(//ns1:Relations)" expectedValue="Relations"/> </filtering-router> </outbound> ...
But if you run this example you will get the following exception:
org.jaxen.UnresolvableException: No Such Function {http://www.mulesource.org/schema/mule/core/2.2}:local-name
at org.jaxen.SimpleFunctionContext.getFunction(SimpleFunctionContext.java:127)
at org.jaxen.ContextSupport.getFunction(ContextSupport.java:242)
at org.jaxen.Context.getFunction(Context.java:216)
at org.jaxen.expr.DefaultFunctionCallExpr.evaluate(DefaultFunctionCallExpr.java:172)
at org.jaxen.expr.DefaultXPathExpr.asList(DefaultXPathExpr.java:102)
at org.jaxen.BaseXPath.selectNodesForContext(BaseXPath.java:674)
at org.jaxen.BaseXPath.selectSingleNodeForContext(BaseXPath.java:698)
at org.jaxen.BaseXPath.stringValueOf(BaseXPath.java:279)
at org.jaxen.BaseXPath.valueOf(BaseXPath.java:254)
at org.mule.module.xml.filters.JaxenFilter.accept(JaxenFilter.java:184)
at org.mule.module.xml.filters.JaxenFilter.accept(JaxenFilter.java:118)
at org.mule.routing.outbound.FilteringOutboundRouter.isMatch(FilteringOutboundRouter.java:119)
at org.mule.routing.outbound.DefaultOutboundRouterCollection. route(DefaultOutboundRouterCollection.java:72)
at org.mule.service.AbstractService.dispatchToOutboundRouter(AbstractService.java:867)
at org.mule.model.seda.SedaService.dispatchToOutboundRouter(SedaService.java:561)
at org.mule.model.seda.SedaService$ComponentStageWorker.doRun(SedaService.java:583)
at org.mule.work.AbstractMuleEventWork.run(AbstractMuleEventWork.java:41)
at org.mule.work.WorkerContext.run(WorkerContext.java:310)
at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor. runWorker(ThreadPoolExecutor.java:1061)
at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker. run(ThreadPoolExecutor.java:575)
at java.lang.Thread.run(Thread.java:637)
Although it is logged as warning it makes the filter to return no matching values and the XML message is discarded (although I use the jaxen-filter here this also goes for the jxpath-filter and the xpath-filter).
The solution for this is quite simple: just give the XPath function a unique prefix (one that is not mapped to a namespace). So if you modify the last example and make the jaxen-filter like:
<xm:jaxen-filter pattern="fn:local-name(//ns1:Relations)" expectedValue="Relations"/>
or
<xm:jaxen-filter pattern="abc:local-name(//ns1:Relations)" expectedValue="Relations"/>
it will work.
You just have to make sure the prefix you use isn’t used in the declared namespace-manager because then the function is looked up (and not found) in the supplied XML document.