diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java
index 6fd0b8469a..6195e129c9 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java
@@ -6,13 +6,14 @@ package net.sourceforge.pmd.lang.rule.xpath.internal;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 
 import net.sourceforge.pmd.lang.rule.xpath.Attribute;
 
 import net.sf.saxon.om.AtomicSequence;
 import net.sf.saxon.om.NodeInfo;
-import net.sf.saxon.pattern.NodeTest;
 import net.sf.saxon.tree.iter.AxisIterator;
+import net.sf.saxon.tree.iter.EmptyIterator;
 import net.sf.saxon.tree.util.FastStringBuffer;
 import net.sf.saxon.tree.util.Navigator;
 import net.sf.saxon.tree.wrapper.SiblingCountingNode;
@@ -50,30 +51,22 @@ class AstAttributeNode extends BaseNodeInfo implements SiblingCountingNode {
         return siblingPosition;
     }
 
-    @Override
-    protected AxisIterator iterateAttributes(NodeTest nodeTest) {
-        return null;
-    }
-
 
     @Override
-    protected AxisIterator iterateChildren(NodeTest nodeTest) {
-        return null;
+    protected AxisIterator iterateAttributes(Predicate<? super NodeInfo> nodeTest) {
+        return EmptyIterator.ofNodes();
     }
 
-
     @Override
-    protected AxisIterator iterateSiblings(NodeTest nodeTest, boolean forwards) {
-        return null;
+    protected AxisIterator iterateChildren(Predicate<? super NodeInfo> nodeTest) {
+        return EmptyIterator.ofNodes();
     }
 
-
     @Override
-    protected AxisIterator iterateDescendants(NodeTest nodeTest, boolean includeSelf) {
-        return null;
+    protected AxisIterator iterateSiblings(Predicate<? super NodeInfo> nodeTest, boolean forwards) {
+        return EmptyIterator.ofNodes();
     }
 
-
     @Override
     public AtomicSequence atomize() {
         if (value == null) {
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java
index 72bf990f27..b13587fe99 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java
@@ -6,16 +6,15 @@ package net.sourceforge.pmd.lang.rule.xpath.internal;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 
 import org.apache.commons.lang3.mutable.MutableInt;
 
 import net.sourceforge.pmd.lang.ast.Node;
 import net.sourceforge.pmd.lang.ast.RootNode;
-import net.sourceforge.pmd.lang.rule.xpath.internal.AstElementNode.DescendantIter;
 
 import net.sf.saxon.Configuration;
 import net.sf.saxon.om.NodeInfo;
-import net.sf.saxon.pattern.NodeTest;
 import net.sf.saxon.tree.iter.AxisIterator;
 import net.sf.saxon.tree.iter.EmptyIterator;
 import net.sf.saxon.tree.util.FastStringBuffer;
@@ -48,23 +47,18 @@ class AstDocumentNode extends BaseNodeInfo {
     }
 
     @Override
-    protected AxisIterator iterateAttributes(NodeTest nodeTest) {
-        return EmptyIterator.OfNodes.THE_INSTANCE;
+    protected AxisIterator iterateAttributes(Predicate<? super NodeInfo> nodeTest) {
+        return EmptyIterator.ofNodes();
     }
 
     @Override
-    protected AxisIterator iterateChildren(NodeTest nodeTest) {
+    protected AxisIterator iterateChildren(Predicate<? super NodeInfo> nodeTest) {
         return filter(nodeTest, iterateList(children));
     }
 
     @Override
-    protected AxisIterator iterateSiblings(NodeTest nodeTest, boolean forwards) {
-        return EmptyIterator.OfNodes.THE_INSTANCE;
-    }
-
-    @Override
-    protected AxisIterator iterateDescendants(NodeTest nodeTest, boolean includeSelf) {
-        return filter(nodeTest, new DescendantIter(this, includeSelf));
+    protected AxisIterator iterateSiblings(Predicate<? super NodeInfo> nodeTest, boolean forwards) {
+        return EmptyIterator.ofNodes();
     }
 
     @Override
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java
index 45719895b5..b5debaa918 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java
@@ -4,13 +4,13 @@
 
 package net.sourceforge.pmd.lang.rule.xpath.internal;
 
-import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Deque;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 import org.apache.commons.lang3.mutable.MutableInt;
 import org.checkerframework.checker.nullness.qual.Nullable;
@@ -23,11 +23,9 @@ import net.sourceforge.pmd.util.CollectionUtil;
 import net.sf.saxon.Configuration;
 import net.sf.saxon.om.NodeInfo;
 import net.sf.saxon.pattern.NameTest;
-import net.sf.saxon.pattern.NodeTest;
 import net.sf.saxon.tree.iter.AxisIterator;
 import net.sf.saxon.tree.iter.EmptyIterator;
 import net.sf.saxon.tree.iter.LookaheadIterator;
-import net.sf.saxon.tree.iter.ReverseListIterator;
 import net.sf.saxon.tree.iter.SingleNodeIterator;
 import net.sf.saxon.tree.util.FastStringBuffer;
 import net.sf.saxon.tree.util.Navigator;
@@ -120,38 +118,31 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin
     }
 
     @Override
-    protected AxisIterator iterateAttributes(NodeTest nodeTest) {
-        if (nodeTest instanceof NameTest) {
-            String local = ((NameTest) nodeTest).getLocalPart();
+    protected AxisIterator iterateAttributes(Predicate<? super NodeInfo> predicate) {
+        if (predicate instanceof NameTest) {
+            String local = ((NameTest) predicate).getLocalPart();
             return SingleNodeIterator.makeIterator(getAttributes().get(local));
         }
 
-        return filter(nodeTest, new IteratorAdapter(getAttributes().values().iterator()));
+        return filter(predicate, new IteratorAdapter(getAttributes().values().iterator()));
     }
 
-
     @Override
-    protected AxisIterator iterateChildren(NodeTest nodeTest) {
+    protected AxisIterator iterateChildren(Predicate<? super NodeInfo> nodeTest) {
         return filter(nodeTest, iterateList(children));
     }
 
-
     @Override // this excludes self
-    protected AxisIterator iterateSiblings(NodeTest nodeTest, boolean forwards) {
+    protected AxisIterator iterateSiblings(Predicate<? super NodeInfo> nodeTest, boolean forwards) {
         if (parent == null) {
-            return EmptyIterator.OfNodes.THE_INSTANCE;
+            return EmptyIterator.ofNodes();
         }
 
         List<? extends NodeInfo> siblingsList =
             forwards ? CollectionUtil.drop(parent.getChildren(), wrappedNode.getIndexInParent() + 1)
                      : CollectionUtil.take(parent.getChildren(), wrappedNode.getIndexInParent());
 
-        @SuppressWarnings("PMD.CloseResource")
-        AxisIterator iter =
-            forwards ? iterateList(siblingsList)
-                     : new RevListAxisIterator(siblingsList);
-
-        return filter(nodeTest, iter);
+        return filter(nodeTest, iterateList(siblingsList, forwards));
     }
 
 
@@ -162,11 +153,6 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin
         return attributeWrapper == null ? null : attributeWrapper.getStringValue();
     }
 
-    @Override
-    protected AxisIterator iterateDescendants(NodeTest nodeTest, boolean includeSelf) {
-        return filter(nodeTest, new DescendantIter(this, includeSelf));
-    }
-
 
     @Override
     public int getLineNumber() {
@@ -214,59 +200,11 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin
         return "Wrapper[" + getLocalPart() + "]@" + hashCode();
     }
 
-    static class DescendantIter implements AxisIterator, LookaheadIterator<NodeInfo> {
 
-        private final Deque<BaseNodeInfo> todo;
 
-        DescendantIter(BaseNodeInfo start, boolean includeSelf) {
-            todo = new ArrayDeque<>();
-            if (includeSelf) {
-                todo.addLast(start);
-            } else {
-                todo.addAll(start.getChildren());
-            }
-        }
-
-        @Override
-        public boolean hasNext() {
-            return !todo.isEmpty();
-        }
-
-        @Override
-        public NodeInfo next() {
-            if (todo.isEmpty()) {
-                return null;
-            }
-            BaseNodeInfo first = todo.removeFirst();
-            todo.addAll(first.getChildren());
-            return first;
-        }
-
-        @Override
-        public void close() {
-            todo.clear();
-        }
-
-        @Override
-        public int getProperties() {
-            return LOOKAHEAD;
-        }
-    }
-
-    private static class RevListAxisIterator extends ReverseListIterator<NodeInfo> implements AxisIterator {
-
-        RevListAxisIterator(List<? extends NodeInfo> list) {
-            super((List<NodeInfo>) list);
-        }
-
-        @Override
-        public NodeInfo next() {
-            return super.next();
-        }
-    }
-
-    private static class IteratorAdapter implements AxisIterator, LookaheadIterator<NodeInfo> {
+    private static class IteratorAdapter implements AxisIterator, LookaheadIterator {
 
+        private static final EnumSet<Property> PROPERTIES = EnumSet.of(Property.LOOKAHEAD);
         private final Iterator<? extends NodeInfo> it;
 
         IteratorAdapter(Iterator<? extends NodeInfo> it) {
@@ -290,8 +228,8 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin
 
 
         @Override
-        public int getProperties() {
-            return LOOKAHEAD;
+        public EnumSet<Property> getProperties() {
+            return PROPERTIES;
         }
     }
 }
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java
index 37a36033fb..0f8d7672e3 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java
@@ -6,13 +6,14 @@ package net.sourceforge.pmd.lang.rule.xpath.internal;
 
 
 import java.util.List;
+import java.util.function.Predicate;
 
 import net.sf.saxon.om.NamePool;
 import net.sf.saxon.om.NodeInfo;
 import net.sf.saxon.pattern.AnyNodeTest;
-import net.sf.saxon.pattern.NodeTest;
 import net.sf.saxon.tree.iter.AxisIterator;
 import net.sf.saxon.tree.iter.ListIterator;
+import net.sf.saxon.tree.iter.ReverseListIterator;
 import net.sf.saxon.tree.util.Navigator.AxisFilter;
 import net.sf.saxon.tree.wrapper.AbstractNodeWrapper;
 import net.sf.saxon.tree.wrapper.SiblingCountingNode;
@@ -77,12 +78,24 @@ abstract class BaseNodeInfo extends AbstractNodeWrapper implements SiblingCounti
         return nodeKind;
     }
 
-    protected static AxisIterator filter(NodeTest nodeTest, AxisIterator iter) {
-        return nodeTest != null && nodeTest != AnyNodeTest.getInstance() ? new AxisFilter(iter, nodeTest) : iter;
+    protected static AxisIterator filter(Predicate<? super NodeInfo> nodeTest, AxisIterator iter) {
+        return nodeTest == null || (nodeTest instanceof AnyNodeTest) ? new AxisFilter(iter, nodeTest) : iter;
     }
 
 
     static AxisIterator iterateList(List<? extends NodeInfo> nodes) {
-        return new ListIterator.OfNodes((List) nodes);
+        return iterateList(nodes, true);
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    static AxisIterator iterateList(List<? extends NodeInfo> nodes, boolean forwards) {
+        return forwards ? new ListIterator.OfNodes((List) nodes)
+                        : new RevListAxisIterator((List) nodes);
+    }
+
+    private static class RevListAxisIterator extends ReverseListIterator<NodeInfo> implements AxisIterator {
+        RevListAxisIterator(List<NodeInfo> list) {
+            super(list);
+        }
     }
 }
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java
index 39c014865b..f4ee66325f 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java
@@ -118,8 +118,8 @@ public class SaxonXPathRuleQuery {
             List<Expression> expressions = getExpressionsForLocalNameOrDefault(node.getXPathNodeName());
             for (Expression expression : expressions) {
                 @SuppressWarnings("PMD.CloseResource")
-                SequenceIterator<?> iterator = expression.iterate(xpathDynamicContext.getXPathContextObject());
-                Item<?> current = iterator.next();
+                SequenceIterator iterator = expression.iterate(xpathDynamicContext.getXPathContextObject());
+                Item current = iterator.next();
                 while (current != null) {
                     if (current instanceof AstElementNode) {
                         results.add(((AstElementNode) current).getUnderlyingNode());
@@ -190,9 +190,11 @@ public class SaxonXPathRuleQuery {
             return;
         }
         try {
-            final XPathEvaluator xpathEvaluator = new XPathEvaluator();
-            this.configuration = xpathEvaluator.getConfiguration();
-            StaticContextWithProperties staticCtx = new StaticContextWithProperties(configuration);
+            this.configuration = Configuration.newConfiguration();
+            this.configuration.setNamePool(getNamePool());
+
+
+            StaticContextWithProperties staticCtx = new StaticContextWithProperties(this.configuration);
             staticCtx.declareNamespace("fn", NamespaceConstant.FN);
 
             for (final PropertyDescriptor<?> propertyDescriptor : properties.keySet()) {
@@ -202,15 +204,15 @@ public class SaxonXPathRuleQuery {
                 }
             }
 
-            xpathEvaluator.setStaticContext(staticCtx);
-            configuration.setNamePool(getNamePool());
-
             for (ExtensionFunctionDefinition fun : xPathHandler.getRegisteredExtensionFunctions()) {
                 StructuredQName qname = fun.getFunctionQName();
                 staticCtx.declareNamespace(qname.getPrefix(), qname.getURI());
-                configuration.registerExtensionFunction(fun);
+                this.configuration.registerExtensionFunction(fun);
             }
 
+            final XPathEvaluator xpathEvaluator = new XPathEvaluator(configuration);
+            xpathEvaluator.setStaticContext(staticCtx);
+
             xpathExpression = xpathEvaluator.createExpression(xpathExpr);
             analyzeXPathForRuleChain(xpathEvaluator);
         } catch (final XPathException e) {
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java
index d429109e29..37d7f2d0dd 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java
@@ -12,7 +12,6 @@ import net.sourceforge.pmd.lang.ast.DummyNode;
 import net.sourceforge.pmd.lang.ast.DummyRoot;
 
 import net.sf.saxon.Configuration;
-import net.sf.saxon.sxpath.XPathEvaluator;
 import net.sf.saxon.type.Type;
 
 public class ElementNodeTest {
@@ -31,7 +30,7 @@ public class ElementNodeTest {
         root.addChild(c1, 1);
 
 
-        Configuration configuration = new XPathEvaluator().getStaticContext().getConfiguration();
+        Configuration configuration = Configuration.newConfiguration();
 
         AstTreeInfo treeInfo = new AstTreeInfo(root, configuration);
         Assert.assertSame(root, treeInfo.getRootNode().getUnderlyingNode());
diff --git a/pom.xml b/pom.xml
index f892e0934a..7069730ae4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -632,7 +632,7 @@
             <dependency>
                 <groupId>net.sf.saxon</groupId>
                 <artifactId>Saxon-HE</artifactId>
-                <version>9.9.1-6</version>
+                <version>10.1</version>
             </dependency>
             <dependency>
                 <groupId>org.mozilla</groupId>