Apache Camel XPath Example
Processors and endpoints are an integral part of a camel routing. Camel uses Domain Specific Language (DSL) to define its routing. When it comes to defining predicates in the routing, you need a mature expression language. There are many different expression languages to choose from, some of which include Simple, EL, JXPath, Mvel, OGNL, PHP, BeanShell, JavaScript, Groovy, Python, Ruby,
XPath.
In this article, we will look into examples of XPath. We will use XPath to create a Predicate in a Message Filter.
Before we start with our example, Let’s look into the setup details.
This example uses the following frameworks:
- Maven 3.2.3
- Apache Camel 2.15.1
- Spring 4.1.5.RELEASE
- Eclipse as the IDE, version Luna 4.4.1.
1. Dependencies
I will be showing you some examples of camel ActiveMQ so you need to add the following dependencies:
camel-core
– basic module of apache camel.camel-stream
– We will use this to send output to the console.spring-context
andcamel-spring
– Since we be configuring our camel context in spring.
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javacodegeeks.camel</groupId> <artifactId>camelHelloWorld</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-core</artifactId> <version>2.15.1</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-stream</artifactId> <version>2.15.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-spring</artifactId> <version>2.15.1</version> </dependency> </dependencies> </project>
2. XPath to filter messages
In the below example, we filter out the orders which are available with an XPath expression and then send them to an order processor bean.
OrderProcessor:
package com.javacodegeeks.camel; public class OrderProcessor { public String process(String payload) { System.out.println("Processed " + payload); return payload; } }
CamelXPathFilterExample:
package com.javacodegeeks.camel; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.util.jndi.JndiContext; public class CamelXPathFilterExample { public static void main(String[] args) throws Exception { JndiContext jndiContext = new JndiContext(); jndiContext.bind("orderBean", new OrderProcessor()); CamelContext camelContext = new DefaultCamelContext(jndiContext); try { camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:start") .choice() .when().xpath("//available = 'true'").to("bean:orderBean") .end() .to("stream:out"); } }); camelContext.start(); ProducerTemplate template = camelContext.createProducerTemplate(); template.sendBody("direct:start", "<order><product>laptop</product><available>true</available></order>"); template.sendBody("direct:start", "<order><product>books</product><available>false</available></order>"); } finally { camelContext.stop(); } } }
As you can see only the laptop orders get processed and the books order is skipped as they are out of stock.
Output:
Processed <order><product>laptop</product><available>true</available></order> <order><product>laptop</product><available>true</available></order> <order><product>books</product><available>false</available></order>
3. XPath Filtering using Spring
The above example can be defined in spring. We use <xpath> element to define the predicate.
xpathFilterApplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> <bean id="orderProcessor" class="com.javacodegeeks.camel.OrderProcessor" /> <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:start" /> <choice> <when> <xpath>//available = 'true'</xpath> <to uri="bean:orderProcessor" /> </when> </choice> <to uri="stream:out"/> </route> </camelContext> </beans>
CamelXPathFilterUsingSpring:
package com.javacodegeeks.camel; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.spring.SpringCamelContext; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class CamelXPathFilterUsingSpring { public static final void main(String[] args) throws Exception { ApplicationContext appContext = new ClassPathXmlApplicationContext( "xpathFilterApplicationContext.xml"); CamelContext camelContext = SpringCamelContext.springCamelContext( appContext, false); try { ProducerTemplate template = camelContext.createProducerTemplate(); camelContext.start(); template.sendBody("direct:start", "<order><product>laptop</product><available>true</available></order>"); template.sendBody("direct:start", "<order><product>books</product><available>false</available></order>"); } finally { camelContext.stop(); } } }
Output:
Processed <order><product>laptop</product><available>true</available></order> <order><product>laptop</product><available>true</available></order> <order><product>books</product><available>false</available></order>
4. Splitting XML Messages using XPath
In this example, we will show you how to use XPath to process fragments of XML. The orders.xml contains many orders. Each order belongs to a particular product and contains order items. In our example below, we extract items of a particular product.
We will use an XPath Expression within the split DSL statement to isolate the orders belonging to ‘electroincs’ product.
orders.xml:
<?xml version="1.0" encoding="UTF-8"?> <orders> <order product="electronics"> <items> <item>Laptop</item> <item>Mobile</item> </items> </order> <order product="books"> <items> <item>Design Patterns</item> <item>XML</item> </items> </order> </orders>
CamelXPathSplitExample:
package com.javacodegeeks.camel; import java.io.FileInputStream; import java.io.InputStream; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; public class CamelXPathSplitExample { public static void main(String[] args) throws Exception { CamelContext camelContext = new DefaultCamelContext(); try { camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:start") .split(xpath("//order[@product='electronics']/items/item/text()")) .to("stream:out") .end(); } }); InputStream is = new FileInputStream("src/main/resources/orders.xml"); camelContext.start(); ProducerTemplate template = camelContext.createProducerTemplate(); template.sendBody("direct:start", is); } finally { camelContext.stop(); } } }
Output:
LaptopMobile
5. Using Namespaces with XPath
We will now modify our previous example and add a namespace to the orders.xml
.
orders.xml:
<?xml version="1.0" encoding="UTF-8"?> <orders xmlns="http://com.javacodegeeks.camel/schema/orders"> <order product="electronics"> <items> <item>Laptop</item> <item>Mobile</item> </items> </order> <order product="books"> <items> <item>Design Patterns</item> <item>XML</item> </items> </order> </orders>
In order for our XPath Expression to match, we will need to refer to the namespace through a prefix and associate the prefix with the namespace URI.
We can associate the namespace to the xpath()
expression using namespace
method. In order for our XPath Expression to match, we will need to refer to the namespace through the defined prefix.
CamelXPathSplitNamespaceExample:
package com.javacodegeeks.camel; import java.io.FileInputStream; import java.io.InputStream; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; public class CamelXPathSplitNamespaceExample { public static void main(String[] args) throws Exception { CamelContext camelContext = new DefaultCamelContext(); try { camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:start") .split(xpath("//n:order[@product='electronics']/n:items/n:item/text()") .namespace("n", "http://com.javacodegeeks.camel/schema/orders")) .to("stream:out") .end(); } }); InputStream is = new FileInputStream("src/main/resources/ordersWithNamespace.xml"); camelContext.start(); ProducerTemplate template = camelContext.createProducerTemplate(); template.sendBody("direct:start", is); } finally { camelContext.stop(); } } }
Output:
LaptopMobile
6. XML Namespaces in Spring
In the XML DSL, the namespace definition is provided on some parent XML element such as the camelContext:
xpathSplitWithNsApplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> <bean id="orderProcessor" class="com.javacodegeeks.camel.OrderProcessor" /> <camelContext xmlns="http://camel.apache.org/schema/spring" xmlns:n="http://com.javacodegeeks.camel/schema/orders"> <route> <from uri="direct:start" /> <split> <xpath>/n:orders/n:order[@product='electronics']/n:items/n:item/text() </xpath> <to uri="stream:out" /> </split> </route> </camelContext> </beans>
CamelXPathSplitNamespaceUsingSpring:
package com.javacodegeeks.camel; import java.io.FileInputStream; import java.io.InputStream; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.spring.SpringCamelContext; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class CamelXPathSplitNamespaceUsingSpring { public static final void main(String[] args) throws Exception { ApplicationContext appContext = new ClassPathXmlApplicationContext( "xpathSplitWithNsApplicationContext.xml"); CamelContext camelContext = SpringCamelContext.springCamelContext( appContext, false); InputStream is = new FileInputStream("src/main/resources/ordersWithNamespace.xml"); camelContext.start(); ProducerTemplate template = camelContext.createProducerTemplate(); template.sendBody("direct:start", is); } }
Output:
LaptopMobile
7. Binding using Camel language annotations
Camel provides a way for you to use annotations to tell it how to map the message to parameters. In the below example, we use @XPat
annotation to only allow processing Laptop orders.
OrderProcessor:
package com.javacodegeeks.camel; import org.apache.camel.language.XPath; public class OrderProcessor { public String process(String payload) { System.out.println("Processed " + payload); return payload; } public boolean processItem(@XPath("//order[@product='electronics']/items/item/text()") String item) { boolean condition = item != null && "Laptop".equals(item); if (condition) { System.out.println("Processing item " + item); } return condition; } }
We use the above annotated method to filter the payloads.
CamelXPathAnnotationExample:
package com.javacodegeeks.camel; import java.io.FileInputStream; import java.io.InputStream; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; public class CamelXPathAnnotationExample { public static void main(String[] args) throws Exception { CamelContext camelContext = new DefaultCamelContext(); try { camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:start") .filter().method(new OrderProcessor(), "processItem") .to("stream:out"); } }); camelContext.start(); ProducerTemplate template = camelContext.createProducerTemplate(); //...//order[@product='electronics']/items/item/text() String ordersXml = "<orders><order product=\'electronics\'><items><item>Laptop</item><item>Mobile</item></items></order></orders>"; template.sendBody("direct:start", ordersXml); ordersXml = "<orders><order product=\'books\'><items><item>Design Patterns</item><item>XML</item></items></order></orders>"; template.sendBody("direct:start", ordersXml); } finally { camelContext.stop(); } } }
Output:
Processing item Laptop LaptopMobile
8. Download the Eclipse Project
This was an example about Apache Camel XPath.
You can download the full source code of this example here: camelXpathExample.zip