blob: eadf004803c8b1557cd118165f877d812109d814 [file]
= XPath Language
:doctitle: XPath
:shortname: xpath
:artifactid: camel-xpath
:description: Evaluates an XPath expression against an XML payload
:since: 1.1
:supportlevel: Stable
:tabs-sync-option:
*Since Camel {since}*
Camel supports http://www.w3.org/TR/xpath[XPath] to allow an
xref:manual::expression.adoc[Expression] or xref:manual::predicate.adoc[Predicate] to be
used in the xref:manual::dsl.adoc[DSL].
For example, you could use XPath to create a
predicate in a xref:eips:filter-eip.adoc[Message Filter]
or as an expression for a xref:eips:recipientList-eip.adoc[Recipient List].
== XPath Language options
// language options: START
include::partial$language-options.adoc[]
// language options: END
== Namespaces
You can use namespaces with XPath expressions using the `Namespaces` helper class.
=== Sharing namespaces via a registry bean
When the same prefix to URI mappings are needed by several expressions, you can register a
single `org.apache.camel.support.builder.Namespaces` bean and refer to it from each
expression with the `namespacesRef` option, instead of repeating the mappings inline.
This is intended for XML and YAML DSL, where a `Namespaces` instance cannot be passed
programmatically. In Java DSL you keep passing the builder directly.
[tabs]
====
Java::
+
[source,java]
----
Namespaces ns = new Namespaces("c", "http://acme.com/cheese")
.add("w", "http://acme.com/wine");
from("direct:start")
.filter(xpath("/c:number = 55", ns))
.to("mock:result");
----
XML::
+
[source,xml]
----
<camel xmlns="http://camel.apache.org/schema/xml-io">
<bean name="myNamespaces" type="org.apache.camel.support.builder.Namespaces">
<properties>
<property key="namespaces[c]" value="http://acme.com/cheese"/>
<property key="namespaces[w]" value="http://acme.com/wine"/>
</properties>
</bean>
<route>
<from uri="direct:start"/>
<filter>
<xpath namespacesRef="myNamespaces">/c:number = 55</xpath>
<to uri="mock:result"/>
</filter>
</route>
</camel>
----
YAML::
+
[source,yaml]
----
- beans:
- name: myNamespaces
type: org.apache.camel.support.builder.Namespaces
properties:
namespaces[c]: "http://acme.com/cheese"
namespaces[w]: "http://acme.com/wine"
- route:
from:
uri: "direct:start"
steps:
- filter:
expression:
xpath:
expression: "/c:number = 55"
namespacesRef: "myNamespaces"
steps:
- to: "mock:result"
----
====
Each prefix is configured as a `namespaces[prefix]` property on the bean, with the namespace
URI as the value.
If an expression declares namespaces inline as well, then the inline namespaces win and
`namespacesRef` is ignored.
The `namespacesRef` option is also available on the xref:xquery-language.adoc[XQuery] and
xref:xtokenize-language.adoc[XML Tokenize] languages.
== Variables
Variables in XPath are defined in different namespaces.
The default
namespace is `\http://camel.apache.org/schema/spring`.
[width="100%",cols="10%,10%,10%,70%",options="header",]
|===
|Namespace URI |Local part |Type |Description
|http://camel.apache.org/xml/in/[http://camel.apache.org/xml/in/] |in |Message |the message
|http://camel.apache.org/xml/out/[http://camel.apache.org/xml/out/] |out |Message |*deprecated* the output message (do not use)
|http://camel.apache.org/xml/function/[http://camel.apache.org/xml/function/] |functions |Object |Additional functions
|http://camel.apache.org/xml/variables/environment-variables[http://camel.apache.org/xml/variables/environment-variables] |env |Object |OS environment variables
|http://camel.apache.org/xml/variables/system-properties[http://camel.apache.org/xml/variables/system-properties] |system |Object |Java System properties
|http://camel.apache.org/xml/variables/exchange-property[http://camel.apache.org/xml/variables/exchange-property] | | Object |the exchange property
|===
Camel will resolve variables according to either:
* namespace given
* no namespace given
=== Namespace given
If the namespace is given, then Camel is instructed exactly what to
return. However, when resolving Camel will try to
resolve a header with the given local part first, and return it. If the
local part has the value *body,* then the body is returned instead.
=== No namespace given
If there is no namespace given, then Camel resolves only based on the
local part. Camel will try to resolve a variable in the following steps:
* from `variables` that has been set using the `variable(name, value)` fluent builder
* from `message.in.header` if there is a header with the given key
* from `exchange.properties` if there is a property with the given key
* from `exchange.variables` if there is a variable with the given key
==== Example of using variables, header and body in XPath expression
You can combine headers, properties, body and variables in an XPath expression as shown in the example below:
The variables and the header are converted to a `Document` (`resultType`), so XPath can navigate them:
[tabs]
====
Java::
+
[source,java]
----
from("timer:java?period=1000&repeatCount=1")
.setBody()
.simple("<dummy>YES</dummy>")
.setVariable("Foo", simple("<hello><id>123</id></hello>", Document.class))
.setVariable("Bar", simple("<holla><id>123</id></holla>", Document.class))
.setHeader("Baz", simple("<hallo><id>123</id></hallo>", Document.class))
.choice()
.when(xpath("($Foo/hello/id = $Bar/holla/id) and /dummy='YES' and $Baz/hallo/id=123"))
.log("EQUAL")
.otherwise()
.log("DIFFERENT")
.end();
----
XML::
+
[source,xml]
----
<route>
<from uri="timer:java?period=1000&amp;repeatCount=1"/>
<setBody>
<simple>&lt;dummy&gt;YES&lt;/dummy&gt;</simple>
</setBody>
<setVariable name="Foo">
<simple resultType="org.w3c.dom.Document">&lt;hello&gt;&lt;id&gt;123&lt;/id&gt;&lt;/hello&gt;</simple>
</setVariable>
<setVariable name="Bar">
<simple resultType="org.w3c.dom.Document">&lt;holla&gt;&lt;id&gt;123&lt;/id&gt;&lt;/holla&gt;</simple>
</setVariable>
<setHeader name="Baz">
<simple resultType="org.w3c.dom.Document">&lt;hallo&gt;&lt;id&gt;123&lt;/id&gt;&lt;/hallo&gt;</simple>
</setHeader>
<choice>
<when>
<xpath>($Foo/hello/id = $Bar/holla/id) and /dummy='YES' and $Baz/hallo/id=123</xpath>
<log message="EQUAL"/>
</when>
<otherwise>
<log message="DIFFERENT"/>
</otherwise>
</choice>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: timer:java
parameters:
period: 1000
repeatCount: 1
steps:
- setBody:
expression:
simple:
expression: "<dummy>YES</dummy>"
- setVariable:
name: Foo
expression:
simple:
expression: "<hello><id>123</id></hello>"
resultType: org.w3c.dom.Document
- setVariable:
name: Bar
expression:
simple:
expression: "<holla><id>123</id></holla>"
resultType: org.w3c.dom.Document
- setHeader:
name: Baz
expression:
simple:
expression: "<hallo><id>123</id></hallo>"
resultType: org.w3c.dom.Document
- choice:
when:
- expression:
xpath:
expression: "($Foo/hello/id = $Bar/holla/id) and /dummy='YES' and $Baz/hallo/id=123"
steps:
- log:
message: EQUAL
otherwise:
steps:
- log:
message: DIFFERENT
----
====
== Functions
Camel adds the following XPath functions that can be used to access the
exchange:
[width="100%",cols="10%,10%,10%,70%",options="header",]
|===
|Function |Argument |Type |Description
|`in:body` |none |Object |Will return the message body.
|`in:header` |the header name |Object |Will return the message header.
|`out:body` |none |Object |*deprecated* Will return the out message body.
|`out:header` |the header name |Object |*deprecated* Will return the out message header.
|`function:properties` |key for property |String |To use a xref:manual:ROOT:using-propertyplaceholder.adoc[Property Placeholder].
|`function:simple` |simple expression |Object |To evaluate a xref:simple-language.adoc[Simple] language.
|===
CAUTION: `function:properties` and `function:simple` is not supported
when the return type is a `NodeSet`, such as when using with a xref:eips:split-eip.adoc[Split] EIP.
Here's an example showing some of these functions in use.
=== Functions example
If you prefer to configure your routes in your Spring
XML file, then you can use XPath expressions as follows
[tabs]
====
Java::
+
[source,java]
----
Namespaces ns = new Namespaces("foo", "http://example.com/person");
from("activemq:MyQueue")
.filter(xpath("/foo:person[@name='James']", ns))
.to("mqseries:SomeOtherQueue");
----
XML::
+
[source,xml]
----
<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">
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"
xmlns:foo="http://example.com/person">
<route>
<from uri="activemq:MyQueue"/>
<filter>
<xpath>/foo:person[@name='James']</xpath>
<to uri="mqseries:SomeOtherQueue"/>
</filter>
</route>
</camelContext>
</beans>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: activemq:MyQueue
steps:
- filter:
expression:
xpath:
expression: "/foo:person[@name='James']"
steps:
- to:
uri: mqseries:SomeOtherQueue
----
====
Notice how we can reuse the namespace prefixes, *foo* in this case, in
the XPath expression for easier namespace-based XPath expressions.
== Stream-based message bodies
If the message body is stream based, which means the input it receives
is submitted to Camel as a stream. That means you will only be able to
read the content of the stream *once*.
You often need to access the data multiple times when you use
xref:xpath-language.adoc[XPath] as a xref:xpath-language.adoc[Message Filter] or
Content-Based Router.
Then, you should use Stream Caching or convert the message body to
a `String` prior, which is safe to be re-read multiple times.
[tabs]
====
Java::
+
[source,java]
----
from("queue:foo")
.filter().xpath("//foo")
.to("queue:bar");
----
XML::
+
[source,xml]
----
<route>
<from uri="queue:foo"/>
<filter>
<xpath>//foo</xpath>
<to uri="queue:bar"/>
</filter>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: queue:foo
steps:
- filter:
expression:
xpath:
expression: //foo
steps:
- to:
uri: queue:bar
----
====
[tabs]
====
Java::
+
[source,java]
----
from("queue:foo")
.choice().when(xpath("//foo")).to("queue:bar")
.otherwise().to("queue:others");
----
XML::
+
[source,xml]
----
<route>
<from uri="queue:foo"/>
<choice>
<when>
<xpath>//foo</xpath>
<to uri="queue:bar"/>
</when>
<otherwise>
<to uri="queue:others"/>
</otherwise>
</choice>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: queue:foo
steps:
- choice:
when:
- expression:
xpath:
expression: //foo
steps:
- to:
uri: queue:bar
otherwise:
steps:
- to:
uri: queue:others
----
====
== Setting a result type
The XPath expression will return a result type using
native XML objects such as `org.w3c.dom.NodeList`. However, many times you
want a result type to be a `String`. To do this, you have to instruct the
XPath which result type to use.
In Java DSL:
._Java-only: XPath expression builder API_
[source,java]
----
xpath("/foo:person/@id", String.class)
----
In XML DSL you use the *resultType* attribute to provide the fully qualified classname.
[source,xml]
----
<xpath resultType="java.lang.String">/foo:person/@id</xpath>
----
TIP: Classes from `java.lang` can omit the FQN name, so you can use `resultType="String"`
Using `@XPath` annotation:
._Java-only: Java bean integration annotation_
[source,java]
----
@XPath(value = "concat('foo-',//order/name/)", resultType = String.class) String name)
----
Where we use the xpath function concat to prefix the order name with
`foo-`. In this case we have to specify that we want a `String` as result
type, so the concat function works.
== Using XPath on Headers
Some users may have XML stored in a header. To apply an XPath to a
header's value, you can do this by defining the `source` attribute with the `header:` prefix
(`variable:` and `property:` work the same way for an exchange variable or property).
[source,xml]
----
<xpath source="header:invoiceDetails">/invoice/@orderType = 'premium'</xpath>
----
And in Java DSL you specify the source with the fluent expression builder as shown:
._Java-only: XPath expression builder API_
[source,java]
----
expression().xpath("/invoice/@orderType = 'premium'").source("header:invoiceDetails").end()
----
== Example
Here is a simple example using an XPath expression as a predicate in a
xref:eips:filter-eip.adoc[Message Filter]:
[tabs]
====
Java::
+
[source,java]
----
from("direct:start")
.filter().xpath("/person[@name='James']")
.to("mock:result");
----
XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<filter>
<xpath>/person[@name='James']</xpath>
<to uri="mock:result"/>
</filter>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- filter:
expression:
xpath:
expression: "/person[@name='James']"
steps:
- to:
uri: mock:result
----
====
== Using namespaces
An XPath expression that uses a namespace prefix needs the namespace declared. In Java DSL use
`org.apache.camel.support.builder.Namespaces`, which is passed to `xpath` as the second parameter. In XML DSL
declare the prefix on a root element (`routes` or `route`), and in YAML DSL list the namespaces on the expression:
[tabs]
====
Java::
+
[source,java]
----
Namespaces ns = new Namespaces("c", "http://acme.com/cheese");
from("direct:start")
.filter(xpath("/c:person[@name='James']", ns))
.to("mock:result");
----
XML::
+
[source,xml]
----
<routes xmlns="http://camel.apache.org/schema/xml-io" xmlns:c="http://acme.com/cheese">
<route>
<from uri="direct:start"/>
<filter>
<xpath>/c:person[@name='James']</xpath>
<to uri="mock:result"/>
</filter>
</route>
</routes>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- filter:
expression:
xpath:
expression: "/c:person[@name='James']"
namespace:
- key: c
value: http://acme.com/cheese
steps:
- to:
uri: mock:result
----
====
Each namespace is a key=value pair, where the prefix is the key.
In the XPath expression then the namespace is used by its prefix, e.g.:
[source,xpath]
----
/c:person[@name='James']
----
The namespace builder supports adding multiple namespaces as shown:
._Java-only: Namespaces builder API_
[source,java]
----
Namespaces ns = new Namespaces("c", "http://acme.com/cheese")
.add("w", "http://acme.com/wine")
.add("b", "http://acme.com/beer");
----
When using namespaces in XML DSL, then it is different, as you set up the namespaces
in the XML root tag (or one of the `camelContext`, `routes`, `route` tags).
In the XML example below we use Spring XML where the namespace is declared in the root tag `beans`,
in the line with `xmlns:foo="http://example.com/person"`:
._XML-only:_
[source,xml]
----
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo="http://example.com/person"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
">
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<filter>
<xpath logNamespaces="true">/foo:person[@name='James']</xpath>
<to uri="mock:result"/>
</filter>
</route>
</camelContext>
</beans>
----
This namespace uses `foo` as prefix, so the `<xpath>` expression uses `foo:` to use this namespace.
== Using @XPath Annotation for Bean Integration
You can use xref:manual::bean-integration.adoc[Bean Integration] to invoke a
method on a bean and use various languages such as `@XPath` to extract a
value from the message and bind it to a method parameter.
NOTE: The default `@XPath` annotation has SOAP and XML namespaces available.
._Java-only: Java bean integration annotation_
[source,java]
----
public class Foo {
@Consume(uri = "activemq:my.queue")
public void doSomething(@XPath("/person/@name") String name, String xml) {
// process the inbound message here
}
}
----
== Using XPathBuilder without an Exchange
You can now use the `org.apache.camel.language.xpath.XPathBuilder` without the
need for an `Exchange`. This comes handy if you want
to use it as a helper to do custom XPath evaluations.
It requires that you pass in a `CamelContext`
since a lot of the moving parts inside the `XPathBuilder` requires access
to the Camel xref:manual:ROOT:type-converter.adoc[Type Converter]
and hence why `CamelContext` is needed.
For example, you can do something like this:
._Java-only: XPathBuilder API_
[source,java]
----
boolean matches = XPathBuilder.xpath("/foo/bar/@xyz").matches(context, "<foo><bar xyz='cheese'/></foo>"));
----
This will match the given predicate.
You can also evaluate as shown in the following three examples:
._Java-only: XPathBuilder API_
[source,java]
----
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);
----
Evaluating with a `String` result is a common requirement and make this simpler:
._Java-only: XPathBuilder API_
[source,java]
----
String name = XPathBuilder.xpath("foo/bar").evaluate(context, "<foo><bar>cheese</bar></foo>");
----
== Using Saxon with XPathBuilder
You need to add *camel-saxon* as dependency to your project.
It's now easier to use http://saxon.sourceforge.net/[Saxon] with the
XPathBuilder which can be done in several ways as shown below
* Using a custom XPathFactory
* Using ObjectModel
The easy one
=== Setting a custom XPathFactory using System Property
Camel now supports reading the
http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/xpath/XPathFactory.html#newInstance(java.lang.String)[JVM
system property `javax.xml.xpath.XPathFactory`] that can be used to set
a custom XPathFactory to use.
This unit test shows how this can be done to use Saxon instead:
Camel will log at `INFO` level if it uses a non-default `XPathFactory`
such as:
----
XPathBuilder INFO Using system property javax.xml.xpath.XPathFactory:http://saxon.sf.net/jaxp/xpath/om with value:
net.sf.saxon.xpath.XPathFactoryImpl when creating XPathFactory
----
To use Apache Xerces, you can configure the system property
----
-Djavax.xml.xpath.XPathFactory=org.apache.xpath.jaxp.XPathFactoryImpl
----
=== Enabling Saxon from XML DSL
Similarly to Java DSL, to enable Saxon from XML DSL, you have three
options:
Referring to a custom factory:
[source,xml]
----
<xpath factoryRef="saxonFactory" resultType="java.lang.String">current-dateTime()</xpath>
----
And declare a bean with the factory:
[source,xml]
----
<bean id="saxonFactory" class="net.sf.saxon.xpath.XPathFactoryImpl"/>
----
Specifying the object model:
[source,xml]
----
<xpath objectModel="http://saxon.sf.net/jaxp/xpath/om" resultType="java.lang.String">current-dateTime()</xpath>
----
And the recommended approach is to set `saxon=true` as shown:
[source,xml]
----
<xpath saxon="true" resultType="java.lang.String">current-dateTime()</xpath>
----
== Namespace auditing to aid debugging
Many XPath-related issues that users frequently face are
linked to the usage of namespaces. You may have some misalignment
between the namespaces present in your message and those that your XPath
expression is aware of or referencing. XPath predicates or expressions
that are unable to locate the XML elements and attributes due to
namespaces issues may look like _they are not working_, when in
reality all there is to it is a lack of namespace definition.
Namespaces in XML are completely necessary, and while we would love to
simplify their usage by implementing some magic or voodoo to wire
namespaces automatically, the truth is that any action down this path would
disagree with the standards and would greatly hinder interoperability.
Therefore, the utmost we can do is assist you in debugging such issues
by adding two new features to the XPath Expression Language and are thus
accessible from both predicates and expressions.
=== Logging the Namespace Context of your XPath expression/predicate
Every time a new XPath expression is created in the internal pool, Camel
will log the namespace context of the expression under the
`org.apache.camel.language.xpath.XPathBuilder` logger. Since Camel
represents Namespace Contexts in a hierarchical fashion (parent-child
relationships), the entire tree is output in a recursive manner with the
following format:
[source,text]
----
[me: {prefix -> namespace}, {prefix -> namespace}], [parent: [me: {prefix -> namespace}, {prefix -> namespace}], [parent: [me: {prefix -> namespace}]]]
----
Any of these options can be used to activate this logging:
* Enable TRACE logging on the
`org.apache.camel.language.xpath.XPathBuilder` logger, or some parent
logger such as `org.apache.camel` or the root logger
* Enable the `logNamespaces` option as indicated in the following section,
in which case the logging will occur on the INFO level
=== Auditing namespaces
Camel is able to discover and dump all namespaces present on every
incoming message before evaluating an XPath expression, providing all
the richness of information you need to help you analyze and pinpoint
possible namespace issues.
To achieve this, it in turn internally uses another specially tailored
XPath expression to extract all namespace mappings that appear in the
message, displaying the prefix and the full namespace URI(s) for each
mapping.
Some points to take into account:
* The implicit XML namespace
(`xmlns:xml="http://www.w3.org/XML/1998/namespace"`) is suppressed from
the output because it adds no value
* Default namespaces are listed under the `DEFAULT` keyword in the output
* Keep in mind that namespaces can be remapped under different scopes.
Think of a top-level `a` prefix which in inner elements can be assigned
a different namespace, or the default namespace changing in inner
scopes. For each discovered prefix, all associated URIs are listed.
You can enable this option in Java DSL and XML DSL:
Java DSL:
._Java-only: XPathBuilder API_
[source,java]
----
XPathBuilder.xpath("/foo:person/@id", String.class).logNamespaces()
----
XML DSL:
[source,xml]
----
<xpath logNamespaces="true" resultType="String">/foo:person/@id</xpath>
----
The result of the auditing will be appeared at the INFO level under the
`org.apache.camel.language.xpath.XPathBuilder` logger and will look like
the following:
----
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]}
----
== Loading script from external resource
You can externalize the script and have Apache Camel load it from a resource
such as `"classpath:"`, `"file:"`, or `"http:"`.
This is done using the following syntax: `"resource:scheme:location"`,
e.g., to refer to a file on the classpath you can do:
._Java-only: Java DSL expression syntax_
[source,java]
----
.setHeader("myHeader").xpath("resource:classpath:myxpath.txt", String.class)
----
== Transforming an XML message
For basic XML transformation where you have a fixed structure, you can represent with a combination of using
Camel simple and XPath language as:
Given this XML body
[source,xml]
----
<order id="123">
<item>Brake</item>
<first>scott</first>
<last>jackson</last>
<address>
<co>sweden</co>
<zip>12345</zip>
</address>
</order>
----
Which you want to transform to a smaller structure:
[source,xml]
----
<user>
<rool>123</rool>
<country>sweden</country>
<fullname>scott</fullname>
</user>
----
Then you can use simple as template and XPath to grab the content from the message payload, as shown in the route snippet below:
[tabs]
====
Java::
+
[source,java]
----
from("direct:start")
.transform().simple("""
<user>
<rool>${xpath(/order/@id)}</rool>
<country>${xpath(/order/address/co/text())}</country>
<fullname>${xpath(/order/first/text())}</fullname>
</user>""")
.to("mock:result");
----
XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<transform>
<simple><![CDATA[<user>
<rool>${xpath(/order/@id)}</rool>
<country>${xpath(/order/address/co/text())}</country>
<fullname>${xpath(/order/first/text())}</fullname>
</user>]]></simple>
</transform>
<to uri="mock:result"/>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- transform:
simple: |
<user>
<rool>${xpath(/order/@id)}</rool>
<country>${xpath(/order/address/co/text())}</country>
<fullname>${xpath(/order/first/text())}</fullname>
</user>
- to:
uri: mock:result
----
====
Notice how we use `${xpath(exp}` syntax in the simple template to use xpath that will be evaluated on the message body,
to extract the content to be used in the output (see previous for output).
Since the simple language can output anything, you can also use this to output in plain text or JSON, etc.
[tabs]
====
Java::
+
[source,java]
----
from("direct:start")
.transform().simple("The order ${xpath(/order/@id)} is being shipped to ${xpath(/order/address/co/text())}")
.to("mock:result");
----
XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<transform>
<simple>The order ${xpath(/order/@id)} is being shipped to ${xpath(/order/address/co/text())}</simple>
</transform>
<to uri="mock:result"/>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- transform:
simple: "The order ${xpath(/order/@id)} is being shipped to ${xpath(/order/address/co/text())}"
- to:
uri: mock:result
----
====
== Dependencies
To use XPath in your camel routes, you need to add the dependency on
*camel-xpath*, which implements the XPath language.
If you use Maven, you could add the following to your `pom.xml`,
substituting the version number for the latest & greatest release.
[source,xml]
----
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-xpath</artifactId>
<version>x.x.x</version>
</dependency>
----