XPath has been edited by Claus Ibsen (Mar 17, 2009).

(View changes)

Content:

XPath

Camel supports XPath to allow an _expression_ or Predicate to be used in the DSL or Xml Configuration. For example you could use XPath to create an Predicate in a Message Filter or as an _expression_ for a Recipient List.

from("queue:foo").
  filter().xpath("//foo")).
  to("queue:bar")

from("queue:foo").
  choice().xpath("//foo")).to("queue:bar").
  otherwise().to("queue:others");

Namespaces

In 1.3 onwards you can easily use namespaces with XPath expressions using the Namespaces helper class.

Namespaces ns = new Namespaces("c", "http://acme.com/cheese");

from("direct:start").filter().
        xpath("/c:pers...@name='James']", ns).
        to("mock:result");

Variables

Variables in XPath is defined in different namespaces. The default namespace is http://camel.apache.org/schema/spring.

Namespace URI Local part Type Description
http://camel.apache.org/xml/in/ in Message the exchange.in message
http://camel.apache.org/xml/out/ out Message the exchange.out message
http://camel.apache.org/xml/variables/environment-variables env Object OS environment variables
http://camel.apache.org/xml/variables/system-properties system Object Java System properties
http://camel.apache.org/xml/variables/exchange-property   Object the exchange property

Camel will resolve variables according to either:

  • namespace given
  • no namespace given

Namespace given

If the namespace is given then Camel is instructed exactly what to return. However when resolving either in or out Camel will try to resolve a header with the given local part first, and return it. If the local part has the value body then the body is returned instead.

No namespace given

If there is no namespace given then Camel resolves only based on the local part. Camel will try to resolve a variable in the following steps:

  • from variables that has been set using the variable(name, value) fluent builder
  • from message.in.header if there is a header with the given key
  • from exchange.properties if there is a property with the given key

Functions

Camel adds the following XPath functions that can be used to access the exchange:

Function Argument Type Description
in:body none Object Will return the in message body.
in:header the header name Object Will return the in message header.
out:body none Object Will return the out message body.
out:header the header name Object Will return the out message header.

Here's an example showing some of these functions in use.

from("direct:start").choice()
  .when().xpath("in:header('foo') = 'bar'").to("mock:x")
  .when().xpath("in:body() = '<two/>'").to("mock:y")
  .otherwise().to("mock:z");

Using XML configuration

If you prefer to configure your routes in your Spring XML file then you can use XPath expressions as follows

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:foo="http://example.com/person"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

  <camelContext id="camel" xmlns="http://activemq.apache.org/camel/schema/spring">
    <route>
      <from uri="activemq:MyQueue"/>
      <filter>
        <xpath>/foo:pers...@name='James']</xpath>
        <to uri="mqseries:SomeOtherQueue"/>
      </filter>
    </route>
  </camelContext>
</beans>

Notice how we can reuse the namespace prefixes, foo in this case, in the XPath _expression_ for easier namespace based XPath expressions!

Setting result type

The XPath _expression_ will return a result type using native XML objects such as org.w3c.dom.NodeList. But many times you want a result type to be a String. To do this you have to instruct the XPath which result type to use.

In Java DSL:

xpath("/foo:person/@id", String.class)

In Spring DSL you use the resultType attribute to provide a fully qualified classname:

<xpath resultType="java.lang.String">/foo:person/@id</xpath>

Examples

Here is a simple example using an XPath _expression_ as a predicate in a Message Filter

from("direct:start").
        filter().xpath("/pers...@name='James']").
        to("mock:result");

If you have a standard set of namespaces you wish to work with and wish to share them across many different XPath expressions you can use the NamespaceBuilder as shown in this example

// lets define the namespaces we'll need in our filters
Namespaces ns = new Namespaces("c", "http://acme.com/cheese")
        .add("xsd", "http://www.w3.org/2001/XMLSchema");

// now lets create an xpath based Message Filter
from("direct:start").
        filter(ns.xpath("/c:pers...@name='James']")).
        to("mock:result");

In this sample we have a choice construct. The first choice evaulates if the message has a header key type that has the value Camel.
The 2nd choice evaluates if the message body has a name tag <name> which values is Kong.
If neither is true the message is routed in the otherwise block:

from("direct:in").choice()
    // using $headerName is special notation in Camel to get the header key
    .when().xpath("$type = 'Camel'")
        .to("mock:camel")
    // here we test for the body name tag
    .when().xpath("//name = 'Kong'")
        .to("mock:donkey")
    .otherwise()
        .to("mock:other")
    .end();

And the spring XML equivalent of the route:

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="direct:in"/>
        <choice>
            <when>
                <xpath>$type = 'Camel'</xpath>
                <to uri="mock:camel"/>
            </when>
            <when>
                <xpath>//name = 'Kong'</xpath>
                <to uri="mock:donkey"/>
            </when>
            <otherwise>
                <to uri="mock:other"/>
            </otherwise>
        </choice>
    </route>
</camelContext>

XPath injection

You can use Bean Integration to invoke a method on a bean and use various languages such as XPath to extract a value from the message and bind it to a method parameter.

The default XPath annotation has SOAP and XML namespaces available. If you want to use your own namespace URIs in an XPath _expression_ you can use your own copy of the XPath annotation to create whatever namespace prefixes you want to use.

i.e. cut and paste the XPath annotation code to your own project in a different package and/or annotation name then add whatever namespace prefix/uris you want in scope when you use your annotation on a method parameter. Then when you use your annotation on a method parameter all the namespaces you want will be available for use in your XPath _expression_.

For example

public class Foo {
	
    @MessageDriven(uri = "activemq:my.queue")
    public void doSomething(@Path("/foo/bar/text()") String correlationID, @Body String body) {
		// process the inbound message here
    }
}

Dependencies

The XPath language is part of camel-core.

Reply via email to