Version 7.1
Copyright © 2012 Red Hat, Inc. and/or its affiliates.
Updated: 08 Jan 2014
Table of Contents
List of Tables
List of Examples
Table 1.1 gives an overview of the different syntaxes for invoking expression and predicate languages.
Table 1.1. Expression and Predicate Languages
| Language | Static Method | Fluent DSL Method | XML Element | Annotation | Artifact |
|---|---|---|---|---|---|
| Bean Integration | bean() | | method | @Bean | Camel core |
| Constant | constant() | | constant | @Constant | Camel core |
| EL | el() | | el | @EL | camel-juel |
| Groovy | groovy() | | groovy | @Groovy | camel-groovy |
| Header | header() | | header | @Header | Camel core |
| JavaScript | javaScript() | | javaScript | @JavaScript | camel-script |
| JoSQL | sql() | | sql | @SQL | camel-josql |
| JXPath | None | | jxpath | @JXPath | camel-jxpath |
| MVEL | mvel() | | mvel | @MVEL | camel-mvel |
| OGNL | ognl() | | ognl | @OGNL | camel-ognl |
| PHP | php() | | php | @PHP | camel-script |
| Property | property() | | property | @Property | Camel core |
| Python | python() | | python | @Python | camel-script |
| Ref | ref() | | ref | N/A | Camel core |
| Ruby | ruby() | | ruby | @Ruby | camel-script |
| Simple/File | simple() | | simple | @Simple | Camel core |
| SpEL | spel() | | spel | @SpEL | camel-spring |
| XPath | xpath() | | xpath | @XPath | Camel core |
| XQuery | xquery() | | xquery | @XQuery | camel-saxon |
Before you can use a particular expression language, you must ensure that the required JAR files are available on the classpath. If the language you want to use is not included in the Apache Camel core, you must add the relevant JARs to your classpath.
If you are using the Maven build system, you can modify the build-time classpath simply by adding the relevant dependency to your POM file. For example, if you want to use the Ruby language, add the following dependency to your POM file:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<!-- Use the same version as your Camel core version -->
<version>${camel.version}</version>
</dependency>If you are going to deploy your application in a Red Hat JBoss Fuse OSGi container, you also
need to ensure that the relevant language features are installed (features are named
after the corresponding Maven artifact). For example, to use the Groovy language in
the OSGi container, you must first install the camel-groovy feature by
entering the following OSGi console command:
karaf@root> features:install camel-groovy
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:
Most of the languages define a static method that can be used in
any context where an
org.apache.camel.Expression type or an
org.apache.camel.Predicate type is expected. The static method
takes a string expression (or predicate) as its argument and returns an
Expression object (which is usually also a Predicate
object).
For example, to implement a content-based router that processes messages in XML
format, you could route messages based on the value of the
/order/address/countryCode element, as follows:
from("SourceURL")
.choice
.when(xpath("/order/address/countryCode = 'us'"))
.to("file://countries/us/")
.when(xpath("/order/address/countryCode = 'uk'"))
.to("file://countries/uk/")
.otherwise()
.to("file://countries/other/")
.to("TargetURL");The Java fluent DSL supports another style of invoking expression languages.
Instead of providing the expression as an argument to an Enterprise Integration
Pattern (EIP), you can provide the expression as a sub-clause of the DSL command.
For example, instead of invoking an XPath expression as
filter(xpath(", you can
invoke the expression as,
Expression"))filter().xpath(".Expression")
For example, the preceding content-based router can be re-implemented in this style of invocation, as follows:
from("SourceURL")
.choice
.when().xpath("/order/address/countryCode = 'us'")
.to("file://countries/us/")
.when().xpath("/order/address/countryCode = 'uk'")
.to("file://countries/uk/")
.otherwise()
.to("file://countries/other/")
.to("TargetURL");You can also invoke an expression language in XML, by putting the expression string inside the relevant XML element.
For example, the XML element for invoking XPath in XML is xpath
(which belongs to the standard Apache Camel namespace). You can use XPath expressions in
a XML DSL content-based router, as follows:
<from uri="file://input/orders"/> <choice> <when> <xpath>/order/address/countryCode = 'us'</xpath> <to uri="file://countries/us/"/> </when> <when> <xpath>/order/address/countryCode = 'uk'</xpath> <to uri="file://countries/uk/"/> </when> <otherwise> <to uri="file://countries/other/"/> </otherwise> </choice>
Alternatively, you can specify a language expression using the
language element, where you specify the name of the language in the
language attribute. For example, you can define an XPath expression
using the language element as follows:
<language language="xpath">/order/address/countryCode = 'us'</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.
The constant language is a trivial built-in language that is used to specify a plain text string. This makes it possible to provide a plain text string in any context where an expression type is expected.
In XML, you can set the username header to the value, Jane Doe
as follows:
<camelContext>
<route>
<from uri="SourceURL"/>
<setHeader headerName="username">
<constant>Jane Doe</constant>
</setHeader>
<to uri="TargetURL"/>
</route>
</camelContext>The Unified Expression Language (EL) was originally specified as part of the JSP 2.1 standard (JSR-245), but it is now available as a standalone language. Apache Camel integrates with JUEL (http://juel.sourceforge.net/), which is an open source implementation of the EL language.
To use EL in your routes you need to add a dependency on
camel-juel to your project as shown in Example 3.1.
Example 3.1. Adding the camel-juel dependency
<!-- Maven POM File -->
<properties>
<camel-version>2.10.0-fuse-00-05</camel-version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-juel</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the el() static method in your application
code, include the following import statement in your Java source
files:
import static org.apache.camel.language.juel.JuelExpression.el;
Table 3.1 lists the variables that are accessible when using EL.
Table 3.1. EL variables
| Variable | Type | Value |
|---|---|---|
exchange
|
org.apache.camel.Exchange
| The current Exchange |
in
|
org.apache.camel.Message
| The IN message |
out
|
org.apache.camel.Message
| The OUT message |
Example 3.2 shows two routes that use EL.
Example 3.2. Routes using EL
<camelContext>
<route>
<from uri="seda:foo"/>
<filter>
<language language="el">${in.headers.foo == 'bar'}</language>
<to uri="seda:bar"/>
</filter>
</route>
<route>
<from uri="seda:foo2"/>
<filter>
<language language="el">${in.headers['My Header'] == 'bar'}</language>
<to uri="seda:bar"/>
</filter>
</route>
</camelContext>The file language is an extension to the simple language which is not always available. You can use it under the following circumstances:
![]() | Note |
|---|---|
The escape character, |
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=trueWhere 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=falseWhere 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
When an exchange originates from a File or FTP consumer endpoint, it is possible to apply file language expressions to the exchange throughout the route (as long as the original message headers are not erased). For example, you could define a content-based router, which routes messages according to their file extension, as follows:
<from uri="file://input/orders"/>
<choice>
<when>
<simple>${file:ext} == 'txt'</simple>
<to uri="bean:orderService?method=handleTextFiles"/>
</when>
<when>
<simple>${file:ext} == 'xml'</simple>
<to uri="bean:orderService?method=handleXmlFiles"/>
</when>
<otherwise>
<to uri="bean:orderService?method=handleOtherFiles"/>
</otherwise>
</choice>File variables can be used whenever a route starts with a File or FTP consumer
endpoint, which implies that the underlying message body is of
java.io.File type. The file variables enable you to access various
parts of the file pathname, almost as if you were invoking the methods of the
java.io.File class (in fact, the file language extracts the
information it needs from message headers that have been set by the File or FTP
endpoint).
Some of file variables return paths that are defined relative to a
starting directory, which is just the directory that is
specified in the File or FTP endpoint. For example, the following File consumer
endpoint has the starting directory, ./filetransfer (a relative
path):
file:filetransfer
The following FTP consumer endpoint has the starting directory,
./ftptransfer (a relative path):
ftp://myhost:2100/ftptransfer
In general, the file variables are named after corresponding methods on the
java.io.File class. For example, the file:absolute
variable gives the value that would be returned by the
java.io.File.getAbsolute() method.
![]() | Note |
|---|---|
This naming convention is not strictly followed, however. For example, there
is no such method as
|
Table 4.1 shows all of the variable supported by the file language.
Table 4.1. Variables for the File Language
| Variable | Type | Description |
|---|---|---|
file:name | String | The pathname relative to the starting directory. |
file:name.ext | String | The file extension (characters following the last .
character in the pathname). |
file:name.noext | String | The pathname relative to the starting directory, omitting the file extension. |
file:onlyname | String | The final segment of the pathname. That is, the file name without the parent directory path. |
file:onlyname.noext | String | The final segment of the pathname, omitting the file extension. |
file:ext | String | The file extension (same as file:name.ext). |
file:parent | String | The pathname of the parent directory, including the starting directory in the path. |
file:path | String | The file pathname, including the starting directory in the path. |
file:absolute | Boolean | true, if the starting directory was specified as an
absolute path; false, otherwise. |
file:absolute.path | String | The absolute pathname of the file. |
file:length | Long | The size of the referenced file. |
file:size | Long | Same as file:length. |
file:modified | java.util.Date | Date last modified. |
Consider a File consumer endpoint, where the starting directory is specified as a
relative pathname. For example, the following File endpoint
has the starting directory, ./filelanguage:
file://filelanguage
Now, while scanning the filelanguage directory, suppose that the
endpoint has just consumed the following file:
./filelanguage/test/hello.txt
And, finally, assume that the filelanguage directory itself has the
following absolute location:
/workspace/camel/camel-core/target/filelanguage
Given the preceding scenario, the file language variables return the following values, when applied to the current exchange:
| Expression | Result |
|---|---|
file:name | test/hello.txt |
file:name.ext | txt |
file:name.noext | test/hello |
file:onlyname | hello.txt |
file:onlyname.noext | hello |
file:ext | txt |
file:parent | filelanguage/test |
file:path | filelanguage/test/hello.txt |
file:absolute | false |
file:absolute.path | /workspace/camel/camel-core/target/filelanguage/test/hello.txt |
Consider a File consumer endpoint, where the starting directory is specified as an
absolute pathname. For example, the following File endpoint
has the starting directory,
/workspace/camel/camel-core/target/filelanguage:
file:///workspace/camel/camel-core/target/filelanguage
Now, while scanning the filelanguage directory, suppose that the
endpoint has just consumed the following file:
./filelanguage/test/hello.txt
Given the preceding scenario, the file language variables return the following values, when applied to the current exchange:
| Expression | Result |
|---|---|
file:name | test/hello.txt |
file:name.ext | txt |
file:name.noext | test/hello |
file:onlyname | hello.txt |
file:onlyname.noext | hello |
file:ext | txt |
file:parent | /workspace/camel/camel-core/target/filelanguage/test |
file:path | /workspace/camel/camel-core/target/filelanguage/test/hello.txt |
file:absolute | true |
file:absolute.path | /workspace/camel/camel-core/target/filelanguage/test/hello.txt |
Groovy is a Java-based scripting language that allows quick parsing of
object. The Groovy support is part of the camel-script module.
To use Groovy in your routes you need to add a dependency on
camel-script to your project as shown in
Example 5.1.
Example 5.1. Adding the camel-script dependency
<!-- Maven POM File -->
<properties>
<camel-version>2.10.0-fuse-00-05</camel-version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the groovy() static method in your application code,
include the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Table 5.1 lists the built-in attributes that are accessible when using Groovy.
Table 5.1. Groovy attributes
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the
properties component inside scripts. |
The attributes all set at ENGINE_SCOPE.
Example 5.2 shows two routes that use Groovy scripts.
Example 5.2. Routes using Groovy
<camelContext>
<route>
<from uri=""mock:mock0" />
<filter>
<language language="groovy">request.lineItems.any { i -> i.value > 100 }</language>
<to uri="mock:mock1" />
</filter>
</route>
<route>
<from uri="direct:in"/>
<setHeader headerName="firstName">
<language language="groovy">$user.firstName $user.lastName</language>
</setHeader>
<to uri="seda:users"/>
</route>
</camelContext>To access a property value from the properties component, invoke the resolve
method on the built-in properties attribute, as follows:
.setHeader("myHeader").groovy("properties.resolve(PropKey)") Where PropKey is the key of the property you want to resolve,
where the key value is of String type.
For more details about the properties component, see Properties in EIP Component Reference.
The header language provides a convenient way of accessing header values in the current message. When you supply a header name, the header language performs a case-insensitive lookup and returns the corresponding header value.
The header language is part of camel-core.
For example, to resequence incoming exchanges according to the value of a
SequenceNumber header (where the sequence number must be a positive integer),
you can define a route as follows:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="SourceURL"/>
<resequence>
<language language="header">SequenceNumber</language>
</resequence>
<to uri="TargetURL"/>
</route>
</camelContext>JavaScript, also known as ECMAScript is a Java-based scripting language that allows quick
parsing of object. The JavaScript support is part of the camel-script module.
To use JavaScript in your routes you need to add a dependency on
camel-script to your project as shown in
Example 7.1.
Example 7.1. Adding the camel-script dependency
<!-- Maven POM File -->
<properties>
<camel-version>2.10.0-fuse-00-05</camel-version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the javaScript() static method in your application code, include
the following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Table 7.1 lists the built-in attributes that are accessible when using JavaScript.
Table 7.1. JavaScript attributes
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the
properties component inside scripts. |
The attributes all set at ENGINE_SCOPE.
Example 7.2 shows a route that uses JavaScript.
Example 7.2. Route using JavaScript
<camelContext>
<route>
<from uri="direct:start"/>
<choice>
<when>
<langauge langauge="javaScript">request.headers.get('user') == 'admin'</langauge>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
</camelContext>To access a property value from the properties component, invoke the resolve
method on the built-in properties attribute, as follows:
.setHeader("myHeader").javaScript("properties.resolve(PropKey)") Where PropKey is the key of the property you want to resolve,
where the key value is of String type.
For more details about the properties component, see Properties in EIP Component Reference.
The JoSQL (SQL for Java objects) language enables you to evaluate predicates and expressions in Apache Camel. JoSQL employs a SQL-like query syntax to perform selection and ordering operations on data from in-memory Java objects—however, JoSQL is not a database. In the JoSQL syntax, each Java object instance is treated like a table row and each object method is treated like a column name. Using this syntax, it is possible to construct powerful statements for extracting and compiling data from collections of Java objects. For details, see http://josql.sourceforge.net/.
To use JoSQL in your routes you need to add a dependency on camel-josql to
your project as shown in Example 8.1.
Example 8.1. Adding the camel-josql dependency
<!-- Maven POM File -->
...
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-josql</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the sql() static method in your application code, include the
following import statement in your Java source files:
import static org.apache.camel.builder.sql.SqlBuilder.sql;
Table 8.1 lists the variables that are accessible when using JoSQL.
Table 8.1. SQL variables
| Name | Type | Description |
|---|---|---|
exchange | org.apache.camel.Exchange | The current Exchange |
in | org.apache.camel.Message | The IN message |
out | org.apache.camel.Message | The OUT message |
property | Object | the Exchange property whose key is property |
header | Object | the IN message header whose key is header |
variable | Object | the variable whose key is variable |
Example 8.2 shows a route that uses JoSQL.
Example 8.2. Route using JoSQL
<camelContext>
<route>
<from uri="direct:start"/>
<setBody>
<language language="sql">select * from MyType</language>
</setBody>
<to uri="seda:regularQueue"/>
</route>
</camelContext>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.
To use JXPath in your routes you need to add a dependency on
camel-jxpath to your project as shown in Example 9.1.
Example 9.1. Adding the camel-jxpath dependency
<!-- Maven POM File -->
<properties>
<camel-version>2.10.0-fuse-00-05</camel-version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jxpath</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>Table 9.1 lists the variables that are accessible when using JXPath.
Table 9.1. JXPath variables
| Variable | Type | Value |
|---|---|---|
this | org.apache.camel.Exchange | The current Exchange |
in | org.apache.camel.Message | The IN message |
out | org.apache.camel.Message | The OUT message |
Example 9.2 shows a route that use JXPath.
Example 9.2. Routes using JXPath
<camelContext>
<route>
<from uri="activemq:MyQueue"/>
<filter>
<jxpath>in/body/name = 'James'</xpath>
<to uri="mqseries:SomeOtherQueue"/>
</filter>
</route>
</camelContext>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.
You use the MVEL dot syntax to invoke Java methods, for example:
getRequest().getBody().getFamilyName()
Because MVEL is dynamically typed, it is unnecessary to cast the message body instance (of
Object type) before invoking the getFamilyName() method. You can
also use an abbreviated syntax for invoking bean attributes, for example:
request.body.familyName
To use MVEL in your routes you need to add a dependency on
camel-mvel to your project as shown in
Example 10.1.
Example 10.1. Adding the camel-mvel dependency
<!-- Maven POM File -->
<properties>
<camel-version>2.10.0-fuse-00-05</camel-version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-mvel</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>Table 10.1 lists the built-in variables that are accessible when using MVEL.
Table 10.1. MVEL variables
| Name | Type | Description |
|---|---|---|
this | org.apache.camel.Exchange | The current Exchange |
exchange | org.apache.camel.Exchange | The current Exchange |
exception | Throwable | the Exchange exception (if any) |
exchangeID | String | the Exchange ID |
fault | org.apache.camel.Message | The Fault message(if any) |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | Map | The Exchange properties |
property( | Object | The value of the named Exchange property |
property( | | The typed value of the named Exchange property |
Example 10.2 shows a route that uses MVEL.
Example 10.2. Route using MVEL
<camelContext>
<route>
<from uri="seda:foo"/>
<filter>
<language langauge="mvel">request.headers.foo == 'bar'</language>
<to uri="seda:bar"/>
</filter>
</route>
</camelContext>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.
To use OGNL in your routes you need to add a dependency on
camel-ognl to your project as shown in
Example 11.1.
Example 11.1. Adding the camel-ognl dependency
<!-- Maven POM File -->
...
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ognl</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the ognl() static method in your application code, include
the following import statement in your Java source files:
import static org.apache.camel.language.ognl.OgnlExpression.ognl;
Table 11.1 lists the built-in variables that are accessible when using OGNL.
Table 11.1. OGNL variables
| Name | Type | Description |
|---|---|---|
this | org.apache.camel.Exchange | The current Exchange |
exchange | org.apache.camel.Exchange | The current Exchange |
exception | Throwable | the Exchange exception (if any) |
exchangeID | String | the Exchange ID |
fault | org.apache.camel.Message | The Fault message(if any) |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | Map | The Exchange properties |
property( | Object | The value of the named Exchange property |
property( | | The typed value of the named Exchange property |
Example 11.2 shows a route that uses OGNL.
Example 11.2. Route using OGNL
<camelContext>
<route>
<from uri="seda:foo"/>
<filter>
<language langauge="ognl">request.headers.foo == 'bar'</language>
<to uri="seda:bar"/>
</filter>
</route>
</camelContext>PHP is a widely-used general-purpose scripting language that is especially suited for
Web development. The PHP support is part of the camel-script module.
To use PHP in your routes you need to add a dependency on
camel-script to your project as shown in
Example 12.1.
Example 12.1. Adding the camel-script dependency
<!-- Maven POM File -->
...
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the php() static method in your application code, include the
following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Table 12.1 lists the built-in attributes that are accessible when using PHP.
Table 12.1. PHP attributes
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the
properties component inside scripts. |
The attributes all set at ENGINE_SCOPE.
Example 12.2 shows a route that uses PHP.
Example 12.2. Route using PHP
<camelContext>
<route>
<from uri="direct:start"/>
<choice>
<when>
<language language="php">strpos(request.headers.get('user'), 'admin')!== FALSE</language>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
</camelContext>To access a property value from the properties component, invoke the resolve
method on the built-in properties attribute, as follows:
.setHeader("myHeader").php("properties.resolve(PropKey)") Where PropKey is the key of the property you want to resolve,
where the key value is of String type.
For more details about the properties component, see Properties in EIP Component Reference.
The property language provides a convenient way of accessing exchange properties. When you supply a key that matches one of the exchange property names, the property language returns the corresponding value.
The property language is part of camel-core.
For example, to implement the recipient list pattern when the listOfEndpoints
exchange property contains the recipient list, you could define a route as follows:
<camelContext>
<route>
<from uri="direct:a"/>
<recipientList>
<property>listOfEndpoints</property>
</recipientList>
</route>
</camelContext>Python is a remarkably powerful dynamic programming language that is used in a wide
variety of application domains. Python is often compared to Tcl, Perl, Ruby, Scheme or Java.
The Python support is part of the camel-script module.
To use Python in your routes you need to add a dependency on
camel-script to your project as shown in
Example 14.1.
Example 14.1. Adding the camel-script dependency
<!-- Maven POM File -->
...
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the python() static method in your application code, include the
following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Table 14.1 lists the built-in attributes that are accessible when using Python.
Table 14.1. Python attributes
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the
properties component inside scripts. |
The attributes all set at ENGINE_SCOPE.
Example 14.2 shows a route that uses Python.
Example 14.2. Route using Python
<camelContext>
<route>
<from uri="direct:start"/>
<choice>
<when>
<langauge langauge="python">if request.headers.get('user') = 'admin'</langauge>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
</camelContext>To access a property value from the properties component, invoke the resolve
method on the built-in properties attribute, as follows:
.setHeader("myHeader").python("properties.resolve(PropKey)") Where PropKey is the key of the property you want to resolve,
where the key value is of String type.
For more details about the properties component, see Properties in EIP Component Reference.
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.
To use the Ref language in your Java application code, include the following import statement in your Java source files:
import static org.apache.camel.language.simple.RefLanguage.ref;
For example, the splitter pattern can reference a custom expression using the Ref language, as follows:
<beans ...> <bean id="myExpression" class="com.mycompany.MyCustomExpression"/> ... <camelContext> <route> <from uri="seda:a"/> <split> <ref>myExpression</ref> <to uri="mock:b"/> </split> </route> </camelContext> </beans>
Ruby is a dynamic, open source programming language with a focus on simplicity and
productivity. It has an elegant syntax that is natural to read and easy to write. The Ruby
support is part of the camel-script module.
To use Ruby in your routes you need to add a dependency on
camel-script to your project as shown in
Example 16.1.
Example 16.1. Adding the camel-script dependency
<!-- Maven POM File -->
...
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the ruby() static method in your application code, include the
following import statement in your Java source files:
import static org.apache.camel.builder.camel.script.ScriptBuilder.*;
Table 16.1 lists the built-in attributes that are accessible when using Ruby.
Table 16.1. Ruby attributes
| Attribute | Type | Value |
|---|---|---|
context | org.apache.camel.CamelContext | The Camel Context |
exchange | org.apache.camel.Exchange | The current Exchange |
request | org.apache.camel.Message | The IN message |
response | org.apache.camel.Message | The OUT message |
properties | org.apache.camel.builder.script.PropertiesFunction | Function with a resolve method to make it easier to use the
properties component inside scripts. |
The attributes all set at ENGINE_SCOPE.
Example 16.2 shows a route that uses Ruby.
Example 16.2. Route using Ruby
<camelContext>
<route>
<from uri="direct:start"/>
<choice>
<when>
<langauge langauge="ruby">$request.headers['user'] == 'admin'</langauge>
<to uri="seda:adminQueue"/>
</when>
<otherwise>
<to uri="seda:regularQueue"/>
</otherwise>
</choice>
</route>
</camelContext>To access a property value from the properties component, invoke the resolve
method on the built-in properties attribute, as follows:
.setHeader("myHeader").ruby("properties.resolve(PropKey)") Where PropKey is the key of the property you want to resolve,
where the key value is of String type.
For more details about the properties component, see Properties in EIP Component Reference.
The simple language is a language that was developed in Apache Camel specifically for the purpose of accessing and manipulating the various parts of an exchange object. The language is not quite as simple as when it was originally created and it now features a comprehensive set of logical operators and conjunctions.
In the Java DSL, there are two styles for using the simple() command
in a route. You can either pass the simple() command as an argument to
a processor, as follows:
from("seda:order")
.filter(simple("${in.header.foo}"))
.to("mock:fooOrders");Or you can call the simple() command as a sub-clause on the
processor, for example:
from("seda:order")
.filter()
.simple("${in.header.foo}")
.to("mock:fooOrders");If you are embedding a simple expression inside a plain text string, you must use
the placeholder syntax, ${. For
example, to embed the Expression}in.header.name expression in a string:
simple("Hello ${in.header.name}, how are you?")From Java, you can customize the start and end tokens ({ and
}, by default) by calling the changeFunctionStartToken
static method and the changeFunctionEndToken static method on the
SimpleLanguage object.
For example, you can change the start and end tokens to [ and
] in Java, as follows:
// Java
import org.apache.camel.language.simple.SimpleLanguage;
...
SimpleLanguage.changeFunctionStartToken("[");
SimpleLanguage.changeFunctionEndToken("]");![]() | Note |
|---|---|
Customizing the start and end tokens affects all Apache Camel applications that
share the same |
In the XML DSL, you can use a simple expression by putting the expression inside a
simple element. For example, to define a route that performs
filtering based on the contents of the foo header:
<route id="simpleExample">
<from uri="seda:orders"/>
<filter>
<simple>${in.header.foo}</simple>
<to uri="mock:fooOrders"/>
</filter>
</route>Sometimes—for example, if you have enabled Spring property placeholders or
OSGi blueprint property placeholders—you might find that the
${ syntax clashes with
another property placeholder syntax. In this case, you can disambiguate the
placeholder using the alternative syntax,
Expression}$simple{, for the simple
expression. For example:Expression}
<simple>Hello $simple{in.header.name}, how are you?</simple>From XML configuration, you can customize the start and end tokens ({
and }, by default) by overriding the SimpleLanguage
instance. For example, to change the start and end tokens to [ and
], define a new SimpleLanguage bean in your XML
configuration file, as follows:
<bean id="simple" class="org.apache.camel.language.simple.SimpleLanguage"> <constructor-arg name="functionStartToken" value="["/> <constructor-arg name="functionEndToken" value="]"/> </bean>
![]() | Note |
|---|---|
Customizing the start and end tokens affects all Apache Camel applications that
share the same |
By default, whitespace preceding and following a simple expression is automatically trimmed in XML DSL. So this expression with surrounding whitespace:
<transform>
<simple>
data=${body}
</simple>
</transform>is automatically trimmed, so that it is equivalent to this expression (no surrounding whitespace):
<transform>
<simple>data=${body}</simple>
</transform>If you want to include newlines before or after the expression, you can either explicitly add a newline character, as follows:
<transform>
<simple>data=${body}\n</simple>
</transform>or you can switch off auto-trimming, by setting the trim attribute to
false, as follows:
<transform trim="false">
<simple>data=${body}
</simple>
</transform>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 |
|---|---|
Since Apache Camel 2.9, you must always use the placeholder
syntax, |
You can use the simple language to define string expressions, based on the
variables provided. For example, you can use a variable of the form,
in.header.HeaderName, to obtain the
value of the HeaderName header, as follows:
simple("${in.header.foo}")You can embed simple variables in a string expression—for example:
simple("Received a message from ${in.header.user} on $(date:in.header.date:yyyyMMdd}.")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}")You can specify the result type of an expression explicitly. This is mainly useful for converting the result type to a boolean or numerical type.
In the Java DSL, specify the result type as an extra argument to
simple(). For example, to return a boolean result, you could
evaluate a simple expression as follows:
...
.setHeader("cool", simple("true", Boolean.class)) In the XML DSL, specify the result type using the resultType
attribute. For example:
<setHeader headerName="cool">
<!-- use resultType to indicate that the type should be a java.lang.Boolean -->
<simple resultType="java.lang.Boolean">true</simple>
</setHeader> Simple expressions can be nested—for example:
simple("${header.${bean:headerChooser?method=whichHeader}}")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 use the null-safe operator, ?., to avoid encountering
null-pointer exceptions, in case the body does not have an
address. For example:
simple("${body?.address?.street}")If the body is a java.util.Map type, you can look up a value in the
map with the key, foo, using the following notation:
simple("${body[foo]?.name}")You can also use square brackets notation, [k], to access the
elements of a list. For example:
simple("${body.address.lines[0]}")
simple("${body.address.lines[1]}")
simple("${body.address.lines[2]}")The last keyword returns the index of the last element of a list. For
example, you can access the second last element of a list, as
follows:
simple("${body.address.lines[last-1]}")You can construct predicates by testing expressions for equality. For example, the
predicate, simple("${header.timeOfDay} == '14:30'"), tests
whether the timeOfDay header in the incoming message is equal to
14:30.
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 RHSValueWhere 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.
For example, you can perform simple string comparisons and numerical comparisons as follows:
simple("${in.header.user} == 'john'")
simple("${in.header.number} > '100'") // String literal can be converted to integerYou can test whether the left hand side is a member of a comma-separated list, as follows:
simple("${in.header.type} in 'gold,silver'")You can test whether the left hand side matches a regular expression, as follows:
simple("${in.header.number} regex '\d{4}'")You can test the type of the left hand side using the is operator, as
follows:
simple("${in.header.type} is 'java.lang.String'")
simple("${in.header.type} is 'String'") // You can abbreviate java.lang. typesYou can test whether the left hand side lies in a specified numerical range (where the range is inclusive), as follows:
simple("${in.header.number} range '100..199'")You can also combine predicates using the logical conjunctions,
&& and ||.
For example, here is an expression using the && conjunction
(logical and):
simple("${in.header.title} contains 'Camel' && ${in.header.type} == 'gold'")And here is an expression using the || conjunction (logical inclusive
or):
simple("${in.header.title} contains 'Camel' || ${in.header.type} == 'gold'")Table 17.1 shows all of the variables supported by the simple language.
Table 17.1. Variables for the Simple Language
| Variable | Type | Description |
|---|---|---|
exchangeId | String | The exchange's ID value. |
id | String | The In message ID value. |
body
| Object |
The In message body. Supports OGNL expressions. |
in.body | Object | The In message body. Supports OGNL expressions. |
out.body
| Object |
The Out message body. |
bodyAs( | Type | The 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 | The 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.HeaderName | Object |
The In message's
|
header[HeaderName] | Object |
The In message's
|
headers.HeaderName | Object | The In message's
HeaderName header. |
headers[HeaderName] | Object | The In message's
HeaderName header (alternative
syntax). |
in.header.HeaderName | Object | The In message's
HeaderName header. Supports
OGNL expressions. |
in.header[HeaderName] | Object | The In message's
HeaderName header (alternative
syntax). |
in.headers.HeaderName | Object | The In message's
HeaderName header. Supports
OGNL expressions. |
in.headers[HeaderName] | Object | The In message's
HeaderName header (alternative
syntax). |
out.header.HeaderName
| Object |
The Out message's
|
out.header[HeaderName] | Object |
The Out message's
|
out.headers.HeaderName | Object | The Out message's
HeaderName header. |
out.headers[HeaderName] | Object | The Out message's
HeaderName header (alternative
syntax). |
headerAs( | Type | The 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. |
headers | Map | All of the In headers (as a
java.util.Map type). |
in.headers | Map | All of the In headers (as a
java.util.Map type). |
property.PropertyName
| Object |
The |
property[PropertyName] | Object |
The |
sys.SysPropertyName | String | The SysPropertyName Java system
property. |
sysenv.SysEnvVar | String | The SysEnvVar system environment
variable. |
exception | String | Either 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.message | String | If an exception is set on the exchange, returns the value of
Exception.getMessage(); otherwise, returns
null. |
exception.stacktrace | String | If 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:pattern | String | A 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: | Object | Invokes a method on the referenced bean and returns the
result of the method invocation. To specify a method
name, you can either use the
syntax; or you can use the
methodName
syntax. |
ref: | Object | Looks 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: | String | The value of the Key property
placeholder (see Property Placeholders in Implementing Enterprise Integration Patterns). |
properties: | String | The 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). |
threadName | String | The name of the current thread. |
The binary operators for simple language predicates are shown in Table 17.2.
Table 17.2. Binary Operators for the Simple Language
| Operator | Description |
|---|---|
== | Equals. |
> | Greater than. |
>= | Greater than or equals. |
< | Less than. |
<= | Less than or equals. |
!= | Not equal to. |
contains | Test if LHS string contains RHS string. |
not contains | Test if LHS string does not contain RHS string. |
regex | Test if LHS string matches RHS regular expression. |
not regex | Test if LHS string does not match RHS regular expression. |
in | Test if LHS string appears in the RHS comma-separated list. |
not in | Test if LHS string does not appear in the RHS comma-separated list. |
is | Test if LHS is an instance of RHS Java type (using Java
instanceof operator). |
not is | Test if LHS is not an instance of RHS Java
type (using Java instanceof operator). |
range | Test if LHS number lies in the RHS range (where range has the
format,
'min...max'). |
not range | Test if LHS number does not lie in the RHS
range (where range has the format,
'min...max'). |
The binary operators for simple language predicates are shown in Table 17.3.
Table 17.3. Unary Operators for the Simple Language
| Operator | Description |
|---|---|
++ | Increment a number by 1. |
-- | Decrement a number by 1. |
\ | Escape the following character. Note the following special cases:
\n for new line, \t for tab, and
\r for carriage return. |
The conjunctions shown in Table 17.4 can be used to combine two or more simple language predicates.
Table 17.4. Conjunctions for Simple Language Predicates
| Operator | Description |
|---|---|
&& | Combine two predicates with logical and. |
|| | Combine two predicates with logical inclusive or. |
and | Deprecated. Use &&
instead. |
or | Deprecated. Use ||
instead. |
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.
The SpEL expressions must use the placeholder syntax,
#{, so that they can be embedded in
a plain text string (in other words, SpEL has expression templating enabled).SpelExpression}
SpEL can also look up beans in the registry (typically, the Spring registry), using the
@ syntax. For example, given a bean with the
ID, BeanIDheaderUtils, and the method, count() (which counts the number of
headers on the current message), you could use the headerUtils bean in an SpEL
predicate, as follows:
#{@headerUtils.count > 4}To use SpEL in your routes you need to add a dependency on camel-spring
to your project as shown in Example 18.1.
Example 18.1. Adding the camel-spring dependency
<!-- Maven POM File -->
<properties>
<camel-version>2.10.0-fuse-00-05</camel-version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>Table 18.1 lists the variables that are accessible when using SpEL.
Table 18.1. SpEL variables
| Variable | Type | Description |
|---|---|---|
this | Exchange | The current exchange is the root object. |
exchange | Exchange | The current exchange. |
exchangeId | String | The current exchange's ID. |
exception | Throwable | The exchange exception (if any). |
fault | Message | The fault message (if any). |
request | Message | The exchange's In message. |
response | Message | The exchange's Out message (if any). |
properties | Map | The exchange properties. |
property( | Object | The exchange property keyed by Name. |
property( | Type | The exchange property keyed by Name, converted to the
type, Type. |
For example, to select only those messages whose Country header has the value
USA, you can use the following SpEL expression:
<route> <from uri="SourceURL"/> <filter> <spel>#{request.headers['Country'] == 'USA'}}</spel> <to uri="TargetURL"/> </filter> </route>
You can define the same route in the Java DSL, as follows:
from("SourceURL")
.filter().spel("#{request.headers['Country'] == 'USA'}")
.to("TargetURL");The following example shows how to embed SpEL expressions within a plain text string:
from("SourceURL")
.setBody(spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}"))
.to("TargetURL");You can use xpath(" to
evaluate an XPath expression on the current exchange (where the XPath expression is
applied to the body of the current In message). The result of
the Expression")xpath() expression is an XML node (or node set, if more than one
node matches).
For example, to extract the contents of the /person/name element from
the current In message body and use it to set a header named
user, you could define a route like the following:
from("queue:foo")
.setHeader("user", xpath("/person/name/text()"))
.to("direct:tie");Instead of specifying xpath() as an argument to
setHeader(), you can use the fluent builder xpath()
command—for example:
from("queue:foo")
.setHeader("user").xpath("/person/name/text()")
.to("direct:tie");If you want to convert the result to a specific type, specify the result type as
the second argument of xpath(). For example, to specify explicitly that
the result type is String:
xpath("/person/name/text()", String.class)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. Apache Camel 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)One of the most frequent problems that can occur when using XPath expressions is that there is a mismatch between the namespaces appearing in the incoming messages and the namespaces used in the XPath expression. To help you troubleshoot this kind of problem, the XPath language supports an option to dump all of the namespaces from all of the incoming messages into the system log.
To enable namespace logging at the INFO log level, enable the
logNamespaces option in the Java DSL, as follows:
xpath("/foo:person/@id", String.class).logNamespaces()Alternatively, you could configure your logging system to enable
TRACE level logging on the
org.apache.camel.builder.xml.XPathBuilder logger.
When namespace logging is enabled, you will see log messages like the following for each processed message:
2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO XPathBuilder -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}To evaluate an XPath expression in the XML DSL, put the XPath expression inside an
xpath element. The XPath expression is applied to the body of the
current In message and returns an XML node (or node set).
Typically, the returned XML node is automatically converted to a string.
For example, to extract the contents of the /person/name element from
the current In message body and use it to set a header named
user, you could define a route like the following:
<beans ...>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="queue:foo"/>
<setHeader headerName="user">
<xpath>/person/name/text()</xpath>
</setHeader>
<to uri="direct:tie"/>
</route>
</camelContext>
</beans>If you want to convert the result to a specific type, specify the result type by
setting the resultType attribute to a Java type name (where you must
specify the fully-qualified type name). For example, to specify explicitly that the
result type is java.lang.String (you can omit the
java.lang. prefix here):
<xpath resultType="String">/person/name/text()</xpath>
When processing documents whose elements belong to one or more XML schemas, it is
typically necessary to associate namespace URIs with prefixes, so that you can
identify element names unambiguously in your XPath expressions. It is possible to
use the standard XML mechanism for associating prefixes with namespace URIs. That
is, you can set an attribute like this:
xmlns:.Prefix="NamespaceURI"
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:
<beans ...>
<camelContext xmlns="http://camel.apache.org/schema/spring"
xmlns:cust="http://acme.com/customer/record" >
<route>
<from uri="queue:foo"/>
<setHeader headerName="user">
<xpath>/cust:person/cust:name/text()</xpath>
</setHeader>
<to uri="direct:tie"/>
</route>
</camelContext>
</beans>One of the most frequent problems that can occur when using XPath expressions is that there is a mismatch between the namespaces appearing in the incoming messages and the namespaces used in the XPath expression. To help you troubleshoot this kind of problem, the XPath language supports an option to dump all of the namespaces from all of the incoming messages into the system log.
To enable namespace logging at the INFO log level, enable the
logNamespaces option in the XML DSL, as follows:
<xpath logNamespaces="true" resultType="String">/foo:person/@id</xpath>
Alternatively, you could configure your logging system to enable
TRACE level logging on the
org.apache.camel.builder.xml.XPathBuilder logger.
When namespace logging is enabled, you will see log messages like the following for each processed message:
2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO XPathBuilder -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}When using Apache Camel bean integration to invoke a method on a Java bean, you can
use the @XPath annotation to extract a value from the exchange and bind
it to a method parameter.
For example, consider the following route fragment, which invokes the
credit method on an AccountService object:
from("queue:payments")
.beanRef("accountService","credit")
...The credit method uses parameter binding annotations to extract
relevant data from the message body and inject it into its parameters, as
follows:
public class AccountService {
...
public void credit(
@XPath("/transaction/transfer/receiver/text()") String name,
@XPath("/transaction/transfer/amount/text()") String amount
)
{
...
}
...
}For more information about bean integration, see Bean Integration in Implementing Enterprise Integration Patterns.
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.
Table 19.1. Predefined Namespaces for @XPath
| Namespace URI | Prefix |
|---|---|
http://www.w3.org/2001/XMLSchema | xsd |
http://www.w3.org/2003/05/soap-envelope | soap |
You can use the @NamespacePrefix annotation to define custom XML
namespaces. Invoke the @NamespacePrefix annotation to initialize the
namespaces argument of the @XPath annotation. The
namespaces defined by @NamespacePrefix can then be used in the
@XPath annotation's expression value.
For example, to associate the prefix, ex, with the custom namespace,
http://fusesource.com/examples, invoke the @XPath
annotation as follows:
public class AccountService {
...
public void credit(
@XPath(
value = "/ex:transaction/ex:transfer/ex:receiver/text()",
namespaces = @NamespacePrefix(
prefix = "ex",
uri = "http://fusesource.com/examples"
)
) String name,
@XPath(
value = "/ex:transaction/ex:transfer/ex:amount/text()",
namespaces = @NamespacePrefix(
prefix = "ex",
uri = "http://fusesource.com/examples"
)
) String amount,
)
{
...
}
...
}The org.apache.camel.builder.xml.XPathBuilder class enables you to
evaluate XPath expressions independently of an exchange. That is, if you have an XML
fragment from any source, you can use XPathBuilder to evaluate an XPath
expression on the XML fragment.
Use the matches() method to check whether one or more XML nodes can
be found that match the given XPath expression. The basic syntax for matching an
XPath expression using XPathBuilder is as follows:
boolean matches = XPathBuilder
.xpath("Expression")
.matches(CamelContext, "XMLString");Where the given expression, Expression, is evaluated
against the XML fragment, XMLString, and the result is
true, if at least one node is found that matches the expression. For example, the
following example returns true, because the XPath expression finds a
match in the xyz attribute.
boolean matches = XPathBuilder
.xpath("/foo/bar/@xyz")
.matches(getContext(), "<foo><bar xyz='cheese'/></foo>"));Use the evaluate() method to return the contents of the first node
that matches the given XPath expression. The basic syntax for evaluating an XPath
expression using XPathBuilder is as follows:
String nodeValue = XPathBuilder
.xpath("Expression")
.evaluate(CamelContext, "XMLString");You can also specify the result type by passing the required type as the second
argument to evaluate()—for example:
String name = XPathBuilder
.xpath("foo/bar")
.evaluate(context, "<foo><bar>cheese</bar></foo>", String.class);
Integer number = XPathBuilder
.xpath("foo/bar")
.evaluate(context, "<foo><bar>123</bar></foo>", Integer.class);
Boolean bool = XPathBuilder
.xpath("foo/bar")
.evaluate(context, "<foo><bar>true</bar></foo>", Boolean.class);A prerequisite for using the Saxon parser is that you add a dependency on the
camel-saxon artifact (either adding this dependency to your Maven
POM, if you use Maven, or adding the camel-saxon-2.10.0-fuse-00-05.jar file
to your classpath, otherwise).
In Java DSL, the simplest way to enable the Saxon parser is to call the
saxon() fluent builder method. For example, you could invoke the
Saxon parser as shown in the following example:
// Java
// create a builder to evaluate the xpath using saxon
XPathBuilder builder = XPathBuilder.xpath("tokenize(/foo/bar, '_')[2]").saxon();
// evaluate as a String result
String result = builder.evaluate(context, "<foo><bar>abc_def_ghi</bar></foo>");In XML DSL, the simplest way to enable the Saxon parser is to set the
saxon attribute to true in the xpath element. For
example, you could invoke the Saxon parser as shown in the following example:
<xpath saxon="true" resultType="java.lang.String">current-dateTime()</xpath>
If you want to use the Saxon XML parser in your application code, you can create an instance of the Saxon transformer factory explicitly using the following code:
// Java import javax.xml.transform.TransformerFactory; import net.sf.saxon.TransformerFactoryImpl; ... TransformerFactory saxonFactory = new net.sf.saxon.TransformerFactoryImpl();
On the other hand, if you prefer to use the generic JAXP API to create a
transformer factory instance, you must first set the
javax.xml.transform.TransformerFactory property in the
file, as follows:ESBInstall/etc/system.properties
javax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl
You can then instantiate the Saxon factory using the generic JAXP API, as follows:
// Java import javax.xml.transform.TransformerFactory; ... TransformerFactory factory = TransformerFactory.newInstance();
If your application depends on any third-party libraries that use Saxon, it might be necessary to use the second, generic approach.
![]() | Note |
|---|---|
The Saxon library must be installed in the container as the OSGi bundle,
|
By default, an XPath expression returns a list of one or more XML nodes, of
org.w3c.dom.NodeList type. You can use the type converter mechanism
to convert the result to a different type, however. In the Java DSL, you can specify
the result type in the second argument of the xpath() command. For
example, to return the result of an XPath expression as a
String:
xpath("/person/name/text()", String.class)In the XML DSL, you can specify the result type in the resultType
attribute, as follows:
<xpath resultType="java.lang.String">/person/name/text()</xpath>
You can use the following patterns in XPath location paths:
/people/personThe 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/@isDayTimeTo select the value of an attribute,
AttributeName, use the syntax
@. For
example, the preceding location path returns AttributeNametrue 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 Apache Camel 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.
You can filter the set of nodes matching a location path by appending a predicate
in square brackets, [. For
example, you can select the
Predicate]Nth node from the list of
matches by appending [ to a location path.
The following expression selects the first matching N]person
element:
/people/person[1]
The following expression selects the second-last person
element:
/people/person[last()-1]
You can test the value of attributes in order to select elements with particular
attribute values. The following expression selects the name elements,
whose surname attribute is either Strachan or Davies:
/person/name[@surname="Strachan" or @surname="Davies"]
You can combine predicate expressions using any of the conjunctions
and, or, not(), and you can compare
expressions using the comparators, =, !=, >,
>=, <, <= (in practice, the
less-than symbol must be replaced by the < entity). You can also
use XPath functions in the predicate filter.
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,
.
For example, you can use the AxisType::MatchingNodechild:: 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):
ancestor
ancestor-or-self
attribute
child
descendant
descendant-or-self
following
following-sibling
namespace
parent
preceding
preceding-sibling
self
XPath provides a small set of standard functions, which can be useful when evaluating predicates. For example, to select the last matching node from a node set, you can use the last() function, which returns the index of the last node in a node set, as follows:
/people/person[last()]
Where the preceding example selects the last person element in a
sequence (in document order).
For full details of all the functions that XPath provides, consult the reference below.
For full details of the XPath grammar, see the XML Path Language, Version 1.0 specification.
You can use xpath in the Java DSL or the XML DSL in a context where a
predicate is expected—for example, as the argument to a filter()
processor or as the argument to a when() clause.
For example, the following route filters incoming messages, allowing a message to
pass, only if the /person/city element contains the value,
London:
from("direct:tie")
.filter().xpath("/person/city = 'London'").to("file:target/messages/uk");
The following route evaluates the XPath predicate in a when()
clause:
from("direct:tie")
.choice()
.when(xpath("/person/city = 'London'")).to("file:target/messages/uk")
.otherwise().to("file:target/messages/others");The XPath language supports the standard XPath predicate operators, as shown in Table 19.2.
Table 19.2. Operators for the XPath Language
| Operator | Description |
|---|---|
= | Equals. |
!= | Not equal to. |
> | Greater than. |
>= | Greater than or equals. |
< | Less than. |
<= | Less than or equals. |
or | Combine two predicates with logical and. |
and | Combine two predicates with logical inclusive or. |
not() | Negate predicate argument. |
When evaluating XPath expressions inside a route, you can use XPath variables to
access the contents of the current exchange, as well as O/S environment variables
and Java system properties. The syntax to access a variable value is
$ or
VarName$,
if the variable is accessed through an XML namespace.Prefix:VarName
For example, you can access the In message's body as
$in:body and the In message's header value as
$in:. O/S environment
variables can be accessed as HeaderName$env: and
Java system properties can be accessed as
EnvVar$system:.SysVar
In the following example, the first route extracts the value of the
/person/city element and inserts it into the city
header. The second route filters exchanges using the XPath expression,
$in:city = 'London', where the $in:city variable is
replaced by the value of the city header.
from("file:src/data?noop=true")
.setHeader("city").xpath("/person/city/text()")
.to("direct:tie");
from("direct:tie")
.filter().xpath("$in:city = 'London'").to("file:target/messages/uk");
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 Apache Camel 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: or
HeaderNamein:body variables. The functions have a slightly different syntax
however: in:header( instead of
'HeaderName')in:; and
HeaderNamein:body() instead of in:body.
You can also use variables in expressions that are evaluated using the
XPathBuilder class. In this case, you cannot use variables such as
$in:body or $in:,
because there is no exchange object to evaluate against. But you
can use variables that are defined inline using the
HeaderNamevariable( fluent builder method.Name,
Value)
For example, the following XPathBuilder construction evaluates the
$test variable, which is defined to have the value,
London:
String var = XPathBuilder.xpath("$test")
.variable("test", "London")
.evaluate(getContext(), "<name>foo</name>");Note that variables defined in this way are automatically entered into the global
namespace (for example, the variable, $test, uses no prefix).
Table 19.3 shows the namespace URIs that are associated with the various namespace prefixes.
Table 19.3. XPath Variable Namespaces
| Namespace URI | Prefix | Description |
|---|---|---|
http://camel.apache.org/schema/spring | None | Default namespace (associated with variables that have no namespace prefix). |
http://camel.apache.org/xml/in/ | in | Used to reference header or body of the current exchange's In message. |
http://camel.apache.org/xml/out/ | out | Used to reference header or body of the current exchange's Out message. |
http://camel.apache.org/xml/functions/ | functions | Used to reference some custom functions. |
http://camel.apache.org/xml/variables/environment-variables | env | Used to reference O/S environment variables. |
http://camel.apache.org/xml/variables/system-properties | system | Used to reference Java system properties. |
http://camel.apache.org/xml/variables/exchange-property | Undefined | Used to reference exchange properties. You must define your own prefix for this namespace. |
Table 19.4 shows the custom functions that you can use in Apache Camel XPath expressions. These functions can be used in addition to the standard XPath functions.
Table 19.4. XPath Custom Functions
| Function | Description |
|---|---|
in:body() | Returns the In message body. |
in:header( | Returns the In message header with name,
HeaderName. |
out:body() | Returns the Out message body. |
out:header( | Returns the Out message header with name,
HeaderName. |
function:properties( | Looks up a property with the key,
PropKey (see Property Placeholders in Implementing Enterprise Integration Patterns). |
function:simple( | Evaluates the specified simple expression,
SimpleExp. |
XQuery was originally devised as a query language for data stored in XML form in a database. The XQuery language enables you to select parts of the current message, when the message is in XML format. XQuery is a superset of the XPath language; hence, any valid XPath expression is also a valid XQuery expression.
You can pass an XQuery expression to xquery() in several ways. For
simple expressions, you can pass the XQuery expressions as a string
(java.lang.String). For longer XQuery expressions, you might prefer to
store the expression in a file, which you can then reference by passing a
java.io.File argument or a java.net.URL argument to
the overloaded xquery() method. The XQuery expression implicitly acts on
the message content and returns a node set as the result. Depending on the context, the return
value is interpreted either as a predicate (where an empty node set is interpreted as false)
or as an expression.
To use XQuery in your routes you need to add a dependency on
camel-saxon to your project as shown in
Example 20.1.
Example 20.1. Adding the camel-saxon dependency
<!-- Maven POM File -->
...
<dependencies>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-saxon</artifactId>
<version>${camel-version}</version>
</dependency>
...
</dependencies>To use the xquery() static method in your application code, include the
following import statement in your Java source files:
import static org.apache.camel.builder.saxon.XQueryBuilder.xquery;
Table 20.1 lists the variables that are accessible when using XQuery.
Table 20.1. XQuery variables
| Variable | Type | Description |
|---|---|---|
exchange | Exchange | The current Exchange |
in.body | Object | The body of the IN message |
out.body | Object | The body of the OUT message |
in.headers. | Object | The IN message header whose key is key |
out.headers. | Object | The OUT message header whose key is key |
key | Object | The Exchange property whose key is key |
Example 20.2 shows a route that uses XQuery.
Example 20.2. Route using XQuery
<camelContext>
<route>
<from uri="activemq:MyQueue"/>
<filter>
<language langauge="xquery">/foo:person[@name='James']</language>
<to uri="mqseries:SomeOtherQueue"/>
</filter>
</route>
</camelContext>