You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2012/01/04 09:14:55 UTC

svn commit: r1227069 - in /camel/trunk: camel-core/src/main/java/org/apache/camel/builder/xml/ camel-core/src/main/java/org/apache/camel/language/xpath/ camel-core/src/main/java/org/apache/camel/model/language/ camel-core/src/test/java/org/apache/camel...

Author: davsclaus
Date: Wed Jan  4 08:14:54 2012
New Revision: 1227069

URL: http://svn.apache.org/viewvc?rev=1227069&view=rev
Log:
CAMEL-4799: XPath XML DSL now have more options to configure xpath engine. Added traceNamespaces option to TRACE log all namespaces in messages to aid during xpath evaluation issues for Camel end users. As a very typical problem is wrong/missing namespace in the XPath expression.

Added:
    camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/
    camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/
    camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderTest.java
    camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.java
    camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageTest.java
    camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/
    camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/
    camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderTest.xml
    camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.xml
    camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageTest.xml
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/DefaultNamespaceContext.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/XPathExpression.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTransformTest.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/DefaultNamespaceContext.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/DefaultNamespaceContext.java?rev=1227069&r1=1227068&r2=1227069&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/DefaultNamespaceContext.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/DefaultNamespaceContext.java Wed Jan  4 08:14:54 2012
@@ -20,8 +20,8 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
-
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.xpath.XPathFactory;
 
@@ -31,8 +31,6 @@ import org.apache.camel.util.CastUtils;
 /**
  * An implementation of {@link NamespaceContext} which uses a simple Map where
  * the keys are the prefixes and the values are the URIs
- *
- * @version 
  */
 public class DefaultNamespaceContext implements NamespaceContext, NamespaceAware {
 
@@ -73,7 +71,7 @@ public class DefaultNamespaceContext imp
         for (Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator(); iter.hasNext();) {
             Map.Entry<String, String> entry = iter.next();
             if (namespaceURI.equals(entry.getValue())) {
-                return (String) entry.getKey();
+                return entry.getKey();
             }
         }
         if (parent != null) {
@@ -102,4 +100,30 @@ public class DefaultNamespaceContext imp
     public void setNamespaces(Map<String, String> namespaces) {
         map.putAll(namespaces);
     }
+
+    /**
+     * toString() implementation that outputs the namespace mappings with the following format: "[me: {prefix -> value}, {prefix -> value}], [parent: {prefix -> value}, {prefix -> value}].
+     * Recurses up the parent's chain.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("[me: ");
+        for (Entry<String, String> nsEntry : map.entrySet()) {
+            sb.append("{" + nsEntry.getKey() + " -> " + nsEntry.getValue() + "},");
+        }
+        if (!map.isEmpty()) {
+            // remove the last comma
+            sb.deleteCharAt(sb.length() - 1);
+        }
+        sb.append("]");
+
+        // Get the parent's namespace mappings
+        if (parent != null) {
+            sb.append(", [parent: ");
+            sb.append(parent.toString());
+            sb.append("]");
+        }
+        return sb.toString();
+    }
+
 }

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java?rev=1227069&r1=1227068&r2=1227069&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java Wed Jan  4 08:14:54 2012
@@ -19,6 +19,9 @@ package org.apache.camel.builder.xml;
 import java.io.File;
 import java.io.InputStream;
 import java.io.StringReader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -77,14 +80,16 @@ import static org.apache.camel.builder.x
  * This implementation is thread safe by using thread locals and pooling to allow concurrency
  *
  * @see XPathConstants#NODESET
- *
- * @version 
  */
 public class XPathBuilder implements Expression, Predicate, NamespaceAware, Service {
     private static final transient Logger LOG = LoggerFactory.getLogger(XPathBuilder.class);
+    private static final String SAXON_OBJECT_MODEL_URI = "http://saxon.sf.net/jaxp/xpath/om";
+    private static final String OBTAIN_ALL_NS_XPATH = "//*/namespace::*";
+
     private static XPathFactory defaultXPathFactory;
 
     private final Queue<XPathExpression> pool = new ConcurrentLinkedQueue<XPathExpression>();
+    private final Queue<XPathExpression> poolTraceNamespaces = new ConcurrentLinkedQueue<XPathExpression>();
     private final String text;
     private final ThreadLocal<MessageVariableResolver> variableResolver = new ThreadLocal<MessageVariableResolver>();
     private final ThreadLocal<Exchange> exchange = new ThreadLocal<Exchange>();
@@ -98,6 +103,7 @@ public class XPathBuilder implements Exp
     private QName resultQName = XPathConstants.NODESET;
     private String objectModelUri;
     private DefaultNamespaceContext namespaceContext;
+    private boolean traceNamespaces;
     private XPathFunctionResolver functionResolver;
     private XPathFunction bodyFunction;
     private XPathFunction headerFunction;
@@ -145,7 +151,7 @@ public class XPathBuilder implements Exp
      * Matches the given xpath using the provided body.
      *
      * @param context the camel context
-     * @param body the body
+     * @param body    the body
      * @return <tt>true</tt> if matches, <tt>false</tt> otherwise
      */
     public boolean matches(CamelContext context, Object body) {
@@ -167,8 +173,8 @@ public class XPathBuilder implements Exp
      * Evaluates the given xpath using the provided body.
      *
      * @param context the camel context
-     * @param body the body
-     * @param type the type to return
+     * @param body    the body
+     * @param type    the type to return
      * @return result of the evaluation
      */
     public <T> T evaluate(CamelContext context, Object body, Class<T> type) {
@@ -190,7 +196,7 @@ public class XPathBuilder implements Exp
      * Evaluates the given xpath using the provided body as a String return type.
      *
      * @param context the camel context
-     * @param body the body
+     * @param body    the body
      * @return result of the evaluation
      */
     public String evaluate(CamelContext context, Object body) {
@@ -278,6 +284,9 @@ public class XPathBuilder implements Exp
      * @return the current builder
      */
     public XPathBuilder objectModel(String uri) {
+        // TODO: Careful! Setting the Object Model URI this way will set the *Default* XPath Factory, which since is a static field,
+        // will set the XPath Factory system-wide. Decide what to do, as changing this behaviour can break compatibility. Provided the setObjectModel which changes
+        // this instance's XPath Factory rather than the static field
         this.objectModelUri = uri;
         return this;
     }
@@ -289,7 +298,7 @@ public class XPathBuilder implements Exp
      * @return the current builder
      */
     public XPathBuilder saxon() {
-        this.objectModelUri = "http://saxon.sf.net/jaxp/xpath/om";
+        this.objectModelUri = SAXON_OBJECT_MODEL_URI;
         return this;
     }
 
@@ -309,8 +318,8 @@ public class XPathBuilder implements Exp
      * prefix can be used in XPath expressions
      *
      * @param prefix is the namespace prefix that can be used in the XPath
-     *                expressions
-     * @param uri is the namespace URI to which the prefix refers
+     *               expressions
+     * @param uri    is the namespace URI to which the prefix refers
      * @return the current builder
      */
     public XPathBuilder namespace(String prefix, String uri) {
@@ -323,7 +332,7 @@ public class XPathBuilder implements Exp
      * prefixes can be used in XPath expressions
      *
      * @param namespaces is namespaces object that should be used in the
-     *                      XPath expression
+     *                   XPath expression
      * @return the current builder
      */
     public XPathBuilder namespaces(Namespaces namespaces) {
@@ -334,6 +343,10 @@ public class XPathBuilder implements Exp
     /**
      * Registers a variable (in the global namespace) which can be referred to
      * from XPath expressions
+     *
+     * @param name  name of variable
+     * @param value value of variable
+     * @return the current builder
      */
     public XPathBuilder variable(String name, Object value) {
         getVariableResolver().addVariable(name, value);
@@ -370,6 +383,25 @@ public class XPathBuilder implements Exp
         return this;
     }
 
+    /**
+     * Activates trace logging of all discovered namespaces in the message - to simplify debugging namespace-related issues
+     * <p/>
+     * Namespaces are printed in Hashmap style <code>{xmlns:prefix=[namespaceURI], xmlns:prefix=[namespaceURI]}</code>.
+     * <p/>
+     * The implicit XML namespace is omitted (http://www.w3.org/XML/1998/namespace).
+     * XML allows for namespace prefixes to be redefined/overridden due to hierarchical scoping, i.e. prefix abc can be mapped to http://abc.com,
+     * and deeper in the document it can be mapped to http://def.com. When two prefixes are detected which are equal but are mapped to different
+     * namespace URIs, Camel will show all namespaces URIs it is mapped to in an array-style.
+     * <p/>
+     * This feature is disabled by default.
+     *
+     * @return the current builder.
+     */
+    public XPathBuilder traceNamespaces() {
+        setTraceNamespaces(true);
+        return this;
+    }
+
     // Properties
     // -------------------------------------------------------------------------
     public XPathFactory getXPathFactory() throws XPathFactoryConfigurationException {
@@ -377,6 +409,12 @@ public class XPathBuilder implements Exp
             return xpathFactory;
         }
 
+        if (objectModelUri != null) {
+            xpathFactory = XPathFactory.newInstance(objectModelUri);
+            LOG.info("Using objectModelUri " + objectModelUri + " when created XPathFactory {}", defaultXPathFactory);
+            return xpathFactory;
+        }
+
         if (defaultXPathFactory == null) {
             initDefaultXPathFactory();
         }
@@ -496,7 +534,7 @@ public class XPathBuilder implements Exp
 
     public XPathFunction getOutHeaderFunction() {
         if (outHeaderFunction == null) {
-            outHeaderFunction = new XPathFunction() {                
+            outHeaderFunction = new XPathFunction() {
                 public Object evaluate(List list) throws XPathFunctionException {
                     if (exchange.get() != null && !list.isEmpty()) {
                         Object value = list.get(0);
@@ -588,6 +626,30 @@ public class XPathBuilder implements Exp
         }
     }
 
+    public void setTraceNamespaces(boolean traceNamespaces) {
+        this.traceNamespaces = traceNamespaces;
+    }
+
+    public boolean isTraceNamespaces() {
+        return traceNamespaces;
+    }
+
+    public String getObjectModelUri() {
+        return objectModelUri;
+    }
+
+    /**
+     * Enables Saxon on this particular XPath expression, as {@link #saxon()} sets the default static XPathFactory which may have already been initialised
+     * by previous XPath expressions
+     */
+    public void enableSaxon() {
+        this.setObjectModelUri(SAXON_OBJECT_MODEL_URI);
+    }
+
+    public void setObjectModelUri(String objectModelUri) {
+        this.objectModelUri = objectModelUri;
+    }
+
     // Implementation methods
     // -------------------------------------------------------------------------
 
@@ -619,6 +681,9 @@ public class XPathBuilder implements Exp
             LOG.trace("Acquired XPathExpression from pool");
         }
         try {
+            if (traceNamespaces && LOG.isTraceEnabled()) {
+                traceNamespaces(exchange);
+            }
             return doInEvaluateAs(xpathExpression, exchange, resultQName);
         } finally {
             // release it back to the pool
@@ -627,6 +692,73 @@ public class XPathBuilder implements Exp
         }
     }
 
+    private void traceNamespaces(Exchange exchange) {
+        InputStream is = null;
+        NodeList answer = null;
+        XPathExpression xpathExpression = null;
+
+        try {
+            xpathExpression = poolTraceNamespaces.poll();
+            if (xpathExpression == null) {
+                xpathExpression = createTraceNamespaceExpression();
+            }
+
+            // prepare the input
+            Object document;
+            if (isInputStreamNeeded(exchange)) {
+                is = exchange.getIn().getBody(InputStream.class);
+                document = getDocument(exchange, is);
+            } else {
+                Object body = exchange.getIn().getBody();
+                document = getDocument(exchange, body);
+            }
+            // fetch all namespaces
+            if (document instanceof InputSource) {
+                InputSource inputSource = (InputSource) document;
+                answer = (NodeList) xpathExpression.evaluate(inputSource, XPathConstants.NODESET);
+            } else if (document instanceof DOMSource) {
+                DOMSource source = (DOMSource) document;
+                answer = (NodeList) xpathExpression.evaluate(source.getNode(), XPathConstants.NODESET);
+            } else {
+                answer = (NodeList) xpathExpression.evaluate(document, XPathConstants.NODESET);
+            }
+        } catch (Exception e) {
+            LOG.trace("Unable to trace discovered namespaces in XPath expression", e);
+        } finally {
+            // IOHelper can handle if is is null
+            IOHelper.close(is);
+            poolTraceNamespaces.add(xpathExpression);
+        }
+
+        if (answer != null) {
+            logDiscoveredNamespaces(answer);
+        }
+    }
+
+    private void logDiscoveredNamespaces(NodeList namespaces) {
+        HashMap<String, HashSet<String>> map = new LinkedHashMap<String, HashSet<String>>();
+        for (int i = 0; i < namespaces.getLength(); i++) {
+            Node n = namespaces.item(i);
+            if (n.getNodeName().equals("xmlns:xml")) {
+                // skip the implicit XML namespace as it provides no value
+                continue;
+            }
+
+            String prefix = namespaces.item(i).getNodeName();
+            if (prefix.equals("xmlns")) {
+                prefix = "DEFAULT";
+            }
+
+            // add to map
+            if (!map.containsKey(prefix)) {
+                map.put(prefix, new HashSet<String>());
+            }
+            map.get(prefix).add(namespaces.item(i).getNodeValue());
+        }
+
+        LOG.trace("Namespaces discovered in message: {}.", map);
+    }
+
     protected Object doInEvaluateAs(XPathExpression xpathExpression, Exchange exchange, QName resultQName) {
         LOG.trace("Evaluating exchange: {} as: {}", exchange, resultQName);
 
@@ -685,6 +817,9 @@ public class XPathBuilder implements Exp
         // XPathFactory is not thread safe
         XPath xPath = getXPathFactory().newXPath();
 
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Creating new XPath expression in pool. Namespaces on XPath expression: {}", getNamespaceContext().toString());
+        }
         xPath.setNamespaceContext(getNamespaceContext());
         xPath.setXPathVariableResolver(getVariableResolver());
 
@@ -696,6 +831,12 @@ public class XPathBuilder implements Exp
         return xPath.compile(text);
     }
 
+    protected synchronized XPathExpression createTraceNamespaceExpression() throws XPathFactoryConfigurationException, XPathExpressionException {
+        // XPathFactory is not thread safe
+        XPath xPath = getXPathFactory().newXPath();
+        return xPath.compile(OBTAIN_ALL_NS_XPATH);
+    }
+
     /**
      * Populate a number of standard prefixes if they are not already there
      */
@@ -840,6 +981,7 @@ public class XPathBuilder implements Exp
 
     public void stop() throws Exception {
         pool.clear();
+        poolTraceNamespaces.clear();
     }
 
     protected synchronized void initDefaultXPathFactory() throws XPathFactoryConfigurationException {

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java?rev=1227069&r1=1227068&r2=1227069&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/language/xpath/XPathLanguage.java Wed Jan  4 08:14:54 2012
@@ -17,6 +17,7 @@
 package org.apache.camel.language.xpath;
 
 import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFactory;
 
 import org.apache.camel.Expression;
 import org.apache.camel.IsSingleton;
@@ -26,11 +27,12 @@ import org.apache.camel.spi.Language;
 
 /**
  * XPath language.
- *
- * @version 
  */
 public class XPathLanguage implements Language, IsSingleton {
     private QName resultType;
+    private XPathFactory xpathFactory;
+    private Boolean useSaxon;
+    private String objectModelUri;
 
     public Predicate createPredicate(String expression) {
         XPathBuilder builder = XPathBuilder.xpath(expression);
@@ -52,10 +54,49 @@ public class XPathLanguage implements La
         this.resultType = resultType;
     }
 
+    public XPathFactory getXpathFactory() {
+        return xpathFactory;
+    }
+
+    public void setXpathFactory(XPathFactory xpathFactory) {
+        this.xpathFactory = xpathFactory;
+    }
+
+    public void setUseSaxon(Boolean useSaxon) {
+        this.useSaxon = useSaxon;
+    }
+
+    public Boolean getUseSaxon() {
+        return useSaxon;
+    }
+
+    public Boolean isUseSaxon() {
+        return useSaxon != null && useSaxon;
+    }
+
+    public String getObjectModelUri() {
+        return objectModelUri;
+    }
+
+    public void setObjectModelUri(String objectModelUri) {
+        this.objectModelUri = objectModelUri;
+    }
+
     protected void configureBuilder(XPathBuilder builder) {
         if (resultType != null) {
             builder.setResultQName(resultType);
         }
+
+        if (isUseSaxon()) {
+            builder.enableSaxon();
+        } else {
+            if (xpathFactory != null) {
+                builder.setXPathFactory(xpathFactory);
+            }
+            if (objectModelUri != null) {
+                builder.setObjectModelUri(objectModelUri);
+            }
+        }
     }
 
     public boolean isSingleton() {

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/XPathExpression.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/XPathExpression.java?rev=1227069&r1=1227068&r2=1227069&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/XPathExpression.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/XPathExpression.java Wed Jan  4 08:14:54 2012
@@ -21,24 +21,35 @@ import javax.xml.bind.annotation.XmlAcce
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.xpath.XPathFactory;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
+import org.apache.camel.builder.xml.XPathBuilder;
 import org.apache.camel.util.ObjectHelper;
 
 /**
  * For XPath expressions and predicates
- *
- * @version 
  */
 @XmlRootElement(name = "xpath")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class XPathExpression extends NamespaceAwareExpression {
     @XmlAttribute(name = "resultType")
     private String resultTypeName;
+    @XmlAttribute(name = "saxon")
+    private Boolean saxon;
+    @XmlAttribute(name = "factoryRef")
+    private String factoryRef;
+    @XmlAttribute(name = "objectModel")
+    private String objectModel;
+    @XmlAttribute(name = "traceNamespaces")
+    private Boolean traceNamespaces;
+
     @XmlTransient
     private Class<?> resultType;
+    @XmlTransient
+    private XPathFactory xpathFactory;
 
     public XPathExpression() {
     }
@@ -71,6 +82,46 @@ public class XPathExpression extends Nam
         this.resultTypeName = resultTypeName;
     }
 
+    public void setSaxon(Boolean saxon) {
+        this.saxon = saxon;
+    }
+
+    public Boolean getSaxon() {
+        return saxon;
+    }
+
+    public boolean isSaxon() {
+        return saxon != null && saxon;
+    }
+
+    public void setFactoryRef(String factoryRef) {
+        this.factoryRef = factoryRef;
+    }
+
+    public String getFactoryRef() {
+        return factoryRef;
+    }
+
+    public void setObjectModel(String objectModel) {
+        this.objectModel = objectModel;
+    }
+
+    public String getObjectModel() {
+        return objectModel;
+    }
+
+    public void setTraceNamespaces(Boolean traceNamespaces) {
+        this.traceNamespaces = traceNamespaces;
+    }
+
+    public Boolean getTraceNamespaces() {
+        return traceNamespaces;
+    }
+
+    public boolean isTraceNamespaces() {
+        return traceNamespaces != null && traceNamespaces;
+    }
+
     @Override
     public Expression createExpression(CamelContext camelContext) {
         if (resultType == null && resultTypeName != null) {
@@ -80,23 +131,72 @@ public class XPathExpression extends Nam
                 throw ObjectHelper.wrapRuntimeCamelException(e);
             }
         }
-
+        resolveXPathFactory(camelContext);
         return super.createExpression(camelContext);
     }
 
     @Override
+    public Predicate createPredicate(CamelContext camelContext) {
+        resolveXPathFactory(camelContext);
+        return super.createPredicate(camelContext);
+    }
+
+    @Override
     protected void configureExpression(CamelContext camelContext, Expression expression) {
-        super.configureExpression(camelContext, expression);
         if (resultType != null) {
             setProperty(expression, "resultType", resultType);
         }
+        if (isSaxon()) {
+            ObjectHelper.cast(XPathBuilder.class, expression).enableSaxon();
+        }
+        if (xpathFactory != null) {
+            setProperty(expression, "xPathFactory", xpathFactory);
+        }
+        if (objectModel != null) {
+            setProperty(expression, "objectModelUri", objectModel);
+        }
+        if (isTraceNamespaces()) {
+            ObjectHelper.cast(XPathBuilder.class, expression).setTraceNamespaces(true);
+        }
+        // moved the super configuration to the bottom so that the namespace init picks up the newly set XPath Factory
+        super.configureExpression(camelContext, expression);
+
     }
 
     @Override
     protected void configurePredicate(CamelContext camelContext, Predicate predicate) {
-        super.configurePredicate(camelContext, predicate);
         if (resultType != null) {
             setProperty(predicate, "resultType", resultType);
         }
+        if (isSaxon()) {
+            ObjectHelper.cast(XPathBuilder.class, predicate).enableSaxon();
+        }
+        if (xpathFactory != null) {
+            setProperty(predicate, "xPathFactory", xpathFactory);
+        }
+        if (objectModel != null) {
+            setProperty(predicate, "objectModelUri", objectModel);
+        }
+        if (isTraceNamespaces()) {
+            ObjectHelper.cast(XPathBuilder.class, predicate).setTraceNamespaces(true);
+        }
+        // moved the super configuration to the bottom so that the namespace init picks up the newly set XPath Factory
+        super.configurePredicate(camelContext, predicate);
+    }
+
+    private void resolveXPathFactory(CamelContext camelContext) {
+        // Factory and Object Model can be set simultaneously. The underlying XPathBuilder allows for setting Saxon too, as it is simply a shortcut for
+        // setting the appropriate Object Model, it is not wise to allow this in XML because the order of invocation of the setters by JAXB may cause undeterministic behaviour 
+        if ((ObjectHelper.isNotEmpty(factoryRef) || ObjectHelper.isNotEmpty(objectModel)) && (saxon != null)) {
+            throw new IllegalArgumentException("The saxon attribute cannot be set on the xpath element if any of the following is also set: factory, objectModel" + this);
+        }
+
+        // Validate the factory class
+        if (ObjectHelper.isNotEmpty(factoryRef)) {
+            xpathFactory = camelContext.getRegistry().lookup(factoryRef, XPathFactory.class);
+            if (xpathFactory == null) {
+                throw new IllegalArgumentException("The provided XPath Factory is invalid; either it cannot be resolved or it is not an XPathFactory instance");
+            }
+        }
     }
 }

Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTransformTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTransformTest.java?rev=1227069&r1=1227068&r2=1227069&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTransformTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTransformTest.java Wed Jan  4 08:14:54 2012
@@ -16,14 +16,29 @@
  */
 package org.apache.camel.builder.xml;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 
 import org.apache.camel.ContextTestSupport;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.slf4j.Logger;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.contains;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
 
 
 /**
- * @version 
+ * @version
  */
 public class XPathTransformTest extends ContextTestSupport {
 
@@ -41,4 +56,69 @@ public class XPathTransformTest extends 
         String out = context.getTypeConverter().convertTo(String.class, doc);
         assertEquals("<root><firstname>Servicemix</firstname><lastname>Camel</lastname></root>", out);
     }
+
+    public void testXPathNamespaceTracingEnabledJavaDSL() throws Exception {
+        Logger l = createNiceMock(Logger.class);
+
+        expect(l.isTraceEnabled()).andReturn(true).anyTimes();
+
+        l.trace(contains("Namespaces discovered in message"), anyObject());
+        expectLastCall().times(1);
+        replay(l);
+
+        String body = "<aRoot xmlns:nsa=\"http://namespacec.net\"><nsa:a xmlns:nsa=\"http://namespacea.net\">Hello|there|Camel</nsa:a>"
+                + "<nsb:a xmlns:nsb=\"http://namespaceb.net\">Hello|there|Camel</nsb:a><nsb:a xmlns:nsb=\"http://namespaceb.net\">Hello|there|Camel</nsb:a>"
+                + "<a xmlns=\"http://defaultNamespace.net\">Hello|there|Camel</a><a>Hello|there|Camel</a></aRoot>"; 
+        Document doc = context.getTypeConverter().convertTo(Document.class, body);
+        Field logField = XPathBuilder.class.getDeclaredField("LOG");
+        logField.setAccessible(true);
+
+        Field modifiers = Field.class.getDeclaredField("modifiers");
+        modifiers.setAccessible(true);
+        modifiers.setInt(logField, logField.getModifiers() & ~Modifier.FINAL);
+
+        logField.set(null, l);
+
+        NodeList list = XPathBuilder.xpath("//*", NodeList.class).traceNamespaces().evaluate(context, doc, NodeList.class);
+        assertNotNull(list);
+
+        verify(l);
+    }
+
+    public void testXPathNamespaceTracingDisabledJavaDSL() throws Exception {
+        Logger l = createNiceMock(Logger.class);
+
+        expect(l.isTraceEnabled()).andReturn(true).anyTimes();
+
+        Capture<String> captures = new Capture<String>(CaptureType.ALL);
+        l.trace(capture(captures), anyObject());
+        expectLastCall().anyTimes();
+
+        replay(l);
+
+        String body = "<aRoot xmlns:nsa=\"http://namespacec.net\"><nsa:a xmlns:nsa=\"http://namespacea.net\">Hello|there|Camel</nsa:a>"
+                + "<nsb:a xmlns:nsb=\"http://namespaceb.net\">Hello|there|Camel</nsb:a><nsb:a xmlns:nsb=\"http://namespaceb.net\">Hello|there|Camel</nsb:a>"
+                + "<a xmlns=\"http://defaultNamespace.net\">Hello|there|Camel</a><a>Hello|there|Camel</a></aRoot>";
+        Document doc = context.getTypeConverter().convertTo(Document.class, body);
+        Field logField = XPathBuilder.class.getDeclaredField("LOG");
+        logField.setAccessible(true);
+
+        Field modifiers = Field.class.getDeclaredField("modifiers");
+        modifiers.setAccessible(true);
+        modifiers.setInt(logField, logField.getModifiers() & ~Modifier.FINAL);
+
+        logField.set(null, l);
+
+        NodeList list = XPathBuilder.xpath("//*", NodeList.class).evaluate(context, doc, NodeList.class);
+        assertNotNull(list);
+
+        verify(l);
+
+        for (String c : captures.getValues()) {
+            if (c.contains("Namespaces discovered in message")) {
+                throw new AssertionError("Did not expect LOG.trace with 'Namespaces discovered in message'");
+            }
+        }
+    }
+
 }

Added: camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderTest.java?rev=1227069&view=auto
==============================================================================
--- camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderTest.java (added)
+++ camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathHeaderTest.java Wed Jan  4 08:14:54 2012
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.xpath;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelSpringTestSupport;
+import org.junit.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class XPathHeaderTest extends CamelSpringTestSupport {
+
+    @Test
+    public void testChoiceWithHeaderSelectCamel() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:camel");
+        mock.expectedBodiesReceived("<name>King</name>");
+        mock.expectedHeaderReceived("type", "Camel");
+
+        template.sendBodyAndHeader("direct:in", "<name>King</name>", "type", "Camel");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testChoiceWithNoHeaderSelectDonkey() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:donkey");
+        mock.expectedBodiesReceived("<name>Kong</name>");
+
+        template.sendBody("direct:in", "<name>Kong</name>");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testChoiceWithNoHeaderSelectOther() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:other");
+        mock.expectedBodiesReceived("<name>Other</name>");
+
+        template.sendBody("direct:in", "<name>Other</name>");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected AbstractXmlApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/language/xpath/XPathHeaderTest.xml");
+    }
+
+}

Added: camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.java?rev=1227069&view=auto
==============================================================================
--- camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.java (added)
+++ camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.java Wed Jan  4 08:14:54 2012
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.xpath;
+
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelSpringTestSupport;
+import org.apache.camel.test.junit4.TestSupport;
+import org.junit.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Tests that verify the usage of default settings in the XPath language by declaring a bean called xpath in the registry
+ */
+public class XPathLanguageDefaultSettingsTest extends CamelSpringTestSupport {
+
+    private static final String KEY = XPathFactory.DEFAULT_PROPERTY_NAME + ":" + "http://java.sun.com/jaxp/xpath/dom";
+    private boolean jvmAdequate = true;
+    private String oldPropertyValue;
+
+    @Override
+    public void setUp() throws Exception {
+        if (!TestSupport.isJavaVendor("ibm")) {
+            // Force using the JAXP default implementation, because having Saxon in the classpath will automatically make JAXP use it
+            // because of Service Provider discovery (this does not happen in OSGi because the META-INF/services package is not exported
+            oldPropertyValue = System.setProperty(KEY, "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl");
+        } else {
+            jvmAdequate = false;
+        }
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (oldPropertyValue != null) {
+            System.setProperty(KEY, oldPropertyValue);
+        } else {
+            System.clearProperty(KEY);
+        }
+        super.tearDown();
+    }
+
+    @Override
+    protected AbstractXmlApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.xml");
+    }
+
+    @Test
+    public void testSpringDSLXPathLanguageDefaultSettings() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpointResult = getMockEndpoint("mock:testDefaultXPathSettingsResult");
+        MockEndpoint mockEndpointException = getMockEndpoint("mock:testDefaultXPathSettingsResultException");
+
+        mockEndpointResult.expectedMessageCount(1);
+        mockEndpointException.expectedMessageCount(0);
+
+        template.sendBody("seda:testDefaultXPathSettings", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
\ No newline at end of file

Added: camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageTest.java?rev=1227069&view=auto
==============================================================================
--- camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageTest.java (added)
+++ camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/language/xpath/XPathLanguageTest.java Wed Jan  4 08:14:54 2012
@@ -0,0 +1,157 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.xpath;
+
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelSpringTestSupport;
+import org.apache.camel.test.junit4.TestSupport;
+import org.junit.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ *
+ */
+public class XPathLanguageTest extends CamelSpringTestSupport {
+
+    private static final String KEY = XPathFactory.DEFAULT_PROPERTY_NAME + ":" + "http://java.sun.com/jaxp/xpath/dom";
+    private boolean jvmAdequate = true;
+    private String oldPropertyValue;
+
+    @Override
+    public void setUp() throws Exception {
+        if (!TestSupport.isJavaVendor("ibm")) {
+            // Force using the JAXP default implementation, because having Saxon in the classpath will automatically make JAXP use it
+            // because of Service Provider discovery (this does not happen in OSGi because the META-INF/services package is not exported
+            oldPropertyValue = System.setProperty(KEY, "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl");
+        } else {
+            jvmAdequate = false;
+        }
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (oldPropertyValue != null) {
+            System.setProperty(KEY, oldPropertyValue);
+        } else {
+            System.clearProperty(KEY);
+        }
+        super.tearDown();
+    }
+
+    protected AbstractXmlApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/language/xpath/XPathLanguageTest.xml");
+    }
+
+    @Test
+    public void testSpringDSLXPathSaxonFlag() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:testSaxonWithFlagResult");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("seda:testSaxonWithFlag", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+        Exchange received = mockEndpoint.getExchanges().get(0);
+        Object body = received.getIn().getBody();
+        assertEquals("Hello", body);
+    }
+
+    @Test
+    public void testSpringDSLXPathFactory() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:testSaxonWithFactoryResult");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("seda:testSaxonWithFactory", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+        Exchange received = mockEndpoint.getExchanges().get(0);
+        Object body = received.getIn().getBody();
+        assertEquals("Hello", body);
+    }
+
+    @Test
+    public void testSpringDSLXPathObjectModel() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:testSaxonWithObjectModelResult");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("seda:testSaxonWithObjectModel", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+        Exchange received = mockEndpoint.getExchanges().get(0);
+        Object body = received.getIn().getBody();
+        assertEquals("Hello", body);
+    }
+
+    @Test
+    public void testSpringDSLXPathSaxonFlagPredicate() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:testSaxonWithFlagResultPredicate");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("seda:testSaxonWithFlagPredicate", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSpringDSLXPathFactoryPredicate() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:testSaxonWithFactoryResultPredicate");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("seda:testSaxonWithFactoryPredicate", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSpringDSLXPathObjectModelPredicate() throws Exception {
+        if (!jvmAdequate) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:testSaxonWithObjectModelResultPredicate");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("seda:testSaxonWithObjectModelPredicate", "<a>Hello|there|Camel</a>");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
\ No newline at end of file

Added: camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderTest.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderTest.xml?rev=1227069&view=auto
==============================================================================
--- camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderTest.xml (added)
+++ camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathHeaderTest.xml Wed Jan  4 08:14:54 2012
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<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 xmlns="http://camel.apache.org/schema/spring">
+    <route>
+      <from uri="direct:in"/>
+      <choice>
+        <when>
+          <xpath>$type = 'Camel'</xpath>
+          <to uri="mock:camel"/>
+        </when>
+        <when>
+          <xpath>//name = 'Kong'</xpath>
+          <to uri="mock:donkey"/>
+        </when>
+        <otherwise>
+          <to uri="mock:other"/>
+        </otherwise>
+      </choice>
+    </route>
+  </camelContext>
+
+</beans>

Added: camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.xml?rev=1227069&view=auto
==============================================================================
--- camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.xml (added)
+++ camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageDefaultSettingsTest.xml Wed Jan  4 08:14:54 2012
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<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 name="saxonFactory" class="net.sf.saxon.xpath.XPathFactoryImpl"/>
+
+  <bean name="xpath" class="org.apache.camel.language.xpath.XPathLanguage">
+    <property name="useSaxon" value="true"/>
+  </bean>
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+    <route>
+      <from uri="seda:testDefaultXPathSettings"/>
+      <onException useOriginalMessage="true">
+        <exception>org.apache.camel.builder.xml.InvalidXPathExpression</exception>
+        <handled>
+          <constant>true</constant>
+        </handled>
+        <to uri="mock:testDefaultXPathSettingsResultException"/>
+      </onException>
+      <setBody>
+        <xpath resultType="java.lang.String">tokenize(a, '\|')</xpath>
+      </setBody>
+      <log message="Test default XPath Settings: ${body}"/>
+      <to uri="mock:testDefaultXPathSettingsResult"/>
+    </route>
+
+  </camelContext>
+
+</beans>

Added: camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageTest.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageTest.xml?rev=1227069&view=auto
==============================================================================
--- camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageTest.xml (added)
+++ camel/trunk/components/camel-saxon/src/test/resources/org/apache/camel/language/xpath/XPathLanguageTest.xml Wed Jan  4 08:14:54 2012
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<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 name="saxonFactory" class="net.sf.saxon.xpath.XPathFactoryImpl"/>
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+    <!-- ************************* -->
+    <!-- *** XPath Expressions *** -->
+    <!-- ************************* -->
+
+    <route>
+      <from uri="seda:testSaxonWithFlag"/>
+      <setBody>
+        <xpath saxon="true" resultType="java.lang.String" traceNamespaces="true">tokenize(a, '\|')</xpath>
+      </setBody>
+      <log message="Test Saxon with flag: ${body}"/>
+      <to uri="mock:testSaxonWithFlagResult"/>
+    </route>
+
+    <route>
+      <from uri="seda:testSaxonWithFactory"/>
+      <setBody>
+        <xpath factoryRef="saxonFactory" resultType="java.lang.String" traceNamespaces="true">tokenize(a, '\|')</xpath>
+      </setBody>
+      <log message="Test Saxon with factory: ${body}"/>
+      <to uri="mock:testSaxonWithFactoryResult"/>
+    </route>
+
+    <route>
+      <from uri="seda:testSaxonWithObjectModel"/>
+      <setBody>
+        <xpath objectModel="http://saxon.sf.net/jaxp/xpath/om" resultType="java.lang.String">tokenize(a, '\|')</xpath>
+      </setBody>
+      <log message="Test Saxon with object model: ${body}"/>
+      <to uri="mock:testSaxonWithObjectModelResult"/>
+    </route>
+
+    <!-- ************************ -->
+    <!-- *** XPath Predicates *** -->
+    <!-- ************************ -->
+
+    <route>
+      <from uri="seda:testSaxonWithFlagPredicate"/>
+      <filter>
+        <xpath saxon="true" resultType="java.lang.String">tokenize(a, '\|')[1] = 'Hello'</xpath>
+        <log message="Test Saxon with flag: ${body}"/>
+        <to uri="mock:testSaxonWithFlagResultPredicate"/>
+      </filter>
+    </route>
+
+    <route>
+      <from uri="seda:testSaxonWithFactoryPredicate"/>
+      <filter>
+        <xpath factoryRef="saxonFactory" resultType="java.lang.String">tokenize(a, '\|')[1] = 'Hello'</xpath>
+        <log message="Test Saxon with factory: ${body}"/>
+        <to uri="mock:testSaxonWithFactoryResultPredicate"/>
+      </filter>
+    </route>
+
+    <route>
+      <from uri="seda:testSaxonWithObjectModelPredicate"/>
+      <filter>
+        <xpath objectModel="http://saxon.sf.net/jaxp/xpath/om" resultType="java.lang.String">tokenize(a, '\|')[1] = 'Hello'</xpath>
+        <log message="Test Saxon with object model: ${body}"/>
+        <to uri="mock:testSaxonWithObjectModelResultPredicate"/>
+      </filter>
+    </route>
+
+  </camelContext>
+
+</beans>