LibraryPrintFeedback

Routing Expression and Predicate Languages

Version 7.0

July 2012
Trademark Disclaimer
Third Party Acknowledgements

Updated: 22 Aug 2012

Table of Contents

1. Introduction
Overview of the Languages
How to Invoke an Expression Language
2. Constant
3. EL
4. The File Language
When to Use the File Language
File Variables
Examples
5. Groovy
6. Header
7. JavaScript
8. JoSQL
9. JXPath
10. MVEL
11. The Object-Graph Navigation Language(OGNL)
12. PHP
13. Property
14. Python
15. Ref
16. Ruby
17. The Simple Language
Java DSL
XML DSL
Expressions
Predicates
Variable Reference
Operator Reference
18. SpEL
19. The XPath Language
Java DSL
XML DSL
XPath Injection
XPath Builder
Expressions
Predicates
Using Variables and Functions
Variable Namespaces
Function Reference
20. XQuery

List of Tables

1.1. Expression and Predicate Languages
3.1. EL variables
4.1. Variables for the File Language
5.1. Groovy attributes
7.1. JavaScript attributes
8.1. SQL variables
9.1. JXPath variables
10.1. MVEL variables
11.1. OGNL variables
12.1. PHP attributes
14.1. Python attributes
16.1. Ruby attributes
17.1. Variables for the Simple Language
17.2. Binary Operators for the Simple Language
17.3. Unary Operators for the Simple Language
17.4. Conjunctions for Simple Language Predicates
18.1. SpEL variables
19.1. Predefined Namespaces for @XPath
19.2. Operators for the XPath Language
19.3. XPath Variable Namespaces
19.4. XPath Custom Functions
20.1. XQuery variables

List of Examples

3.1. Adding the camel-juel dependency
3.2. Routes using EL
5.1. Adding the camel-script dependency
5.2. Routes using Groovy
7.1. Adding the camel-script dependency
7.2. Route using JavaScript
8.1. Adding the camel-josql dependency
8.2. Route using JoSQL
9.1. Adding the camel-jxpath dependency
9.2. Routes using JXPath
10.1. Adding the camel-mvel dependency
10.2. Route using MVEL
11.1. Adding the camel-ognl dependency
11.2. Route using OGNL
12.1. Adding the camel-script dependency
12.2. Route using PHP
14.1. Adding the camel-script dependency
14.2. Route using Python
16.1. Adding the camel-script dependency
16.2. Route using Ruby
18.1. Adding the camel-spring dependency
20.1. Adding the camel-saxon dependency
20.2. Route using XQuery

As shown in Table 1.1, there are several different syntaxes for invoking an expression language, depending on the context in which it is used. You can invoke an expression language:

Language annotations are used in the context of bean integration (see Bean Integration in Implementing Enterprise Integration Patterns). The annotations provide a convenient way of extracting information from a message or header and then injecting the extracted data into a bean's method parameters.

For example, consider the bean, myBeanProc, which is invoked as a predicate of the filter() EIP. If the bean's checkCredentials method returns true, the message is allowed to proceed; but if the method returns false, the message is blocked by the filter. The filter pattern is implemented as follows:

// Java
MyBeanProcessor myBeanProc = new MyBeanProcessor();

from("SourceURL")
  .filter().method(myBeanProc, "checkCredentials")
  .to("TargetURL");

The implementation of the MyBeanProcessor class exploits the @XPath annotation to extract the username and password from the underlying XML message, as follows:

// Java
import org.apache.camel.language.XPath;

public class MyBeanProcessor {
    boolean void checkCredentials(
        @XPath("/credentials/username/text()") String user,
        @XPath("/credentials/password/text()") String pass
    ) {
        // Check the user/pass credentials...
        ...
    }
}

The @XPath annotation is placed just before the parameter into which it gets injected. Notice how the XPath expression explicitly selects the text node, by appending /text() to the path, which ensures that just the content of the element is selected, not the enclosing tags.

There are several URI options that you can set on a File or FTP consumer endpoint, which take a file language expression as their value. For example, in a File consumer endpoint URI you can set the fileName, move, preMove, moveFailed, and sortBy options using a file expression.

In a File consumer endpoint, the fileName option acts as a filter, determining which file will actually be read from the starting directory. If a plain text string is specified (for example, fileName=report.txt), the File consumer reads the same file each time it is updated. You can make this option more dynamic, however, by specifying a simple expression. For example, you could use a counter bean to select a different file each time the File consumer polls the starting directory, as follows:

file://target/filelanguage/bean/?fileName=${bean:counter.next}.txt&delete=true

Where the ${bean:counter.next} expression invokes the next() method on the bean registered under the ID, counter.

The move option is used to move files to a backup location after then have been read by a File consumer endpoint. For example, the following endpoint moves files to a backup directory, after they have been processed:

file://target/filelanguage/?move=backup/${date:now:yyyyMMdd}/${file:name.noext}.bak&recursive=false

Where the ${file:name.noext}.bak expression modifies the original file name, replacing the file extension with .bak.

You can use the sortBy option to specify the order in which file should be processed. For example, to process files according to the alphabetical order of their file name, you could use the following File consumer endpoint:

file://target/filelanguage/?sortBy=file:name

To process file according to the order in which they were last modified, you could use the following File consumer endpoint:

file://target/filelanguage/?sortBy=file:modified

You can reverse the order by adding the reverse: prefix—for example:

file://target/filelanguage/?sortBy=reverse:file:modified

The JXPath language enables you to invoke Java beans using the Apache Commons JXPath language. The JXPath language has a similar syntax to XPath, but instead of selecting element or attribute nodes from an XML document, it invokes methods on an object graph of Java beans. If one of the bean attributes returns an XML document (a DOM/JDOM instance), however, the remaining portion of the path is interpreted as an XPath expression and is used to extract an XML node from the document. In other words, the JXPath language provides a hybrid of object graph navigation and XML node selection.

MVEL (http://mvel.codehaus.org/) is a Java-based dynamic language that is similar to OGNL, but is reported to be much faster. The MVEL support is in the camel-mvel module.

OGNL (http://www.opensymphony.com/ognl/) is an expression language for getting and setting properties of Java objects. You use the same expression for both getting and setting the value of a property. The OGNL support is in the camel-ognl module.

The Ref expression language is really just a way to look up a custom Expression from the Registry. This is particular convenient to use in the XML DSL.

The Ref language is part of camel-core.

The simple language provides various elementary expressions that return different parts of a message exchange. For example, the expression, simple("${header.timeOfDay}"), would return the contents of a header called timeOfDay from the incoming message.

[Note]Note

Since Fuse Mediation Router 2.9, you must always use the placeholder syntax, ${Expression}, to return a variable value. It is never permissible to omit the enclosing tokens (${ and }).

As well as providing variables that access all of the different parts of an exchange (see Table 17.1), the simple language also provides special variables for formatting dates, date:command:pattern, and for calling bean methods, bean:beanRef. For example, you can use the date and the bean variables as follows:

simple("Todays date is ${date:now:yyyyMMdd}")
simple("The order type is ${bean:orderService?method=getOrderType}")

The Object Graph Navigation Language (OGNL) is a notation for invoking bean methods in a chain-like fashion. If a message body contains a Java bean, you can easily access its bean properties using OGNL notation. For example, if the message body is a Java object with a getAddress() accessor, you can access the Address object and the Address object's properties as follows:

simple("${body.address}")
simple("${body.address.street}")
simple("${body.address.zip}")
simple("${body.address.city}")

Where the notation, ${body.address.street}, is shorthand for ${body.getAddress.getStreet}.

You can also test various parts of an exchange (headers, message body, and so on) using simple predicates. Simple predicates have the following general syntax:

${LHSVariable} Op RHSValue

Where the variable on the left hand side, LHSVariable, is one of the variables shown in Table 17.1 and the value on the right hand side, RHSValue, is one of the following:

  • Another variable, ${RHSVariable}.

  • A string literal, enclosed in single quotes, ' '.

  • A numeric constant, enclosed in single quotes, ' '.

  • The null object, null.

The simple language always attempts to convert the RHS value to the type of the LHS value.

Table 17.1 shows all of the variables supported by the simple language.

Table 17.1. Variables for the Simple Language

VariableTypeDescription
exchangeIdStringThe exchange's ID value.
idStringThe In message ID value.
body Object

The In message body. Supports OGNL expressions.

in.bodyObjectThe In message body. Supports OGNL expressions.
out.body Object

The Out message body.

bodyAs(Type)TypeThe In message body, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: byte[], String, Integer, and Long. The converted body can be null.
mandatoryBodyAs(Type)TypeThe In message body, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: byte[], String, Integer, and Long. The converted body is expected to be non-null.
header.HeaderNameObject

The In message's HeaderName header. Supports OGNL expressions.

headers.HeaderNameObjectThe In message's HeaderName header.
in.header.HeaderNameObjectThe In message's HeaderName header. Supports OGNL expressions.
in.headers.HeaderNameObjectThe In message's HeaderName header. Supports OGNL expressions.
out.header.HeaderName Object

The Out message's HeaderName header.

out.headers.HeaderNameObjectThe Out message's HeaderName header.
headerAs(Key,Type)TypeThe Key header, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: byte[], String, Integer, and Long. The converted value can be null.
headersMapAll of the In headers (as a java.util.Map type).
in.headersMapAll of the In headers (as a java.util.Map type).
property.PropertyName Object

The PropertyName property on the exchange.

sys.SysPropertyNameStringThe SysPropertyName Java system property.
sysenv.SysEnvVarStringThe SysEnvVar system environment variable.
exceptionStringEither the exception object from Exchange.getException() or, if this value is null, the caught exception from the Exchange.EXCEPTION_CAUGHT property; otherwise null. Supports OGNL expressions.
exception.messageStringIf an exception is set on the exchange, returns the value of Exception.getMessage(); otherwise, returns null.
exception.stacktraceStringIf an exception is set on the exchange, returns the value of Exception.getStackTrace(); otherwise, returns null. Note: The simple language first tries to retrieve an exception from Exchange.getException(). If that property is not set, it checks for a caught exception, by calling Exchange.getProperty(Exchange.CAUGHT_EXCEPTION).
date:command:patternStringA date formatted using a java.text.SimpleDateFormat pattern. The following commands are supported: now, for the current date and time; header.HeaderName, or in.header.HeaderName to use a java.util.Date object in the HeaderName header from the In message; out.header.HeaderName to use a java.util.Date object in the HeaderName header from the Out message;
bean:beanID.MethodObjectInvokes a method on the referenced bean and returns the result of the method invocation. To specify a method name, you can either use the beanID.Method syntax; or you can use the beanID?method=methodName syntax.
ref:beanIDObjectLooks up the bean with the ID, beanID, in the registry and returns a reference to the bean itself. For example, if you are using the splitter EIP, you could use this variable to reference the bean that implements the splitting algorithm.
properties:KeyStringThe value of the Key property placeholder (see Property Placeholders in Implementing Enterprise Integration Patterns).
properties:Location:KeyStringThe value of the Key property placeholder, where the location of the properties file is given by Location (see Property Placeholders in Implementing Enterprise Integration Patterns).
threadNameStringThe name of the current thread.

The Spring Expression Language (SpEL) is an object graph navigation language provided with Spring 3, which can be used to construct predicates and expressions in a route. A notable feature of SpEL is the ease with which you can access beans from the registry.

Typically, XML elements belong to a schema, which is identified by a namespace URI. When processing documents like this, it is necessary to associate namespace URIs with prefixes, so that you can identify element names unambiguously in your XPath expressions. Fuse Mediation Router provides the helper class, org.apache.camel.builder.xml.Namespaces, which enables you to define associations between namespaces and prefixes.

For example, to associate the prefix, cust, with the namespace, http://acme.com/customer/record, and then extract the contents of the element, /cust:person/cust:name, you could define a route like the following:

import org.apache.camel.builder.xml.Namespaces;
...
Namespaces ns = new Namespaces("cust", "http://acme.com/customer/record");

from("queue:foo")
    .setHeader("user", xpath("/cust:person/cust:name/text()", ns))
    .to("direct:tie");

Where you make the namespace definitions available to the xpath() expression builder by passing the Namespaces object, ns, as an additional argument. If you need to define multiple namespaces, use the Namespace.add() method, as follows:

import org.apache.camel.builder.xml.Namespaces;
...
Namespaces ns = new Namespaces("cust", "http://acme.com/customer/record");
ns.add("inv", "http://acme.com/invoice");
ns.add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

If you need to specify the result type and define namespaces, you can use the three-argument form of xpath(), as follows:

xpath("/person/name/text()", String.class, ns)

Table 19.1 shows the namespaces that are predefined for XPath. You can use these namespace prefixes in the XPath expression that appears in the @XPath annotation.


You can use the following patterns in XPath location paths:

/people/person

The basic location path specifies the nested location of a particular element. That is, the preceding location path would match the person element in the following XML fragment:

<people>
  <person>...</person>
</people>

Note that this basic pattern can match multiple nodes—for example, if there is more than one person element inside the people element.

/name/text()

If you just want to access the text inside by the element, append /text() to the location path, otherwise the node includes the element's start and end tags (and these tags would be included when you convert the node to a string).

/person/telephone/@isDayTime

To select the value of an attribute, AttributeName, use the syntax @AttributeName. For example, the preceding location path returns true when applied to the following XML fragment:

<person>
  <telephone isDayTime="true">1234567890</telephone>
</person>
*

A wildcard that matches all elements in the specified scope. For example, /people/person/* matches all the child elements of person.

@*

A wildcard that matches all attributes of the matched elements. For example, /person/name/@* matches all attributes of every matched name element.

//

Match the location path at every nesting level. For example, the //name pattern matches every name element highlighted in the following XML fragment:

<invoice>
  <person>
    <name .../>
  </person>
</invoice>
<person>
  <name .../>
</person>
<name .../>
..

Selects the parent of the current context node. Not normally useful in the Fuse Mediation Router XPath language, because the current context node is the document root, which has no parent.

node()

Match any kind of node.

text()

Match a text node.

comment()

Match a comment node.

processing-instruction()

Match a processing-instruction node.

When you consider the structure of an XML document, the root element contains a sequence of children, and some of those child elements contain further children, and so on. Looked at in this way, where nested elements are linked together by the child-of relationship, the whole XML document has the structure of a tree. Now, if you choose a particular node in this element tree (call it the context node), you might want to refer to different parts of the tree relative to the chosen node. For example, you might want to refer to the children of the context node, to the parent of the context node, or to all of the nodes that share the same parent as the context node (sibling nodes).

An XPath axis is used to specify the scope of a node match, restricting the search to a particular part of the node tree, relative to the current context node. The axis is attached as a prefix to the node name that you want to match, using the syntax, AxisType::MatchingNode. For example, you can use the child:: axis to search the children of the current context node, as follows:

/invoice/items/child::item

The context node of child::item is the items element that is selected by the path, /invoice/items. The child:: axis restricts the search to the children of the context node, items, so that child::item matches the children of items that are named item. As a matter of fact, the child:: axis is the default axis, so the preceding example can be written equivalently as:

/invoice/items/item

But there several other axes (13 in all), some of which you have already seen in abbreviated form: @ is an abbreviation of attribute::, and // is an abbreviation of descendant-or-self::. The full list of axes is as follows (for details consult the reference below):

In addition to the standard XPath functions, the XPath language defines additional functions. These additional functions (which are listed in Table 19.4) can be used to access the underlying exchange, to evaluate a simple expression or to look up a property in the Fuse Mediation Router property placeholder component.

For example, the following example uses the in:header() function and the in:body() function to access a head and the body from the underlying exchange:

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");

Notice the similarity between theses functions and the corresponding in:HeaderName or in:body variables. The functions have a slightly different syntax however: in:header('HeaderName') instead of in:HeaderName; and in:body() instead of in:body.