Redundent Expression Elimination branch checkin.  This branch is for major
optimization work being done.  I expect it to be folded in on the main branch
within a couple of weeks.

Goal of branch: around 50% overall performance gain.

Major architectural changes
1) Rip out cacheing in all iterators, and move the caching into XNodeSet (actually NodeSequence where the caching is done derives from XObject and XNodeSet derives from NodeSequence).  Lots of other changes went into this, including rewriting of some of the xsl:key stuff.

2) Implementation of a Visitor mechanism for the stylesheet and xpath components.  Each component for an XPath event is passed an ExpressionOwner, which just has a getExpression and setExpression method, which allows us to create a list of these, and then be able to do rewrites.  This should be a generally useful mechanism for all sorts of stuff, and should be considered a public API.

3) Implementation of deepEquality methods for all XPath components, which allows us to see if two components are equal.

4) Implementation of RedundentExprEliminator, which is a derivative from the new XSLTVisitor class, which runs over the stylesheet collecting xpaths within the same scope, and absolute xpaths that are not context dependent.  These are then each reduced by walking the list and checking for deep equality (though global paths are always reduced).  Reduction takes place by creating variables that have a special namespace and a non-legal local name.  Both full and partial path reduction done.

Not done yet: Add back in the xsl:key caching that I ripped out (not a big deal).  Could be skipped, with some risk.

Not done yet: Implement isLast function.  With the new stuff, the last() function will be slower, so, since most cases are just checking to see if an item is the last, I want to rewrite foo[last()] patterns to foo[xalan:isLast()].  Could be skipped, with some risk.

Davanum performance test result: 4x increase in performance.

Datapower performance suite results: very slight decrease in overall performance.   :-(

Smoke test results: All clear when run with Xerces 1.

To Do on this branch:

Christina trace/debug API enhancements.
Possible unroll of recursive evaluation.
Implement serializers directly off of ResultTreeHandler (and provide ContentHandler adapters).
Specialize and optimize serializers for 80% cases.


git-svn-id: https://svn.apache.org/repos/asf/xalan/java/branches/SBOAG_BRANCH_OPTIMIZATION2@336025 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java b/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
index 67effd3..c901cdd 100644
--- a/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
+++ b/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
@@ -305,7 +305,7 @@
 
           if (targetObject instanceof XObject)
             targetObject = ((XObject) targetObject).object();
-
+            
           if (m_classObj.isAssignableFrom(targetObject.getClass()))
             resolveType = MethodResolver.DYNAMIC;
           else
diff --git a/src/org/apache/xalan/processor/ProcessorKey.java b/src/org/apache/xalan/processor/ProcessorKey.java
index ea9158e..f18a917 100644
--- a/src/org/apache/xalan/processor/ProcessorKey.java
+++ b/src/org/apache/xalan/processor/ProcessorKey.java
@@ -121,7 +121,8 @@
    * @param target The target element where the properties will be set.
    */
   void setPropertiesFromAttributes(
-          StylesheetHandler handler, String rawName, Attributes attributes, Object target)
+          StylesheetHandler handler, String rawName, Attributes attributes, 
+          org.apache.xalan.templates.ElemTemplateElement target)
             throws org.xml.sax.SAXException
   {
 
diff --git a/src/org/apache/xalan/processor/ProcessorPreserveSpace.java b/src/org/apache/xalan/processor/ProcessorPreserveSpace.java
index 6d2cd32..5f6ea77 100644
--- a/src/org/apache/xalan/processor/ProcessorPreserveSpace.java
+++ b/src/org/apache/xalan/processor/ProcessorPreserveSpace.java
@@ -75,38 +75,6 @@
 {
 
   /**
-   * Bean property to allow setPropertiesFromAttributes to
-   * get the elements attribute.
-   */
-  private Vector m_elements;
-
-  /**
-   * Set from the elements attribute.  This is a list of 
-   * whitespace delimited element qualified names that specify
-   * preservation of whitespace.
-   *
-   * @param elems Should be a non-null reference to a list 
-   *              of {@link org.apache.xpath.XPath} objects.
-   */
-  public void setElements(Vector elems)
-  {
-    m_elements = elems;
-  }
-
-  /**
-   * Get the property set by setElements().  This is a list of 
-   * whitespace delimited element qualified names that specify
-   * preservation of whitespace.
-   *
-   * @return A reference to a list of {@link org.apache.xpath.XPath} objects, 
-   *         or null.
-   */
-  Vector getElements()
-  {
-    return m_elements;
-  }
-
-  /**
    * Receive notification of the start of an preserve-space element.
    *
    * @param handler The calling StylesheetHandler/TemplatesBuilder.
@@ -123,14 +91,15 @@
    *        Attributes object.
    */
   public void startElement(
-          StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
+          StylesheetHandler handler, String uri, String localName, String rawName, 
+          Attributes attributes)
             throws org.xml.sax.SAXException
   {
-
-    setPropertiesFromAttributes(handler, rawName, attributes, this);
-
     Stylesheet thisSheet = handler.getStylesheet();
-    Vector xpaths = getElements();
+	WhitespaceInfoPaths paths = new WhitespaceInfoPaths(thisSheet);
+    setPropertiesFromAttributes(handler, rawName, attributes, paths);
+
+    Vector xpaths = paths.getElements();
 
     for (int i = 0; i < xpaths.size(); i++)
     {
@@ -139,5 +108,6 @@
 
       thisSheet.setPreserveSpaces(wsi);
     }
+    paths.clearElements();
   }
 }
diff --git a/src/org/apache/xalan/processor/ProcessorStripSpace.java b/src/org/apache/xalan/processor/ProcessorStripSpace.java
index a1f8119..0eb390e 100644
--- a/src/org/apache/xalan/processor/ProcessorStripSpace.java
+++ b/src/org/apache/xalan/processor/ProcessorStripSpace.java
@@ -94,10 +94,11 @@
           StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
             throws org.xml.sax.SAXException
   {
-    setPropertiesFromAttributes(handler, rawName, attributes, this);
-
     Stylesheet thisSheet = handler.getStylesheet();
-    Vector xpaths = getElements();
+	WhitespaceInfoPaths paths = new WhitespaceInfoPaths(thisSheet);
+    setPropertiesFromAttributes(handler, rawName, attributes, paths);
+
+    Vector xpaths = paths.getElements();
 
     for (int i = 0; i < xpaths.size(); i++)
     {
@@ -106,6 +107,7 @@
 
       thisSheet.setStripSpaces(wsi);
     }
+    paths.clearElements();
 
   }
 }
diff --git a/src/org/apache/xalan/processor/StylesheetHandler.java b/src/org/apache/xalan/processor/StylesheetHandler.java
index 4bec315..1914199 100644
--- a/src/org/apache/xalan/processor/StylesheetHandler.java
+++ b/src/org/apache/xalan/processor/StylesheetHandler.java
@@ -190,11 +190,11 @@
    * @throws javax.xml.transform.TransformerException if the expression can not be processed.
    * @see <a href="http://www.w3.org/TR/xslt#section-Expressions">Section 4 Expressions in XSLT Specification</a>
    */
-  public XPath createXPath(String str)
+  public XPath createXPath(String str, ElemTemplateElement owningTemplate)
           throws javax.xml.transform.TransformerException
   {
     ErrorListener handler = m_stylesheetProcessor.getErrorListener();
-    return new XPath(str, getLocator(), this, XPath.SELECT, handler);
+    return new XPath(str, owningTemplate, this, XPath.SELECT, handler);
   }
 
   /**
@@ -207,11 +207,11 @@
    * @throws javax.xml.transform.TransformerException if the pattern can not be processed.
    * @see <a href="http://www.w3.org/TR/xslt#patterns">Section 5.2 Patterns in XSLT Specification</a>
    */
-  XPath createMatchPatternXPath(String str)
+  XPath createMatchPatternXPath(String str, ElemTemplateElement owningTemplate)
           throws javax.xml.transform.TransformerException
   {
     ErrorListener handler = m_stylesheetProcessor.getErrorListener();
-    return new XPath(str, getLocator(), this, XPath.MATCH, handler);
+    return new XPath(str, owningTemplate, this, XPath.MATCH, handler);
   }
 
   /**
diff --git a/src/org/apache/xalan/processor/WhitespaceInfoPaths.java b/src/org/apache/xalan/processor/WhitespaceInfoPaths.java
new file mode 100644
index 0000000..b45c5df
--- /dev/null
+++ b/src/org/apache/xalan/processor/WhitespaceInfoPaths.java
@@ -0,0 +1,60 @@
+package org.apache.xalan.processor;
+
+import org.apache.xalan.templates.WhiteSpaceInfo;
+import java.util.Vector;
+import org.apache.xalan.templates.Stylesheet;
+
+public class WhitespaceInfoPaths extends WhiteSpaceInfo
+{
+	
+  /**
+   * Bean property to allow setPropertiesFromAttributes to
+   * get the elements attribute.
+   */
+  private Vector m_elements;
+
+  /**
+   * Set from the elements attribute.  This is a list of 
+   * whitespace delimited element qualified names that specify
+   * preservation of whitespace.
+   *
+   * @param elems Should be a non-null reference to a list 
+   *              of {@link org.apache.xpath.XPath} objects.
+   */
+  public void setElements(Vector elems)
+  {
+    m_elements = elems;
+  }
+
+  /**
+   * Get the property set by setElements().  This is a list of 
+   * whitespace delimited element qualified names that specify
+   * preservation of whitespace.
+   *
+   * @return A reference to a list of {@link org.apache.xpath.XPath} objects, 
+   *         or null.
+   */
+  Vector getElements()
+  {
+    return m_elements;
+  }
+  
+  public void clearElements()
+  {
+  	m_elements = null;
+  }
+
+ /**
+   * Constructor WhitespaceInfoPaths
+   *
+   * @param thisSheet The current stylesheet
+   */
+  public WhitespaceInfoPaths(Stylesheet thisSheet)
+  {
+  	super(thisSheet);
+  	setStylesheet(thisSheet);
+  }
+
+
+}
+
diff --git a/src/org/apache/xalan/processor/XSLTAttributeDef.java b/src/org/apache/xalan/processor/XSLTAttributeDef.java
index c21d831..221f47a 100644
--- a/src/org/apache/xalan/processor/XSLTAttributeDef.java
+++ b/src/org/apache/xalan/processor/XSLTAttributeDef.java
@@ -465,13 +465,14 @@
    * in the attribute value template string.
    */
   AVT processAVT(
-          StylesheetHandler handler, String uri, String name, String rawName, String value)
+          StylesheetHandler handler, String uri, String name, String rawName, String value,
+          ElemTemplateElement owner)
             throws org.xml.sax.SAXException
   {
 
     try
     {
-      AVT avt = new AVT(handler, uri, name, rawName, value);
+      AVT avt = new AVT(handler, uri, name, rawName, value, owner);
 
       return avt;
     }
@@ -566,13 +567,14 @@
    * string contains a syntax error.
    */
   Object processEXPR(
-          StylesheetHandler handler, String uri, String name, String rawName, String value)
+          StylesheetHandler handler, String uri, String name, String rawName, String value,
+          ElemTemplateElement owner)
             throws org.xml.sax.SAXException
   {
 
     try
     {
-      XPath expr = handler.createXPath(value);
+      XPath expr = handler.createXPath(value, owner);
 
       return expr;
     }
@@ -618,13 +620,14 @@
    * string contains a syntax error.
    */
   Object processPATTERN(
-          StylesheetHandler handler, String uri, String name, String rawName, String value)
+          StylesheetHandler handler, String uri, String name, String rawName, String value,
+          ElemTemplateElement owner)
             throws org.xml.sax.SAXException
   {
 
     try
     {
-      XPath pattern = handler.createMatchPatternXPath(value);
+      XPath pattern = handler.createMatchPatternXPath(value, owner);
 
       return pattern;
     }
@@ -741,7 +744,8 @@
    * strings contains a syntax error.
    */
   Vector processSIMPLEPATTERNLIST(
-          StylesheetHandler handler, String uri, String name, String rawName, String value)
+          StylesheetHandler handler, String uri, String name, String rawName, String value,
+          ElemTemplateElement owner)
             throws org.xml.sax.SAXException
   {
 
@@ -754,7 +758,7 @@
       for (int i = 0; i < nPatterns; i++)
       {
         XPath pattern =
-          handler.createMatchPatternXPath(tokenizer.nextToken());
+          handler.createMatchPatternXPath(tokenizer.nextToken(), owner);
 
         patterns.addElement(pattern);
       }
@@ -895,7 +899,8 @@
    * @throws org.xml.sax.SAXException if the attribute value can not be processed.
    */
   Object processValue(
-          StylesheetHandler handler, String uri, String name, String rawName, String value)
+          StylesheetHandler handler, String uri, String name, String rawName, String value,
+          ElemTemplateElement owner)
             throws org.xml.sax.SAXException
   {
 
@@ -905,7 +910,7 @@
     switch (type)
     {
     case T_AVT :
-      processedValue = processAVT(handler, uri, name, rawName, value);
+      processedValue = processAVT(handler, uri, name, rawName, value, owner);
       break;
     case T_CDATA :
       processedValue = processCDATA(handler, uri, name, rawName, value);
@@ -917,13 +922,13 @@
       processedValue = processENUM(handler, uri, name, rawName, value);
       break;
     case T_EXPR :
-      processedValue = processEXPR(handler, uri, name, rawName, value);
+      processedValue = processEXPR(handler, uri, name, rawName, value, owner);
       break;
     case T_NMTOKEN :
       processedValue = processNMTOKEN(handler, uri, name, rawName, value);
       break;
     case T_PATTERN :
-      processedValue = processPATTERN(handler, uri, name, rawName, value);
+      processedValue = processPATTERN(handler, uri, name, rawName, value, owner);
       break;
     case T_PRIORITY :
       processedValue = processPRIORITY(handler, uri, name, rawName, value);
@@ -936,7 +941,7 @@
       break;
     case T_SIMPLEPATTERNLIST :
       processedValue = processSIMPLEPATTERNLIST(handler, uri, name, rawName,
-                                                value);
+                                                value, owner);
       break;
     case T_URL :
       processedValue = processURL(handler, uri, name, rawName, value);
@@ -966,7 +971,7 @@
    * @throws org.xml.sax.SAXException wraps an invocation exception if the
    * setter method can not be invoked on the object.
    */
-  void setDefAttrValue(StylesheetHandler handler, Object elem)
+  void setDefAttrValue(StylesheetHandler handler, ElemTemplateElement elem)
           throws org.xml.sax.SAXException
   {
     setAttrValue(handler, this.getNamespace(), this.getName(),
@@ -1042,7 +1047,8 @@
    * @throws org.xml.sax.SAXException
    */
   void setAttrValue(
-          StylesheetHandler handler, String attrUri, String attrLocalName, String attrRawName, String attrValue, Object elem)
+          StylesheetHandler handler, String attrUri, String attrLocalName, 
+          String attrRawName, String attrValue, ElemTemplateElement elem)
             throws org.xml.sax.SAXException
   {
     if(attrRawName.equals("xmlns") || attrRawName.startsWith("xmlns:"))
@@ -1076,7 +1082,7 @@
         else
         {
           Object value = processValue(handler, attrUri, attrLocalName,
-                                      attrRawName, attrValue);
+                                      attrRawName, attrValue, elem);
                                       
           // First try to match with the primative value.
           Class[] argTypes = new Class[]{ getPrimativeClass(value) };
diff --git a/src/org/apache/xalan/processor/XSLTElementProcessor.java b/src/org/apache/xalan/processor/XSLTElementProcessor.java
index 5a2fee8..ef15f5d 100644
--- a/src/org/apache/xalan/processor/XSLTElementProcessor.java
+++ b/src/org/apache/xalan/processor/XSLTElementProcessor.java
@@ -79,7 +79,7 @@
  * processors, and deals with things that are common to all elements.
  * @see <a href="http://www.w3.org/TR/xslt#dtd">XSLT DTD</a>
  */
-public class XSLTElementProcessor
+public class XSLTElementProcessor extends ElemTemplateElement
 {
 
   /**
@@ -305,7 +305,8 @@
    * @param target The target element where the properties will be set.
    */
   void setPropertiesFromAttributes(
-          StylesheetHandler handler, String rawName, Attributes attributes, Object target)
+          StylesheetHandler handler, String rawName, Attributes attributes, 
+          ElemTemplateElement target)
             throws org.xml.sax.SAXException
   {
     setPropertiesFromAttributes(handler, rawName, attributes, target, true);
@@ -326,7 +327,8 @@
    * @throws TransformerException
    */
   Attributes setPropertiesFromAttributes(
-          StylesheetHandler handler, String rawName, Attributes attributes, Object target, boolean throwError)
+          StylesheetHandler handler, String rawName, Attributes attributes, 
+          ElemTemplateElement target, boolean throwError)
             throws org.xml.sax.SAXException
   {
 
diff --git a/src/org/apache/xalan/templates/AVT.java b/src/org/apache/xalan/templates/AVT.java
index b003e38..646784b 100644
--- a/src/org/apache/xalan/templates/AVT.java
+++ b/src/org/apache/xalan/templates/AVT.java
@@ -79,7 +79,7 @@
  * <meta name="usage" content="advanced"/>
  * Class to hold an Attribute Value Template.
  */
-public class AVT implements java.io.Serializable
+public class AVT implements java.io.Serializable, XSLTVisitable
 {
 
   /**
@@ -185,7 +185,9 @@
    *
    * @throws javax.xml.transform.TransformerException
    */
-  public AVT(StylesheetHandler handler, String uri, String name, String rawName, String stringedValue)
+  public AVT(StylesheetHandler handler, String uri, String name, 
+             String rawName, String stringedValue,
+             ElemTemplateElement owner)
           throws javax.xml.transform.TransformerException
   {
 
@@ -324,7 +326,7 @@
                           buffer.setLength(0);
 
                           XPath xpath =
-                                       handler.createXPath(exprBuffer.toString());
+                                       handler.createXPath(exprBuffer.toString(), owner);
 
                           m_parts.addElement(new AVTPartXPath(xpath));
 
@@ -611,4 +613,23 @@
       }
     }
   }
+  
+  /**
+   * @see XSLTVisitable#callVisitors(XSLTVisitor)
+   */
+  public void callVisitors(XSLTVisitor visitor)
+  {
+  	if(visitor.visitAVT(this) && (null != m_parts))
+  	{
+      int n = m_parts.size();
+
+      for (int i = 0; i < n; i++)
+      {
+        AVTPart part = (AVTPart) m_parts.elementAt(i);
+
+        part.callVisitors(visitor);
+      }  		
+  	}
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/AVTPart.java b/src/org/apache/xalan/templates/AVTPart.java
index 4c3fc25..fb1bb93 100644
--- a/src/org/apache/xalan/templates/AVTPart.java
+++ b/src/org/apache/xalan/templates/AVTPart.java
@@ -67,7 +67,7 @@
  * Class to hold a part, either a string or XPath,
  * of an Attribute Value Template.
  */
-public abstract class AVTPart implements java.io.Serializable
+public abstract class AVTPart implements java.io.Serializable, XSLTVisitable
 {
 
   /**
diff --git a/src/org/apache/xalan/templates/AVTPartSimple.java b/src/org/apache/xalan/templates/AVTPartSimple.java
index 2a1fc7d..9ba686a 100644
--- a/src/org/apache/xalan/templates/AVTPartSimple.java
+++ b/src/org/apache/xalan/templates/AVTPartSimple.java
@@ -127,4 +127,12 @@
   {
     buf.append(m_val);
   }
+  /**
+   * @see XSLTVisitable#callVisitors(XSLTVisitor)
+   */
+  public void callVisitors(XSLTVisitor visitor)
+  {
+  	// Don't do anything for the subpart for right now.
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/AVTPartXPath.java b/src/org/apache/xalan/templates/AVTPartXPath.java
index 0f6e38b..090b02d 100644
--- a/src/org/apache/xalan/templates/AVTPartXPath.java
+++ b/src/org/apache/xalan/templates/AVTPartXPath.java
@@ -57,10 +57,12 @@
 package org.apache.xalan.templates;
 
 import org.apache.xpath.*;
+import org.apache.xpath.Expression;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.compiler.XPathParser;
 import org.apache.xml.utils.FastStringBuffer;
+import org.apache.xpath.ExpressionOwner;
 
 //import org.w3c.dom.*;
 import org.apache.xml.dtm.DTM;
@@ -177,4 +179,12 @@
       xobj.appendToFsb(buf);
     }
   }
+  
+  /**
+   * @see XSLTVisitable#callVisitors(XSLTVisitor)
+   */
+  public void callVisitors(XSLTVisitor visitor)
+  {
+  	m_xpath.getExpression().callVisitors(m_xpath, visitor);
+  }
 }
diff --git a/src/org/apache/xalan/templates/AbsPathChecker.java b/src/org/apache/xalan/templates/AbsPathChecker.java
new file mode 100644
index 0000000..3b1d4cf
--- /dev/null
+++ b/src/org/apache/xalan/templates/AbsPathChecker.java
@@ -0,0 +1,117 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xalan.templates;
+
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.functions.FuncCurrent;
+import org.apache.xpath.functions.FuncExtFunction;
+import org.apache.xpath.functions.Function;
+import org.apache.xpath.operations.Variable;
+
+/**
+ * This class runs over a path expression that is assumed to be absolute, and 
+ * checks for variables and the like that may make it context dependent.
+ */
+public class AbsPathChecker extends XPathVisitor
+{
+	private boolean m_isAbs = true;
+	
+	/**
+	 * Process the LocPathIterator to see if it contains variables 
+	 * or functions that may make it context dependent.
+	 * @param path LocPathIterator that is assumed to be absolute, but needs checking.
+	 * @return true if the path is confirmed to be absolute, false if it 
+	 * may contain context dependencies.
+	 */
+	public boolean checkAbsolute(LocPathIterator path)
+	{
+		m_isAbs = true;
+		path.callVisitors(null, this);
+		return m_isAbs;
+	}
+	
+	/**
+	 * Visit a function.
+	 * @param owner The owner of the expression, to which the expression can 
+	 *              be reset if rewriting takes place.
+	 * @param func The function reference object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	public boolean visitFunction(ExpressionOwner owner, Function func)
+	{
+		if((func instanceof FuncCurrent) ||
+		   (func instanceof FuncExtFunction))
+			m_isAbs = false;
+		return true;
+	}
+	
+	/**
+	 * Visit a variable reference.
+	 * @param owner The owner of the expression, to which the expression can 
+	 *              be reset if rewriting takes place.
+	 * @param var The variable reference object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	public boolean visitVariableRef(ExpressionOwner owner, Variable var)
+	{
+		m_isAbs = false;
+		return true;
+	}
+}
+
diff --git a/src/org/apache/xalan/templates/ElemApplyTemplates.java b/src/org/apache/xalan/templates/ElemApplyTemplates.java
index 8db67f0..4c92470 100644
--- a/src/org/apache/xalan/templates/ElemApplyTemplates.java
+++ b/src/org/apache/xalan/templates/ElemApplyTemplates.java
@@ -267,9 +267,11 @@
         sourceNodes = sortNodes(xctxt, keys, sourceNodes);
 
       if (TransformerImpl.S_DEBUG)
+      {
         transformer.getTraceManager().fireSelectedEvent(sourceNode, this,
                 "select", new XPath(m_selectExpression),
                 new org.apache.xpath.objects.XNodeSet(sourceNodes));
+      }
 
       final ResultTreeHandler rth = transformer.getResultTreeHandler();
       ContentHandler chandler = rth.getContentHandler();
@@ -277,19 +279,6 @@
       final TemplateList tl = sroot.getTemplateListComposed();
       final boolean quiet = transformer.getQuietConflictWarnings();
       
-      xctxt.pushCurrentNode(DTM.NULL);
-      int[] currentNodes = xctxt.getCurrentNodeStack();
-      int currentNodePos = xctxt.getCurrentNodeFirstFree() - 1;
-      
-      xctxt.pushCurrentExpressionNode(DTM.NULL);
-      int[] currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
-      int currentExpressionNodePos = xctxt.getCurrentExpressionNodesFirstFree() - 1;
-
-      xctxt.pushSAXLocatorNull();
-      xctxt.pushContextNodeList(sourceNodes);
-      transformer.pushElemTemplateElement(null);
-      // pushParams(transformer, xctxt);
-
       // Should be able to get this from the iterator but there must be a bug.
       DTM dtm = xctxt.getDTM(sourceNode);
       
@@ -312,6 +301,19 @@
         vars.setStackFrame(argsFrame);
       }
       
+      xctxt.pushCurrentNode(DTM.NULL);
+      int[] currentNodes = xctxt.getCurrentNodeStack();
+      int currentNodePos = xctxt.getCurrentNodeFirstFree() - 1;
+      
+      xctxt.pushCurrentExpressionNode(DTM.NULL);
+      int[] currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
+      int currentExpressionNodePos = xctxt.getCurrentExpressionNodesFirstFree() - 1;
+
+      xctxt.pushSAXLocatorNull();
+      xctxt.pushContextNodeList(sourceNodes);
+      transformer.pushElemTemplateElement(null);
+      // pushParams(transformer, xctxt);
+      
       int child;
       while (DTM.NULL != (child = sourceNodes.nextNode()))
       {
diff --git a/src/org/apache/xalan/templates/ElemAttribute.java b/src/org/apache/xalan/templates/ElemAttribute.java
index e36b888..e438875 100644
--- a/src/org/apache/xalan/templates/ElemAttribute.java
+++ b/src/org/apache/xalan/templates/ElemAttribute.java
@@ -113,8 +113,6 @@
    * @see <a href="http://www.w3.org/TR/xslt#creating-attributes">creating-attributes in XSLT Specification</a>
    *
    * @param transformer non-null reference to the the current transform-time state.
-   * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
-   * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
    *
    * @throws TransformerException
    */
diff --git a/src/org/apache/xalan/templates/ElemCallTemplate.java b/src/org/apache/xalan/templates/ElemCallTemplate.java
index eeae952..5154c6f 100644
--- a/src/org/apache/xalan/templates/ElemCallTemplate.java
+++ b/src/org/apache/xalan/templates/ElemCallTemplate.java
@@ -56,19 +56,13 @@
  */
 package org.apache.xalan.templates;
 
-import java.util.Vector;
-
-import org.w3c.dom.*;
-
-import org.xml.sax.*;
-
-import org.apache.xpath.*;
-import org.apache.xml.utils.QName;
-import org.apache.xalan.res.XSLTErrorResources;
-import org.apache.xpath.VariableStack;
-import org.apache.xalan.transformer.TransformerImpl;
 import javax.xml.transform.SourceLocator;
 import javax.xml.transform.TransformerException;
+import org.apache.xalan.res.XSLTErrorResources;
+import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.XObject;
 
 /**
@@ -378,4 +372,24 @@
     // contain a for-each, and other elements.
     return super.appendChild(newChild);
   }
+  
+    /**
+     * Call the children visitors.
+     * @param visitor The visitor whose appropriate method will be called.
+     */
+    public void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+    {
+//      if (null != m_paramElems)
+//      {
+//        int size = m_paramElems.length;
+//
+//        for (int i = 0; i < size; i++)
+//        {
+//          ElemWithParam ewp = m_paramElems[i];
+//          ewp.callVisitors(visitor);
+//        }
+//      }
+
+      super.callChildVisitors(visitor, callAttrs);
+    }
 }
diff --git a/src/org/apache/xalan/templates/ElemChoose.java b/src/org/apache/xalan/templates/ElemChoose.java
index 385d9ff..96cdc28 100644
--- a/src/org/apache/xalan/templates/ElemChoose.java
+++ b/src/org/apache/xalan/templates/ElemChoose.java
@@ -141,6 +141,11 @@
         // must be xsl:when
         XPathContext xctxt = transformer.getXPathContext();
         int sourceNode = xctxt.getCurrentNode();
+        
+        // System.err.println("\""+when.getTest().getPatternString()+"\"");
+        
+        // if(when.getTest().getPatternString().equals("COLLECTION/icuser/ictimezone/LITERAL='GMT +13:00 Pacific/Tongatapu'"))
+        // 	System.err.println("Found COLLECTION/icuser/ictimezone/LITERAL");
 
         if (TransformerImpl.S_DEBUG)
         {
@@ -216,4 +221,14 @@
 
     return super.appendChild(newChild);
   }
+  
+  /**
+   * Tell if this element can accept variable declarations.
+   * @return true if the element can accept and process variable declarations.
+   */
+  public boolean canAcceptVariables()
+  {
+  	return false;
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemCopyOf.java b/src/org/apache/xalan/templates/ElemCopyOf.java
index 8fafd1f..e7ff1bd 100644
--- a/src/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/org/apache/xalan/templates/ElemCopyOf.java
@@ -274,4 +274,16 @@
     //" to " + this.m_elemName);
     return null;
   }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs)
+  		m_selectExpression.getExpression().callVisitors(m_selectExpression, visitor);
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemElement.java b/src/org/apache/xalan/templates/ElemElement.java
index ba58f56..8cad2a1 100644
--- a/src/org/apache/xalan/templates/ElemElement.java
+++ b/src/org/apache/xalan/templates/ElemElement.java
@@ -271,8 +271,6 @@
    * for the attributes and children of the created element.
    *
    * @param transformer non-null reference to the the current transform-time state.
-   * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
-   * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
    *
    * @throws TransformerException
    */
@@ -430,4 +428,23 @@
       throw new TransformerException(se);
     }
   }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs)
+  	{
+  	  if(null != m_name_avt)
+  		m_name_avt.callVisitors(visitor);
+  		
+  	  if(null != m_namespace_avt)
+  		m_namespace_avt.callVisitors(visitor);
+  	}
+  		
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemExtensionCall.java b/src/org/apache/xalan/templates/ElemExtensionCall.java
index a451cda..7a107a1 100644
--- a/src/org/apache/xalan/templates/ElemExtensionCall.java
+++ b/src/org/apache/xalan/templates/ElemExtensionCall.java
@@ -406,4 +406,17 @@
     return null;
   }
   
+  /**
+   * Accept a visitor and call the appropriate method 
+   * for this class.
+   * 
+   * @param visitor The visitor whose appropriate method will be called.
+   * @return true if the children of the object should be visited.
+   */
+  protected boolean accept(XSLTVisitor visitor)
+  {
+  	return visitor.visitExtensionElement(this);
+  }
+
+  
 }
diff --git a/src/org/apache/xalan/templates/ElemForEach.java b/src/org/apache/xalan/templates/ElemForEach.java
index 7ea5e28..548f64c 100644
--- a/src/org/apache/xalan/templates/ElemForEach.java
+++ b/src/org/apache/xalan/templates/ElemForEach.java
@@ -68,6 +68,7 @@
 import org.xml.sax.*;
 
 import org.apache.xpath.*;
+import org.apache.xpath.Expression;
 import org.apache.xpath.axes.ContextNodeList;
 import org.apache.xpath.objects.XObject;
 
@@ -84,6 +85,7 @@
 
 import javax.xml.transform.SourceLocator;
 import javax.xml.transform.TransformerException;
+import org.apache.xpath.ExpressionOwner;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -103,7 +105,7 @@
  * </pre>
  * @see <a href="http://www.w3.org/TR/xslt#for-each">for-each in XSLT Specification</a>
  */
-public class ElemForEach extends ElemTemplateElement
+public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
 {
   /** Set true to request some basic status reports */
   static final boolean DEBUG = false;
@@ -333,7 +335,6 @@
   {
 
     NodeSorter sorter = new NodeSorter(xctxt);
-
     sourceNodes.setShouldCacheNodes(true);
     sourceNodes.runTo(-1);
     xctxt.pushContextNodeList(sourceNodes);
@@ -367,23 +368,25 @@
     final XPathContext xctxt = transformer.getXPathContext();
     final int sourceNode = xctxt.getCurrentNode();
     DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt,
-                                sourceNode);
+            sourceNode);
 
     try
     {
 
       final Vector keys = (m_sortElems == null)
-                          ? null
-                          : transformer.processSortKeys(this, sourceNode);
+              ? null
+              : transformer.processSortKeys(this, sourceNode);
 
       // Sort if we need to.
       if (null != keys)
         sourceNodes = sortNodes(xctxt, keys, sourceNodes);
 
       if (TransformerImpl.S_DEBUG)
+      {
         transformer.getTraceManager().fireSelectedEvent(sourceNode, this,
                 "select", new XPath(m_selectExpression),
                 new org.apache.xpath.objects.XNodeSet(sourceNodes));
+      }
 
       final ResultTreeHandler rth = transformer.getResultTreeHandler();
       ContentHandler chandler = rth.getContentHandler();
@@ -397,7 +400,7 @@
 
       int[] currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
       int currentExpressionNodePos =
-        xctxt.getCurrentExpressionNodesFirstFree() - 1;
+              xctxt.getCurrentExpressionNodesFirstFree() - 1;
 
       xctxt.pushSAXLocatorNull();
       xctxt.pushContextNodeList(sourceNodes);
@@ -431,31 +434,31 @@
         // Loop through the children of the template, calling execute on 
         // each of them.
         for (ElemTemplateElement t = this.m_firstChild; t != null;
-                t = t.m_nextSibling)
+             t = t.m_nextSibling)
         {
           xctxt.setSAXLocator(t);
           transformer.setCurrentElement(t);
           t.execute(transformer);
         }
 
-	// KLUGE: Implement <?xalan:doc_cache_off?> 
-	// ASSUMPTION: This will be set only when the XPath was indeed
-	// a call to the Document() function. Calling it in other
-	// situations is likely to fry Xalan.
-	//
-	// %REVIEW% We need a MUCH cleaner solution -- one that will
-	// handle cleaning up after document() and getDTM() in other
-	// contexts. The whole SourceTreeManager mechanism should probably
-	// be moved into DTMManager rather than being explicitly invoked in
-	// FuncDocument and here.
-	if(m_doc_cache_off)
-	{
-	  if(DEBUG)
-	    System.out.println("JJK***** CACHE RELEASE *****\n"+
-			       "\tdtm="+dtm.getDocumentBaseURI());
-	  xctxt.getSourceTreeManager().removeDocumentFromCache(dtm.getDocument());
-	  xctxt.release(dtm,false);
-	}
+        // KLUGE: Implement <?xalan:doc_cache_off?>
+        // ASSUMPTION: This will be set only when the XPath was indeed
+        // a call to the Document() function. Calling it in other
+        // situations is likely to fry Xalan.
+        //
+        // %REVIEW% We need a MUCH cleaner solution -- one that will
+        // handle cleaning up after document() and getDTM() in other
+        // contexts. The whole SourceTreeManager mechanism should probably
+        // be moved into DTMManager rather than being explicitly invoked in
+        // FuncDocument and here.
+        if(m_doc_cache_off)
+        {
+          if(DEBUG)
+            System.out.println("JJK***** CACHE RELEASE *****\n"+
+                    "\tdtm="+dtm.getDocumentBaseURI());
+          xctxt.getSourceTreeManager().removeDocumentFromCache(dtm.getDocument());
+          xctxt.release(dtm,false);
+        }
       }
     }
     finally
@@ -500,4 +503,41 @@
     else
       return super.appendChild(newChild);
   }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  public void callChildVisitors(XSLTVisitor visitor, boolean callAttributes)
+  {
+  	if(callAttributes && (null != m_selectExpression))
+  		m_selectExpression.callVisitors(this, visitor);
+  		
+    int length = getSortElemCount();
+
+    for (int i = 0; i < length; i++)
+    {
+      getSortElem(i).callVisitors(visitor);
+    }
+
+    super.callChildVisitors(visitor, callAttributes);
+  }
+
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_selectExpression;
+  }
+
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+  	exp.exprSetParent(this);
+  	m_selectExpression = exp;
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemIf.java b/src/org/apache/xalan/templates/ElemIf.java
index c435103..852492c 100644
--- a/src/org/apache/xalan/templates/ElemIf.java
+++ b/src/org/apache/xalan/templates/ElemIf.java
@@ -119,7 +119,7 @@
    * values that may be based on some other property that
    * depends on recomposition.
    *
-   * NEEDSDOC @param sroot
+   * @param sroot The root stylesheet.
    *
    * @throws TransformerException
    */
@@ -200,4 +200,16 @@
       transformer.executeChildTemplates(this, true);
     }
   }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs)
+  		m_test.getExpression().callVisitors(m_test, visitor);
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemLiteralResult.java b/src/org/apache/xalan/templates/ElemLiteralResult.java
index 9f97047..523ad6b 100644
--- a/src/org/apache/xalan/templates/ElemLiteralResult.java
+++ b/src/org/apache/xalan/templates/ElemLiteralResult.java
@@ -737,4 +737,36 @@
   {
     return (null == m_avts) ? null : m_avts.elements();
   }
+  
+    /**
+     * Accept a visitor and call the appropriate method 
+     * for this class.
+     * 
+     * @param visitor The visitor whose appropriate method will be called.
+     * @return true if the children of the object should be visited.
+     */
+    protected boolean accept(XSLTVisitor visitor)
+    {
+      return visitor.visitLiteralResultElement(this);
+    }
+
+    /**
+     * Call the children visitors.
+     * @param visitor The visitor whose appropriate method will be called.
+     */
+    protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+    {
+      if (callAttrs && null != m_avts)
+      {
+        int nAttrs = m_avts.size();
+
+        for (int i = (nAttrs - 1); i >= 0; i--)
+        {
+          AVT avt = (AVT) m_avts.elementAt(i);
+          avt.callVisitors(visitor);
+        }
+      }
+      super.callChildVisitors(visitor, callAttrs);
+    }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemNumber.java b/src/org/apache/xalan/templates/ElemNumber.java
index 0053146..06a458b 100644
--- a/src/org/apache/xalan/templates/ElemNumber.java
+++ b/src/org/apache/xalan/templates/ElemNumber.java
@@ -1949,6 +1949,37 @@
 
     return roman;
   }  // end long2roman
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  public void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs)
+  	{
+	  	if(null != m_countMatchPattern)
+	  		m_countMatchPattern.getExpression().callVisitors(m_countMatchPattern, visitor);
+	  	if(null != m_fromMatchPattern)
+	  		m_fromMatchPattern.getExpression().callVisitors(m_fromMatchPattern, visitor);
+	  	if(null != m_valueExpr)
+	  		m_valueExpr.getExpression().callVisitors(m_valueExpr, visitor);
+	
+	  	if(null != m_format_avt)
+	  		m_format_avt.callVisitors(visitor);
+	  	if(null != m_groupingSeparator_avt)
+	  		m_groupingSeparator_avt.callVisitors(visitor);
+	  	if(null != m_groupingSize_avt)
+	  		m_groupingSize_avt.callVisitors(visitor);
+	  	if(null != m_lang_avt)
+	  		m_lang_avt.callVisitors(visitor);
+	  	if(null != m_lettervalue_avt)
+	  		m_lettervalue_avt.callVisitors(visitor);
+  	}
+
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 
   /**
    * This class returns tokens using non-alphanumberic
@@ -2101,4 +2132,5 @@
       return count;
     }
   }  // end NumberFormatStringTokenizer
+
 }
diff --git a/src/org/apache/xalan/templates/ElemTemplateElement.java b/src/org/apache/xalan/templates/ElemTemplateElement.java
index 649134c..3c7e9ed 100644
--- a/src/org/apache/xalan/templates/ElemTemplateElement.java
+++ b/src/org/apache/xalan/templates/ElemTemplateElement.java
@@ -76,6 +76,7 @@
 import org.apache.xalan.transformer.ResultTreeHandler;
 import org.apache.xpath.VariableStack;
 import org.apache.xpath.WhitespaceStrippingElementMatcher;
+import org.apache.xpath.ExpressionNode;
 
 // TRaX imports
 import javax.xml.transform.Templates;
@@ -109,8 +110,8 @@
  * @see Stylesheet
  */
 public class ElemTemplateElement extends UnImplNode
-        implements PrefixResolver, Serializable, SourceLocator, 
-                   WhitespaceStrippingElementMatcher
+        implements PrefixResolver, Serializable, ExpressionNode, 
+                   WhitespaceStrippingElementMatcher, XSLTVisitable
 {
 
   /**
@@ -506,6 +507,76 @@
     // oldChildElem.m_stylesheet = null;
     return newChildElem;
   }
+  
+  /**
+   * Unimplemented. See org.w3c.dom.Node
+   *
+   * @param newChild New child node to insert
+   * @param refChild Insert in front of this child
+   *
+   * @return null
+   *
+   * @throws DOMException
+   */
+  public Node insertBefore(Node newChild, Node refChild) throws DOMException
+  {
+  	if(null == refChild)
+  	{
+  		appendChild(newChild);
+  		return newChild;
+  	}
+  	
+  	if(newChild == refChild)
+  	{
+  		// hmm...
+  		return newChild;
+  	}
+
+    Node node = m_firstChild; 
+    Node prev = null;  
+    boolean foundit = false;
+    
+    while (null != node)
+    {
+    	// If the newChild is already in the tree, it is first removed.
+    	if(newChild == node)
+    	{
+    		if(null != prev)
+    			((ElemTemplateElement)prev).m_nextSibling = 
+    				(ElemTemplateElement)node.getNextSibling();
+    		else
+    			m_firstChild = (ElemTemplateElement)node.getNextSibling();
+    		node = node.getNextSibling();
+    		continue; // prev remains the same.
+    	}
+    	if(refChild == node)
+    	{
+    		if(null != prev)
+    		{
+    			((ElemTemplateElement)prev).m_nextSibling = (ElemTemplateElement)newChild;
+    		}
+    		else
+    		{
+    			m_firstChild = (ElemTemplateElement)newChild;
+    		}
+    		((ElemTemplateElement)newChild).m_nextSibling = (ElemTemplateElement)refChild;
+    		((ElemTemplateElement)newChild).setParentElem(this);
+    		prev = newChild;
+    		node = node.getNextSibling();
+    		foundit = true;
+    		continue;
+    	}
+    	prev = node;
+    	node = node.getNextSibling();
+    }
+    
+    if(!foundit)
+    	throw new DOMException(DOMException.NOT_FOUND_ERR, 
+    		"refChild was not found in insertBefore method!");
+    else
+    	return newChild;
+  }
+
 
   /**
    * Replace the old child with a new child.
@@ -1471,5 +1542,105 @@
     StylesheetRoot sroot = this.getStylesheetRoot();
     return (null != sroot) ? sroot.canStripWhiteSpace() : false;
   }
+  
+  /**
+   * Tell if this element can accept variable declarations.
+   * @return true if the element can accept and process variable declarations.
+   */
+  public boolean canAcceptVariables()
+  {
+  	return true;
+  }
+  
+  //=============== ExpressionNode methods ================
+  
+  /** 
+   * Set the parent of this node.
+   * @param n Must be a ElemTemplateElement.
+   */
+  public void exprSetParent(ExpressionNode n)
+  {
+  	// This obviously requires that only a ElemTemplateElement can 
+  	// parent a node of this type.
+  	setParentElem((ElemTemplateElement)n);
+  }
+  
+  /**
+   * Get the ExpressionNode parent of this node.
+   */
+  public ExpressionNode exprGetParent()
+  {
+  	return getParentElem();
+  }
+
+  /** 
+   * This method tells the node to add its argument to the node's
+   * list of children. 
+   * @param n Must be a ElemTemplateElement. 
+   */
+  public void exprAddChild(ExpressionNode n, int i)
+  {
+  	appendChild((ElemTemplateElement)n);
+  }
+
+  /** This method returns a child node.  The children are numbered
+     from zero, left to right. */
+  public ExpressionNode exprGetChild(int i)
+  {
+  	return (ExpressionNode)item(i);
+  }
+
+  /** Return the number of children the node has. */
+  public int exprGetNumChildren()
+  {
+  	return getLength();
+  }
+  
+  /**
+   * Accept a visitor and call the appropriate method 
+   * for this class.
+   * 
+   * @param visitor The visitor whose appropriate method will be called.
+   * @return true if the children of the object should be visited.
+   */
+  protected boolean accept(XSLTVisitor visitor)
+  {
+  	return visitor.visitInstruction(this);
+  }
+
+  /**
+   * @see XSLTVisitable#callVisitors(XSLTVisitor)
+   */
+  public void callVisitors(XSLTVisitor visitor)
+  {
+  	if(accept(visitor))
+  	{
+		callChildVisitors(visitor);
+  	}
+  }
+
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttributes)
+  {
+    for (ElemTemplateElement node = m_firstChild;
+      node != null;
+      node = node.m_nextSibling)
+      {
+      node.callVisitors(visitor);
+    }
+  }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor)
+  {
+  	callChildVisitors(visitor, true);
+  }
+
 
 }
diff --git a/src/org/apache/xalan/templates/ElemValueOf.java b/src/org/apache/xalan/templates/ElemValueOf.java
index 4140f8e..16f0889 100644
--- a/src/org/apache/xalan/templates/ElemValueOf.java
+++ b/src/org/apache/xalan/templates/ElemValueOf.java
@@ -355,4 +355,16 @@
     //" to " + this.m_elemName);
     return null;
   }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs)
+  		m_selectExpression.getExpression().callVisitors(m_selectExpression, visitor);
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemVariable.java b/src/org/apache/xalan/templates/ElemVariable.java
index da3873e..cde6218 100644
--- a/src/org/apache/xalan/templates/ElemVariable.java
+++ b/src/org/apache/xalan/templates/ElemVariable.java
@@ -62,6 +62,7 @@
 import org.xml.sax.*;
 
 import org.apache.xpath.*;
+import org.apache.xpath.Expression;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.objects.XString;
 import org.apache.xpath.objects.XRTreeFrag;
@@ -459,5 +460,44 @@
     super.setParentElem(p);
     p.m_hasVariableDecl = true;
   }
+  
+  /**
+   * Accept a visitor and call the appropriate method 
+   * for this class.
+   * 
+   * @param visitor The visitor whose appropriate method will be called.
+   * @return true if the children of the object should be visited.
+   */
+  protected boolean accept(XSLTVisitor visitor)
+  {
+  	return visitor.visitVariableOrParamDecl(this);
+  }
+
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(null != m_selectPattern)
+  		m_selectPattern.getExpression().callVisitors(m_selectPattern, visitor);
+    super.callChildVisitors(visitor, callAttrs);
+  }
+  
+  /**
+   * Tell if this is a psuedo variable reference, declared by Xalan instead 
+   * of by the user.
+   */
+  public boolean isPsuedoVar()
+  {
+  	java.lang.String ns = m_qname.getNamespaceURI();
+  	if((null != ns) && ns.equals(RedundentExprEliminator.PSUEDOVARNAMESPACE))
+  	{
+  		if(m_qname.getLocalName().startsWith("#"))
+  			return true;
+  	}
+  	return false;
+  }
 
 }
diff --git a/src/org/apache/xalan/templates/ElemVariablePsuedo.java b/src/org/apache/xalan/templates/ElemVariablePsuedo.java
new file mode 100644
index 0000000..cab5d10
--- /dev/null
+++ b/src/org/apache/xalan/templates/ElemVariablePsuedo.java
@@ -0,0 +1,48 @@
+package org.apache.xalan.templates;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xpath.XPath;
+
+public class ElemVariablePsuedo extends ElemVariable
+{
+  XUnresolvedVariableSimple m_lazyVar;
+	
+  /**
+   * Set the "select" attribute.
+   * If the variable-binding element has a select attribute,
+   * then the value of the attribute must be an expression and
+   * the value of the variable is the object that results from
+   * evaluating the expression. In this case, the content
+   * of the variable must be empty.
+   *
+   * @param v Value to set for the "select" attribute.
+   */
+  public void setSelect(XPath v)
+  {
+    super.setSelect(v);
+    m_lazyVar = new XUnresolvedVariableSimple(this);
+  }
+  
+  /**
+   * Execute a variable declaration and push it onto the variable stack.
+   * @see <a href="http://www.w3.org/TR/xslt#variables">variables in XSLT Specification</a>
+   *
+   * @param transformer non-null reference to the the current transform-time state.
+   * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
+   * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
+   *
+   * @throws TransformerException
+   */
+  public void execute(TransformerImpl transformer) throws TransformerException
+  {
+
+    // if (TransformerImpl.S_DEBUG)
+    //  transformer.getTraceManager().fireTraceEvent(this);
+
+    // transformer.getXPathContext().getVarStack().pushVariable(m_qname, var);
+    transformer.getXPathContext().getVarStack().setLocalVariable(m_index, m_lazyVar);
+  }
+
+}
+
diff --git a/src/org/apache/xalan/templates/ElemWhen.java b/src/org/apache/xalan/templates/ElemWhen.java
index d1f8c6a..331d24a 100644
--- a/src/org/apache/xalan/templates/ElemWhen.java
+++ b/src/org/apache/xalan/templates/ElemWhen.java
@@ -152,4 +152,16 @@
    *
    */
   public ElemWhen(){}
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs)
+  		m_test.getExpression().callVisitors(m_test, visitor);
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 }
diff --git a/src/org/apache/xalan/templates/ElemWithParam.java b/src/org/apache/xalan/templates/ElemWithParam.java
index d6be1d5..56dc42c 100644
--- a/src/org/apache/xalan/templates/ElemWithParam.java
+++ b/src/org/apache/xalan/templates/ElemWithParam.java
@@ -265,6 +265,18 @@
 
     return var;
   }
+  
+  /**
+   * Call the children visitors.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+  {
+  	if(callAttrs && (null != m_selectPattern))
+  		m_selectPattern.getExpression().callVisitors(m_selectPattern, visitor);
+    super.callChildVisitors(visitor, callAttrs);
+  }
+
 
 
 }
diff --git a/src/org/apache/xalan/templates/FuncDocument.java b/src/org/apache/xalan/templates/FuncDocument.java
index 14a551b..993f70d 100644
--- a/src/org/apache/xalan/templates/FuncDocument.java
+++ b/src/org/apache/xalan/templates/FuncDocument.java
@@ -179,6 +179,7 @@
       // the tree representation of the stylesheet is exactly 
       // the same as if the XML document containing the stylesheet 
       // was the initial source document.
+      assertion(null != xctxt.getNamespaceContext(), "Namespace context can not be null!");
       base = xctxt.getNamespaceContext().getBaseIdentifier();
     }
 
diff --git a/src/org/apache/xalan/templates/FuncKey.java b/src/org/apache/xalan/templates/FuncKey.java
index 4becc12..a9be865 100644
--- a/src/org/apache/xalan/templates/FuncKey.java
+++ b/src/org/apache/xalan/templates/FuncKey.java
@@ -117,6 +117,16 @@
     XObject arg = getArg1().execute(xctxt);
     boolean argIsNodeSetDTM = (XObject.CLASS_NODESET == arg.getType());
     KeyManager kmgr = transformer.getKeyManager();
+    
+    // Don't bother with nodeset logic if the thing is only one node.
+    if(argIsNodeSetDTM)
+    {
+    	XNodeSet ns = (XNodeSet)arg;
+    	ns.setShouldCacheNodes(true);
+    	int len = ns.getLength();
+    	if(len <= 1)
+    		argIsNodeSetDTM = false;
+    }
 
     if (argIsNodeSetDTM)
     {
@@ -124,6 +134,7 @@
       DTMIterator ni = arg.iter();
       int pos;
       UnionPathIterator upi = new UnionPathIterator();
+      upi.exprSetParent(this);
 
       while (DTM.NULL != (pos = ni.nextNode()))
       {
@@ -147,13 +158,15 @@
           usedrefs.put(ref, ISTRUE);
         }
 
-        LocPathIterator nl =
+        XNodeSet nl =
           kmgr.getNodeSetDTMByKey(xctxt, docContext, keyname, ref,
                                xctxt.getNamespaceContext());
+                               
+        nl.setRoot(xctxt.getCurrentNode(), xctxt);
 
 //        try
 //        {
-          upi.addIterator((LocPathIterator)nl.asIterator(xctxt, docContext));
+          upi.addIterator(nl);
 //        }
 //        catch(CloneNotSupportedException cnse)
 //        {
@@ -170,18 +183,10 @@
     else
     {
       XMLString ref = arg.xstr();
-      LocPathIterator nl = kmgr.getNodeSetDTMByKey(xctxt, docContext, keyname,
+      nodes = kmgr.getNodeSetDTMByKey(xctxt, docContext, keyname,
                                                 ref,
                                                 xctxt.getNamespaceContext());
-
-      try
-      {
-        nodes = new XNodeSet((LocPathIterator)nl.cloneWithReset());
-      }
-      catch(CloneNotSupportedException cnse)
-      {
-        // will never happen.
-      }
+      nodes.setRoot(xctxt.getCurrentNode(), xctxt);
     }
 
     return nodes;
diff --git a/src/org/apache/xalan/templates/RedundentExprEliminator.java b/src/org/apache/xalan/templates/RedundentExprEliminator.java
new file mode 100644
index 0000000..df42ed4
--- /dev/null
+++ b/src/org/apache/xalan/templates/RedundentExprEliminator.java
@@ -0,0 +1,1470 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xalan.templates;
+
+import java.util.Vector;
+
+import org.apache.xml.utils.QName;
+import org.apache.xml.utils.WrappedRuntimeException;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionNode;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPath;
+import org.apache.xpath.axes.AxesWalker;
+import org.apache.xpath.axes.FilterExprIteratorSimple;
+import org.apache.xpath.axes.FilterExprWalker;
+import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.axes.SelfIteratorNoPredicate;
+import org.apache.xpath.axes.WalkerFactory;
+import org.apache.xpath.axes.WalkingIterator;
+import org.apache.xpath.operations.Variable;
+import org.apache.xpath.operations.VariableSafeAbsRef;
+import org.w3c.dom.DOMException;
+
+/**
+ * This class eleminates redundent XPaths from a given subtree, 
+ * and also collects all absolute paths within the subtree.  First 
+ * it must be called as a visitor to the subtree, and then 
+ * eleminateRedundent must be called.
+ */
+public class RedundentExprEliminator extends XSLTVisitor
+{
+  Vector m_paths;
+  Vector m_absPaths;
+  boolean m_isSameContext;
+  AbsPathChecker m_absPathChecker = new AbsPathChecker();
+  
+  static int m_uniquePsuedoVarID = 1;
+  static final String PSUEDOVARNAMESPACE = Constants.S_VENDORURL+"/xalan/psuedovar";
+ 
+  public static boolean DEBUG = false;
+  public static boolean DIAGNOSE_NUM_PATHS_REDUCED = false;
+  public static boolean DIAGNOSE_MULTISTEPLIST = false;
+
+  /**
+   * So we can reuse it over and over again.
+   */
+  VarNameCollector m_varNameCollector = new VarNameCollector();
+
+  /**
+   * Construct a RedundentExprEliminator.
+   * 
+   * @param absPathsList Vector to which absolute paths will 
+   * be inserted.  The vector may be null, if the caller does 
+   * not wish to collect absolute paths.
+   */
+  public RedundentExprEliminator()
+  {
+    m_isSameContext = true;
+    m_absPaths = new Vector();
+    m_paths = null;
+  }
+  
+  
+  /**
+   * Method to be called after the all expressions within an  
+   * node context have been visited.  It eliminates redundent 
+   * expressions by creating a variable in the psuedoVarRecipient 
+   * for each redundent expression, and then rewriting the redundent 
+   * expression to be a variable reference.
+   * 
+   * @param psuedoVarRecipient The recipient of the psuedo vars.  The 
+   * variables will be inserted as first children of the element, before 
+   * any existing variables.
+   */
+  public void eleminateRedundentLocals(ElemTemplateElement psuedoVarRecipient)
+  {
+    eleminateRedundent(psuedoVarRecipient, m_paths);
+  }
+  
+  /**
+   * Method to be called after the all global expressions within a stylesheet 
+   * have been collected.  It eliminates redundent 
+   * expressions by creating a variable in the psuedoVarRecipient 
+   * for each redundent expression, and then rewriting the redundent 
+   * expression to be a variable reference.
+   * 
+   * @param psuedoVarRecipient The recipient of the psuedo vars.  The 
+   * variables will be inserted as first children of the element, before 
+   * any existing variables.
+   */
+  public void eleminateRedundentGlobals(StylesheetRoot stylesheet)
+  {
+    eleminateRedundent(stylesheet, m_absPaths);
+  }
+
+  
+  /**
+   * Method to be called after the all expressions within an  
+   * node context have been visited.  It eliminates redundent 
+   * expressions by creating a variable in the psuedoVarRecipient 
+   * for each redundent expression, and then rewriting the redundent 
+   * expression to be a variable reference.
+   * 
+   * @param psuedoVarRecipient The owner of the subtree from where the 
+   *                           paths were collected.
+   * @param paths A vector of paths that hold ExpressionOwner objects, 
+   *              which must yield LocationPathIterators.
+   */
+  protected void eleminateRedundent(ElemTemplateElement psuedoVarRecipient, Vector paths)
+  {
+    int n = paths.size();
+    int numPathsEliminated = 0;
+    int numUniquePathsEliminated = 0;
+    for (int i = 0; i < n; i++)
+    {
+      ExpressionOwner owner = (ExpressionOwner) paths.elementAt(i);
+      if (null != owner)
+      {
+        int found = findAndEliminateRedundant(i + 1, i, owner, psuedoVarRecipient, paths);
+        if (found > 0)
+                  numUniquePathsEliminated++;
+        numPathsEliminated += found;
+      }
+    }
+    
+    eleminateSharedPartialPaths(psuedoVarRecipient, paths);
+    
+    if(DIAGNOSE_NUM_PATHS_REDUCED)
+		diagnoseNumPaths(paths, numPathsEliminated, numUniquePathsEliminated);
+  }
+  
+  /**
+   * Eliminate the shared partial paths in the expression list.
+   * 
+   * @param psuedoVarRecipient The recipient of the psuedo vars.
+   * 
+   * @param paths A vector of paths that hold ExpressionOwner objects, 
+   *              which must yield LocationPathIterators.
+   */
+  protected void eleminateSharedPartialPaths(ElemTemplateElement psuedoVarRecipient, Vector paths)
+  {
+  	MultistepExprHolder list = createMultistepExprList(paths);
+  	if(null != list)
+  	{
+  		if(DIAGNOSE_MULTISTEPLIST)
+        	list.diagnose();
+        	
+        boolean isGlobal = (paths == m_absPaths);
+        	
+        // Iterate over the list, starting with the most number of paths, 
+        // trying to find the longest matches first.
+        int longestStepsCount = list.m_stepCount;
+    	for (int i = longestStepsCount-1; i >= 1; i--)
+    	{
+    		MultistepExprHolder next = list;
+        	while(null != next)
+        	{
+        		if(next.m_stepCount < i)
+        			break;
+				list = matchAndEliminatePartialPaths(next, list, isGlobal, i, psuedoVarRecipient);
+				next = next.m_next;
+        	}
+    	}
+  	}
+  }
+
+  /**
+   * For a given path, see if there are any partitial matches in the list, 
+   * and, if there are, replace those partial paths with psuedo variable refs,
+   * and create the psuedo variable decl.
+   * 
+   * @return The head of the list, which may have changed.
+   */
+  protected MultistepExprHolder matchAndEliminatePartialPaths(MultistepExprHolder testee, 
+                                               MultistepExprHolder head,
+                                               boolean isGlobal,
+                                               int lengthToTest,
+                                               ElemTemplateElement varScope)
+  {  	
+  	if(null == testee.m_exprOwner)
+  		return head;
+  		
+    // Start with the longest possible match, and move down.
+    WalkingIterator iter1 = (WalkingIterator) testee.m_exprOwner.getExpression();
+    if(partialIsVariable(testee, lengthToTest))
+    	return head;
+    MultistepExprHolder matchedPaths = null;
+    MultistepExprHolder matchedPathsTail = null;
+    MultistepExprHolder meh = head;
+    while( null != meh)
+    {
+      if ((meh != testee) && (null != meh.m_exprOwner))
+      {
+	      WalkingIterator iter2 = (WalkingIterator) meh.m_exprOwner.getExpression();
+	      if (stepsEqual(iter1, iter2, lengthToTest))
+	      {
+	        if (null == matchedPaths)
+	        {
+	          try
+	          {
+	          	matchedPaths = (MultistepExprHolder)testee.clone();
+	          	testee.m_exprOwner = null; // So it won't be processed again.
+	          }
+	          catch(CloneNotSupportedException cnse){}
+	          matchedPathsTail = matchedPaths;
+	          matchedPathsTail.m_next = null;
+	        }
+	       
+	        try
+	        {
+	          matchedPathsTail.m_next = (MultistepExprHolder)meh.clone();
+	          meh.m_exprOwner = null; // So it won't be processed again.
+	        }
+	        catch(CloneNotSupportedException cnse){}
+	        matchedPathsTail = matchedPathsTail.m_next;
+	        matchedPathsTail.m_next = null;
+	      }
+      }
+      meh = meh.m_next;
+    }
+    	
+	int matchCount = 0;
+	if(null != matchedPaths)
+	{
+		ElemTemplateElement root = isGlobal ? varScope : findCommonAncestor(matchedPaths);
+		WalkingIterator sharedIter = (WalkingIterator)matchedPaths.m_exprOwner.getExpression();
+		WalkingIterator newIter = createIteratorFromSteps(sharedIter, lengthToTest);
+		ElemVariable var = createPsuedoVarDecl(root, newIter, isGlobal);
+		if(DIAGNOSE_MULTISTEPLIST)
+			System.err.println("Created var: "+var.getName()+(isGlobal ? "(Global)" : ""));
+		while(null != matchedPaths)
+		{
+			ExpressionOwner owner = matchedPaths.m_exprOwner;
+			WalkingIterator iter = (WalkingIterator)owner.getExpression();
+			
+			if(DIAGNOSE_MULTISTEPLIST)
+				diagnoseLineNumber(iter);
+			
+			LocPathIterator newIter2 = 
+			    changePartToRef(var.getName(), iter, lengthToTest, isGlobal);
+			owner.setExpression(newIter2);
+			
+			matchedPaths = matchedPaths.m_next;
+		}
+	}
+	
+	if(DIAGNOSE_MULTISTEPLIST)
+		diagnoseMultistepList(matchCount, lengthToTest, isGlobal);
+    return head;
+  }
+  
+  /**
+   * Check if results of partial reduction will just be a variable, in 
+   * which case, skip it.
+   */
+  boolean partialIsVariable(MultistepExprHolder testee, int lengthToTest)
+  {
+  	if(1 == lengthToTest)
+  	{
+  		WalkingIterator wi = (WalkingIterator)testee.m_exprOwner.getExpression();
+  		if(wi.getFirstWalker() instanceof FilterExprWalker)
+  			return true;
+  	}
+  	return false;
+  }
+
+  /**
+   * Tell what line number belongs to a given expression.
+   */
+  protected void diagnoseLineNumber(Expression expr)
+  {
+    ElemTemplateElement e = getElemFromExpression(expr);
+    System.err.println("   " + e.getSystemId() + " Line " + e.getLineNumber());
+  }
+      
+  /**
+   * Given a linked list of expressions, find the common ancestor that is 
+   * suitable for holding a psuedo variable for shared access.
+   */
+  protected ElemTemplateElement findCommonAncestor(MultistepExprHolder head)
+  {
+  	// Not sure this algorithm is the best, but will do for the moment.
+  	int numExprs = head.getLength();
+  	// The following could be made cheaper by pre-allocating large arrays, 
+  	// but then we would have to assume a max number of reductions, 
+  	// which I am not inclined to do right now.
+    ElemTemplateElement[] elems = new ElemTemplateElement[numExprs];
+    int[] ancestorCounts = new int[numExprs];
+    
+    // Loop through, getting the parent elements, and counting the 
+    // ancestors.
+  	MultistepExprHolder next = head;
+  	int shortestAncestorCount = 10000;
+  	for(int i = 0; i < numExprs; i++)
+  	{
+  		ElemTemplateElement elem = 
+  			getElemFromExpression(next.m_exprOwner.getExpression());
+  		elems[i] = elem;
+  		int numAncestors = countAncestors(elem);
+  		ancestorCounts[i] = numAncestors;
+  		if(numAncestors < shortestAncestorCount)
+  		{
+  			shortestAncestorCount = numAncestors;
+  		}
+  		next = next.m_next;
+  	}
+  	
+  	// Now loop through and "correct" the elements that have more ancestors.
+  	for(int i = 0; i < numExprs; i++)
+  	{
+  		if(ancestorCounts[i] > shortestAncestorCount)
+  		{
+  			int numStepCorrection = ancestorCounts[i] - shortestAncestorCount;
+  			for(int j = 0; j < numStepCorrection; j++)
+  			{
+  				elems[i] = elems[i].getParentElem();
+  			}
+  		}
+  	}
+  	
+  	// Now everyone has an equal number of ancestors.  Walk up from here 
+  	// equally until all are equal.
+  	ElemTemplateElement first = null;
+  	while(shortestAncestorCount-- >= 0)
+  	{
+  		boolean areEqual = true;
+  		first = elems[0];
+  		for(int i = 1; i < numExprs; i++)
+  		{
+  			if(first != elems[i])
+  			{
+  				areEqual = false;
+  				break;
+  			}
+  		}
+  		// This second check is to make sure we have a common ancestor that is not the same 
+  		// as the expression owner... i.e. the var decl has to go above the expression owner.
+  		if(areEqual && isNotSameAsOwner(head, first) && first.canAcceptVariables())
+  		{
+  			if(DIAGNOSE_MULTISTEPLIST)
+  			{
+  				System.err.print(first.getClass().getName());
+  				System.err.println(" at   " + first.getSystemId() + " Line " + first.getLineNumber());
+  			}
+  			return first;
+  		}
+   			
+  		for(int i = 0; i < numExprs; i++)
+  		{
+  			elems[i] = elems[i].getParentElem();
+  		}
+  	}
+  	
+  	assert(false, "Could not find common ancestor!!!");
+  	return null;
+  }
+  
+  /**
+   * Find out if the given ElemTemplateElement is not the same as one of 
+   * the ElemTemplateElement owners of the expressions.
+   * 
+   * @param head Head of linked list of expression owners.
+   * @param ete The ElemTemplateElement that is a candidate for a psuedo 
+   * variable parent.
+   * @return true if the given ElemTemplateElement is not the same as one of 
+   * the ElemTemplateElement owners of the expressions.  This is to make sure 
+   * we find an ElemTemplateElement that is in a viable position to hold 
+   * psuedo variables that are visible to the references.
+   */
+  protected boolean isNotSameAsOwner(MultistepExprHolder head, ElemTemplateElement ete)
+  {
+  	MultistepExprHolder next = head;
+  	while(null != next)
+  	{
+  		ElemTemplateElement elemOwner = getElemFromExpression(next.m_exprOwner.getExpression());
+  		if(elemOwner == ete)
+  			return false;
+  		next = next.m_next;
+  	}
+  	return true;
+  }
+  
+  /**
+   * Count the number of ancestors that a ElemTemplateElement has.
+   * 
+   * @param elem An representation of an element in an XSLT stylesheet.
+   * @return The number of ancestors of elem (including the element itself).
+   */
+  protected int countAncestors(ElemTemplateElement elem)
+  {
+  	int count = 0;
+  	while(null != elem)
+  	{
+  		count++;
+  		elem = elem.getParentElem();
+  	}
+  	return count;
+  }
+
+  /**
+   * Print out diagnostics about partial multistep evaluation.
+   */
+  protected void diagnoseMultistepList(
+      int matchCount,
+      int lengthToTest,
+      boolean isGlobal)
+  {
+      if (matchCount > 0)
+        {
+        System.err.print(
+          "Found multistep matches: " + matchCount + ", " + lengthToTest + " length");
+        if (isGlobal)
+              System.err.println(" (global)");
+        else
+              System.err.println();
+      }
+  }
+  
+  /**
+   * Change a given number of steps to a single variable reference.
+   * 
+   * @param uniquePsuedoVarName The name of the variable reference.
+   * @param wi The walking iterator that is to be changed.
+   * @param numSteps The number of steps to be changed.
+   * @param isGlobal true if this will be a global reference.
+   */
+  protected LocPathIterator changePartToRef(final QName uniquePsuedoVarName, WalkingIterator wi, 
+                                 final int numSteps, final boolean isGlobal)
+  {
+  	Variable var = new Variable();
+  	var.setQName(uniquePsuedoVarName);
+  	var.setIsGlobal(isGlobal);
+  	if(isGlobal)
+  	{	ElemTemplateElement elem = getElemFromExpression(wi);
+  		StylesheetRoot root = elem.getStylesheetRoot();
+  		Vector vars = root.getVariablesAndParamsComposed();
+  		var.setIndex(vars.size()-1);
+  	}
+  	
+  	// Walk to the first walker after the one's we are replacing.
+  	AxesWalker walker = wi.getFirstWalker();
+  	for(int i = 0; i < numSteps; i++)
+  	{
+  		assert(null != walker, "Walker should not be null!");
+  		walker = walker.getNextWalker();
+  	}
+  	
+  	if(null != walker)
+  	{
+  	
+  	  FilterExprWalker few = new FilterExprWalker(wi);
+  	  few.setInnerExpression(var);
+  	  few.exprSetParent(wi);
+  	  few.setNextWalker(walker);
+  	  walker.setPrevWalker(few);
+  	  wi.setFirstWalker(few);
+  	  return wi;
+  	}
+  	else
+  	{
+  	  FilterExprIteratorSimple feis = new FilterExprIteratorSimple(var);
+  	  feis.exprSetParent(wi.exprGetParent());
+  	  return feis;
+  	}
+  }
+  
+  /**
+   * Create a new WalkingIterator from the steps in another WalkingIterator.
+   * 
+   * @param wi The iterator from where the steps will be taken.
+   * @param numSteps The number of steps from the first to copy into the new 
+   *                 iterator.
+   * @return The new iterator.
+   */
+  protected WalkingIterator createIteratorFromSteps(final WalkingIterator wi, int numSteps)
+  {
+  	WalkingIterator newIter = new WalkingIterator(wi.getPrefixResolver());
+  	try
+  	{
+  		AxesWalker walker = (AxesWalker)wi.getFirstWalker().clone();
+  		newIter.setFirstWalker(walker);
+  		walker.setLocPathIterator(newIter);
+  		for(int i = 1; i < numSteps; i++)
+  		{
+  			AxesWalker next = (AxesWalker)walker.getNextWalker().clone();
+  			walker.setNextWalker(next);
+  			next.setLocPathIterator(newIter);
+  			walker = next;
+  		}
+  		walker.setNextWalker(null);
+  	}
+  	catch(CloneNotSupportedException cnse)
+  	{
+  		throw new WrappedRuntimeException(cnse);
+  	}
+  	return newIter;
+  }
+    
+  /**
+   * Compare a given number of steps between two iterators, to see if they are equal.
+   * 
+   * @param iter1 The first iterator to compare.
+   * @param iter2 The second iterator to compare.
+   * @param numSteps The number of steps to compare.
+   * @return true If the given number of steps are equal.
+   * 
+   */
+  protected boolean stepsEqual(WalkingIterator iter1, WalkingIterator iter2, 
+                                         int numSteps)
+  {
+  	AxesWalker aw1 = iter1.getFirstWalker();
+  	AxesWalker aw2 = iter2.getFirstWalker();
+  	
+  	for(int i = 0; (i < numSteps); i++)
+  	{
+  		if((null == aw1) || (null == aw2))
+  		 	return false;
+  		 	
+  		if(!aw1.deepEquals(aw2))
+  			return false;
+  		
+  		aw1 = aw1.getNextWalker();
+  		aw2 = aw2.getNextWalker();
+  	}
+  	
+  	assert((null != aw1) || (null != aw2), "Total match is incorrect!");
+  	
+  	return true;
+  }
+  
+  /**
+   * For the reduction of location path parts, create a list of all 
+   * the multistep paths with more than one step, sorted by the 
+   * number of steps, with the most steps occuring earlier in the list.
+   * If the list is only one member, don't bother returning it.
+   * 
+   * @param paths Vector of ExpressionOwner objects, which may contain null entries. 
+   *              The ExpressionOwner objects must own LocPathIterator objects.
+   * @return null if no multipart paths are found or the list is only of length 1, 
+   * otherwise the first MultistepExprHolder in a linked list of these objects.
+   */
+  protected MultistepExprHolder createMultistepExprList(Vector paths)
+  {
+  	MultistepExprHolder first = null;
+  	int n = paths.size();
+  	for(int i = 0; i < n; i++)
+  	{
+  		ExpressionOwner eo = (ExpressionOwner)paths.elementAt(i);
+  		if(null == eo)
+  			continue;
+  			
+  		// Assuming location path iterators should be OK.
+  		LocPathIterator lpi = (LocPathIterator)eo.getExpression();
+  		int numPaths = countSteps(lpi);
+  		if(numPaths > 1)
+  		{
+  			if(null == first)
+  				first = new MultistepExprHolder(eo, numPaths, null);
+  			else
+  				first = first.addInSortedOrder(eo, numPaths);
+  		}
+  	}
+  	
+  	if((null == first) || (first.getLength() <= 1))
+  		return null;
+  	else
+  		return first;
+  }
+  
+  /**
+   * Look through the vector from start point, looking for redundant occurances.
+   * When one or more are found, create a psuedo variable declaration, insert 
+   * it into the stylesheet, and replace the occurance with a reference to 
+   * the psuedo variable.  When a redundent variable is found, it's slot in 
+   * the vector will be replaced by null.
+   * 
+   * @param start The position to start looking in the vector.
+   * @param targetIndex The position of firstOccuranceOwner.
+   * @param firstOccuranceOwner The owner of the expression we are looking for.
+   * @param psuedoVarRecipient Where to put the psuedo variables.
+   * 
+   * @return The number of expression occurances that were modified.
+   */
+  protected int findAndEliminateRedundant(int start, int firstOccuranceIndex,
+                         ExpressionOwner firstOccuranceOwner, 
+                         ElemTemplateElement psuedoVarRecipient,
+                         Vector paths) 
+                 throws org.w3c.dom.DOMException 
+  {
+	MultistepExprHolder head = null;
+	MultistepExprHolder tail = null;
+	int numPathsFound = 0;
+	int n = paths.size();
+	
+	Expression expr1 = firstOccuranceOwner.getExpression();
+	if(DEBUG)
+		assertIsLocPathIterator(expr1, firstOccuranceOwner);
+	boolean isGlobal = (paths == m_absPaths);
+	LocPathIterator lpi = (LocPathIterator)expr1;
+	int stepCount = countSteps(lpi);
+	for(int j = start; j < n; j++)
+	{
+		ExpressionOwner owner2 = (ExpressionOwner)paths.elementAt(j);
+		if(null != owner2)
+		{
+			Expression expr2 = owner2.getExpression();
+			boolean isEqual = expr2.deepEquals(lpi);
+			if(isEqual)
+			{  		
+				LocPathIterator lpi2  = (LocPathIterator)expr2;				
+				if(null == head)
+				{
+					head = new MultistepExprHolder(firstOccuranceOwner, stepCount, null);
+					tail = head;
+					numPathsFound++;
+				}
+				tail.m_next = new MultistepExprHolder(owner2, stepCount, null);
+				tail = tail.m_next;
+	
+				// Null out the occurance, so we don't have to test it again.
+				paths.setElementAt(null, j);
+				
+				// foundFirst = true;
+				numPathsFound++;
+			}
+		}
+	}
+	
+	// Change all globals in xsl:templates, etc, to global vars no matter what.
+	if((0 == numPathsFound) && isGlobal)
+	{
+      head = new MultistepExprHolder(firstOccuranceOwner, stepCount, null);
+      numPathsFound++;
+	}
+	
+	if(null != head)
+	{
+		ElemTemplateElement root = isGlobal ? psuedoVarRecipient : findCommonAncestor(head);
+		LocPathIterator sharedIter = (LocPathIterator)head.m_exprOwner.getExpression();
+		ElemVariable var = createPsuedoVarDecl(root, sharedIter, isGlobal);
+		if(DIAGNOSE_MULTISTEPLIST)
+			System.err.println("Created var: "+var.getName()+(isGlobal ? "(Global)" : ""));
+		QName uniquePsuedoVarName = var.getName();
+		while(null != head)
+		{
+			ExpressionOwner owner = head.m_exprOwner;	
+			if(DIAGNOSE_MULTISTEPLIST)
+				diagnoseLineNumber(owner.getExpression());
+			changeToVarRef(uniquePsuedoVarName, owner, paths, root);
+			head = head.m_next;
+		}
+		// Replace the first occurance with the variable's XPath, so  
+		// that further reduction may take place if needed.
+		paths.setElementAt(var.getSelect(), firstOccuranceIndex);
+	}
+	
+	return numPathsFound;
+  } 
+  
+  /**
+   * To be removed.
+   */
+  protected int oldFindAndEliminateRedundant(int start, int firstOccuranceIndex,
+                         ExpressionOwner firstOccuranceOwner, 
+                         ElemTemplateElement psuedoVarRecipient,
+                         Vector paths) 
+                 throws org.w3c.dom.DOMException 
+  {
+	QName uniquePsuedoVarName = null;
+	boolean foundFirst = false;
+	int numPathsFound = 0;
+	int n = paths.size();
+	Expression expr1 = firstOccuranceOwner.getExpression();
+	if(DEBUG)
+		assertIsLocPathIterator(expr1, firstOccuranceOwner);
+	boolean isGlobal = (paths == m_absPaths);
+	LocPathIterator lpi = (LocPathIterator)expr1;
+	for(int j = start; j < n; j++)
+	{
+		ExpressionOwner owner2 = (ExpressionOwner)paths.elementAt(j);
+		if(null != owner2)
+		{
+			Expression expr2 = owner2.getExpression();
+			boolean isEqual = expr2.deepEquals(lpi);
+			if(isEqual)
+			{  		
+				LocPathIterator lpi2  = (LocPathIterator)expr2;				
+				if(!foundFirst)
+				{
+					foundFirst = true;
+					// Insert variable decl into psuedoVarRecipient
+					// We want to insert this into the first legitimate 
+					// position for a variable.
+				    ElemVariable var = createPsuedoVarDecl(psuedoVarRecipient, lpi, isGlobal);
+				    if(null == var)
+				    	return 0;
+				    uniquePsuedoVarName = var.getName();
+	
+					changeToVarRef(uniquePsuedoVarName, firstOccuranceOwner, 
+					               paths, psuedoVarRecipient);
+					               
+					// Replace the first occurance with the variable's XPath, so  
+					// that further reduction may take place if needed.
+					paths.setElementAt(var.getSelect(), firstOccuranceIndex);
+					numPathsFound++;
+				}
+	
+				changeToVarRef(uniquePsuedoVarName, owner2, paths, psuedoVarRecipient);
+	
+				// Null out the occurance, so we don't have to test it again.
+				paths.setElementAt(null, j);
+				
+				// foundFirst = true;
+				numPathsFound++;
+			}
+		}
+	}
+	
+	// Change all globals in xsl:templates, etc, to global vars no matter what.
+	if((0 == numPathsFound) && (paths == m_absPaths))
+	{
+      ElemVariable var = createPsuedoVarDecl(psuedoVarRecipient, lpi, true);
+      if(null == var)
+        return 0;
+	  uniquePsuedoVarName = var.getName();
+      changeToVarRef(uniquePsuedoVarName, firstOccuranceOwner, paths, psuedoVarRecipient);
+      paths.setElementAt(var.getSelect(), firstOccuranceIndex);
+      numPathsFound++;
+	}
+	return numPathsFound;
+  }
+  
+  /**
+   * Count the steps in a given location path.
+   * 
+   * @param lpi The location path iterator that owns the steps.
+   * @return The number of steps in the given location path.
+   */
+  protected int countSteps(LocPathIterator lpi)
+  {
+  	if(lpi instanceof WalkingIterator)
+  	{
+  		WalkingIterator wi = (WalkingIterator)lpi;
+  		AxesWalker aw = wi.getFirstWalker();
+  		int count = 0;
+  		while(null != aw)
+  		{
+  			count++;
+  			aw = aw.getNextWalker();
+  		}
+  		return count;
+  	}
+  	else
+  		return 1;
+  }
+  
+  /**
+   * Change the expression owned by the owner argument to a variable reference 
+   * of the given name.
+   * 
+   * Warning: For global vars, this function relies on the variable declaration 
+   * to which it refers having been added just prior to this function being called,
+   * so that the reference index can be determined from the size of the global variables 
+   * list minus one.
+   * 
+   * @param varName The name of the variable which will be referenced.
+   * @param owner The owner of the expression which will be replaced by a variable ref.
+   * @param paths The paths list that the iterator came from, mainly to determine
+   *              if this is a local or global reduction.
+   * @param psuedoVarRecipient The element within whose scope the variable is 
+   *                           being inserted, possibly a StylesheetRoot.
+   */
+  protected void changeToVarRef(QName varName, ExpressionOwner owner, 
+                                Vector paths, ElemTemplateElement psuedoVarRecipient) 
+  {
+	Variable varRef = (paths == m_absPaths) ? new VariableSafeAbsRef() : new Variable();
+	varRef.setQName(varName);
+	if(paths == m_absPaths)
+	{
+		StylesheetRoot root = (StylesheetRoot)psuedoVarRecipient;
+		Vector globalVars = root.getVariablesAndParamsComposed();
+		// Assume this operation is occuring just after the decl has 
+		// been added.
+		varRef.setIndex(globalVars.size()-1);
+		varRef.setIsGlobal(true);
+	}
+	owner.setExpression(varRef);
+  }
+
+  /**
+   * Create a psuedo variable reference that will represent the 
+   * shared redundent XPath, and add it to the stylesheet.
+   * 
+   * @param psuedoVarRecipient The broadest scope of where the variable 
+   * should be inserted, usually an xsl:template or xsl:for-each.
+   * @param lpi The LocationPathIterator that the variable should represent.
+   * @param isGlobal true if the paths are global.
+   * @return The new psuedo var element.
+   */
+  protected ElemVariable createPsuedoVarDecl(
+      ElemTemplateElement psuedoVarRecipient,
+      LocPathIterator lpi, boolean isGlobal)
+      throws org.w3c.dom.DOMException
+  {
+    QName uniquePsuedoVarName = new QName (PSUEDOVARNAMESPACE, "#"+m_uniquePsuedoVarID);
+    m_uniquePsuedoVarID++;
+  		
+  	if(isGlobal)
+  	{
+  	  return createGlobalPsuedoVarDecl(uniquePsuedoVarName, 
+  	                                  (StylesheetRoot)psuedoVarRecipient, lpi);
+  	}
+  	else						
+      return createLocalPsuedoVarDecl(uniquePsuedoVarName, psuedoVarRecipient, lpi);
+  }
+  
+  /**
+   * Create a psuedo variable reference that will represent the 
+   * shared redundent XPath, for a local reduction.
+   * 
+   * @param uniquePsuedoVarName The name of the new variable.
+   * @param stylesheetRoot The broadest scope of where the variable 
+   *        should be inserted, which must be a StylesheetRoot element in this case.
+   * @param lpi The LocationPathIterator that the variable should represent.
+   * @return null if the decl was not created, otherwise the new Psuedo var  
+   *              element.
+   */
+  protected ElemVariable createGlobalPsuedoVarDecl(QName uniquePsuedoVarName,
+                                           StylesheetRoot stylesheetRoot, 
+                                           LocPathIterator lpi) 
+        throws org.w3c.dom.DOMException 
+  {
+  	ElemVariable psuedoVar = new ElemVariable();
+  	psuedoVar.setIsTopLevel(true);
+	XPath xpath = new XPath(lpi);
+	psuedoVar.setSelect(xpath);
+	psuedoVar.setName(uniquePsuedoVarName);
+	
+	Vector globalVars = stylesheetRoot.getVariablesAndParamsComposed();
+	psuedoVar.setIndex(globalVars.size());
+	globalVars.addElement(psuedoVar);
+	return psuedoVar;
+  }
+
+  
+  
+
+  /**
+   * Create a psuedo variable reference that will represent the 
+   * shared redundent XPath, for a local reduction.
+   * 
+   * @param uniquePsuedoVarName The name of the new variable.
+   * @param psuedoVarRecipient The broadest scope of where the variable 
+   * should be inserted, usually an xsl:template or xsl:for-each.
+   * @param lpi The LocationPathIterator that the variable should represent.
+   * @param addToContext true if the decl should be added to psuedoVarRecipient.
+   * @return null if the decl was not created, otherwise the new Psuedo var  
+   *              element.
+   */
+  protected ElemVariable createLocalPsuedoVarDecl(QName uniquePsuedoVarName,
+                                           ElemTemplateElement psuedoVarRecipient, 
+                                           LocPathIterator lpi) 
+        throws org.w3c.dom.DOMException 
+  {
+		ElemVariable psuedoVar = new ElemVariablePsuedo();
+		
+		XPath xpath = new XPath(lpi);
+		psuedoVar.setSelect(xpath);
+		psuedoVar.setName(uniquePsuedoVarName);
+
+		ElemVariable var = addVarDeclToElem(psuedoVarRecipient, lpi, psuedoVar);
+		
+		lpi.exprSetParent(var);
+		
+		return var;
+  }
+
+  /**
+   * Add the given variable to the psuedoVarRecipient.
+   */
+  protected ElemVariable addVarDeclToElem(
+    ElemTemplateElement psuedoVarRecipient,
+    LocPathIterator lpi,
+    ElemVariable psuedoVar)
+    throws org.w3c.dom.DOMException
+  {
+    // Create psuedo variable element
+    ElemTemplateElement ete = psuedoVarRecipient.getFirstChildElem();
+
+    lpi.callVisitors(null, m_varNameCollector);
+
+    // If the location path contains variables, we have to insert the 
+    // psuedo variable after the reference. (Otherwise, we want to 
+    // insert it as close as possible to the top, so we'll be sure 
+    // it is in scope for any other vars.
+    if (m_varNameCollector.getVarCount() > 0)
+    {
+      ElemTemplateElement baseElem = getElemFromExpression(lpi);
+      ElemVariable varElem = getPrevVariableElem(baseElem);
+      while (null != varElem)
+      {
+        if (m_varNameCollector.doesOccur(varElem.getName()))
+          {
+          psuedoVarRecipient = varElem.getParentElem();
+          ete = varElem.getNextSiblingElem();
+          break;
+        }
+        varElem = getPrevVariableElem(varElem);
+      }
+    }
+
+    if ((null != ete) && (Constants.ELEMNAME_PARAMVARIABLE == ete.getXSLToken()))
+    {
+      // Can't stick something in front of a param, so abandon! (see variable13.xsl)
+      if(isParam(lpi))
+        return null;
+
+      while (null != ete)
+      {
+        ete = ete.getNextSiblingElem();
+        if ((null != ete) && Constants.ELEMNAME_PARAMVARIABLE != ete.getXSLToken())
+            break;
+      }
+    }
+    psuedoVarRecipient.insertBefore(psuedoVar, ete);
+    m_varNameCollector.reset();
+    return psuedoVar;
+  }
+    
+  /**
+   * Tell if the expr param is contained within an xsl:param.
+   */
+  protected boolean isParam(ExpressionNode expr)
+  {
+  	while(null != expr)
+  	{
+  		if(expr instanceof ElemTemplateElement)
+  			break;
+  		expr = expr.exprGetParent();
+  	}
+  	if(null != expr)
+  	{
+  		ElemTemplateElement ete = (ElemTemplateElement)expr;
+  		while(null != ete)
+  		{
+  			int type = ete.getXSLToken();
+  			switch(type)
+  			{
+  				case Constants.ELEMNAME_PARAMVARIABLE:
+  					return true;
+  				case Constants.ELEMNAME_TEMPLATE:
+  				case Constants.ELEMNAME_STYLESHEET:
+  					return false;
+  			}
+  			ete = ete.getParentElem();
+  		}
+  	}
+  	return false;
+  	
+  }
+  
+  /**
+   * Find the previous occurance of a xsl:variable.  Stop 
+   * the search when a xsl:for-each, xsl:template, or xsl:stylesheet is 
+   * encountered.
+   * 
+   * @param elem Should be non-null template element.
+   * @return The first previous occurance of an xsl:variable or xsl:param, 
+   * or null if none is found.
+   */
+  protected ElemVariable getPrevVariableElem(ElemTemplateElement elem)
+  {
+  	// This could be somewhat optimized.  since getPreviousSiblingElem is a  
+  	// fairly expensive operation.
+  	while(null != (elem = getPrevElementWithinContext(elem)))
+  	{
+  		int type = elem.getXSLToken();
+  			
+  		if((Constants.ELEMNAME_VARIABLE == type) ||
+  		   (Constants.ELEMNAME_PARAMVARIABLE == type))
+  		{
+  			return (ElemVariable)elem;
+  		}
+  	}
+  	return null;
+  }
+  
+  /**
+   * Get the previous sibling or parent of the given template, stopping at 
+   * xsl:for-each, xsl:template, or xsl:stylesheet.
+   * 
+   * @param elem Should be non-null template element.
+   * @return previous sibling or parent, or null if previous is xsl:for-each, 
+   * xsl:template, or xsl:stylesheet.
+   */
+  protected ElemTemplateElement getPrevElementWithinContext(ElemTemplateElement elem)
+  {
+  	ElemTemplateElement prev = elem.getPreviousSiblingElem();
+  	if(null == prev)
+  		prev = elem.getParentElem();
+  	if(null != prev)
+  	{
+  	  int type = prev.getXSLToken();
+  	  if((Constants.ELEMNAME_FOREACH == type) || 
+  	     (Constants.ELEMNAME_TEMPLATE == type) ||
+  	     (Constants.ELEMNAME_STYLESHEET == type))
+  	  {
+  	  	prev = null;
+  	  }
+  	}
+  	return prev;
+  }
+  
+  /**
+   * From an XPath expression component, get the ElemTemplateElement 
+   * owner.
+   * 
+   * @param expr Should be static expression with proper parentage.
+   * @return Valid ElemTemplateElement, or throw a runtime exception 
+   * if it is not found.
+   */
+  protected ElemTemplateElement getElemFromExpression(Expression expr)
+  {
+  	ExpressionNode parent = expr.exprGetParent();
+  	while(null != parent)
+  	{
+  		if(parent instanceof ElemTemplateElement)
+  			return (ElemTemplateElement)parent;
+  		parent = parent.exprGetParent();
+  	}
+  	throw new RuntimeException("Programmer's error! expr has no ElemTemplateElement parent!");
+  }
+      
+  /**
+   * Tell if the given LocPathIterator is relative to an absolute path, i.e. 
+   * in not dependent on the context.
+   * 
+   * @return true if the LocPathIterator is not dependent on the context node.
+   */
+  public boolean isAbsolute(LocPathIterator path)
+  {
+  	int analysis = path.getAnalysisBits();
+    boolean isAbs = (WalkerFactory.isSet(analysis, WalkerFactory.BIT_ROOT) || 
+           WalkerFactory.isSet(analysis, WalkerFactory.BIT_ANY_DESCENDANT_FROM_ROOT));
+    if(isAbs)
+    {
+    	isAbs = m_absPathChecker.checkAbsolute(path);
+    }
+    return isAbs;
+  }
+
+
+  /**
+   * Visit a LocationPath.
+   * @param owner The owner of the expression, to which the expression can 
+   *              be reset if rewriting takes place.
+   * @param path The LocationPath object.
+   * @return true if the sub expressions should be traversed.
+   */
+  public boolean visitLocationPath(ExpressionOwner owner, LocPathIterator path)
+  {
+  	// Don't optimize "." or single step variable paths.
+  	// Both of these cases could use some further optimization by themselves.
+  	if(path instanceof SelfIteratorNoPredicate)
+  	{
+  		return true;
+  	}
+  	else if(path instanceof WalkingIterator)
+  	{
+  		WalkingIterator wi = (WalkingIterator)path;
+  		AxesWalker aw = wi.getFirstWalker();
+  		if((aw instanceof FilterExprWalker) && (null == aw.getNextWalker()))
+  		{
+  			FilterExprWalker few = (FilterExprWalker)aw;
+  			Expression exp = few.getInnerExpression();
+  			if(exp instanceof Variable)
+  				return true;
+  		}
+  	}
+
+    if (isAbsolute(path) && (null != m_absPaths))
+    {
+      if(DEBUG)
+        validateNewAddition(m_absPaths, owner, path);
+      m_absPaths.addElement(owner);
+    }
+    else if (m_isSameContext && (null != m_paths))
+    {
+      if(DEBUG)
+        validateNewAddition(m_paths, owner, path);
+      m_paths.addElement(owner);
+    }
+
+    return true;
+  }
+
+  /**
+   * Visit a predicate within a location path.  Note that there isn't a 
+   * proper unique component for predicates, and that the expression will 
+   * be called also for whatever type Expression is.
+   * 
+   * @param owner The owner of the expression, to which the expression can 
+   *              be reset if rewriting takes place.
+   * @param pred The predicate object.
+   * @return true if the sub expressions should be traversed.
+   */
+  public boolean visitPredicate(ExpressionOwner owner, Expression pred)
+  {
+    boolean savedIsSame = m_isSameContext;
+    m_isSameContext = false;
+
+    // Any further down, just collect the absolute paths.
+    pred.callVisitors(owner, this);
+
+    m_isSameContext = savedIsSame;
+
+    // We've already gone down the subtree, so don't go have the caller 
+    // go any further.
+    return false;
+  }
+  
+  /**
+   * Visit an XSLT top-level instruction.
+   * 
+   * @param elem The xsl instruction element object.
+   * @return true if the sub expressions should be traversed.
+   */
+   boolean visitTopLevelInstruction(ElemTemplateElement elem)
+   {
+     int type = elem.getXSLToken();
+     switch(type)
+     {
+       case Constants.ELEMNAME_TEMPLATE :
+         return visitInstruction(elem);
+       default:
+         return true;
+     }
+   }
+
+
+  /**
+   * Visit an XSLT instruction.  Any element that isn't called by one 
+   * of the other visit methods, will be called by this method.
+   * 
+   * @param elem The xsl instruction element object.
+   * @return true if the sub expressions should be traversed.
+   */
+  boolean visitInstruction(ElemTemplateElement elem)
+  {
+    int type = elem.getXSLToken();
+    switch (type)
+    {
+      case Constants.ELEMNAME_CALLTEMPLATE :
+      case Constants.ELEMNAME_TEMPLATE :
+      case Constants.ELEMNAME_FOREACH :
+        {
+          
+          // Just get the select value.
+          if(type == Constants.ELEMNAME_FOREACH)
+          {
+            ElemForEach efe = (ElemForEach) elem;
+   		    
+  		    Expression select = efe.getSelect();
+  		    select.callVisitors(efe, this);
+          }
+         
+  		  Vector savedPaths = m_paths;
+  		  m_paths = new Vector();
+  		    
+  		  // Visit children.  Call the superclass callChildVisitors, because 
+  		  // we don't want to visit the xsl:for-each select attribute, or, for 
+  		  // that matter, the xsl:template's match attribute.
+  		  elem.callChildVisitors(this, false);  		
+  		  eleminateRedundentLocals(elem);
+  		    
+  		  m_paths = savedPaths;
+ 
+          // select.callVisitors(efe, this);
+          return false;
+        }
+      case Constants.ELEMNAME_NUMBER :
+      case Constants.ELEMNAME_SORT :
+        // Just collect absolute paths until and unless we can fully
+        // analyze these cases.
+        boolean savedIsSame = m_isSameContext;
+        m_isSameContext = false;
+        elem.callChildVisitors(this);
+        m_isSameContext = savedIsSame;
+        return false;
+        
+      default :
+        return true;
+    }
+  }
+  
+  // ==== DIAGNOSTIC AND DEBUG FUNCTIONS ====
+  
+  /**
+   * Print out to std err the number of paths reduced.
+   */
+  protected void diagnoseNumPaths(Vector paths, int numPathsEliminated,  
+                                  int numUniquePathsEliminated) 
+  {
+		if (numPathsEliminated > 0)
+		{ 
+		  if(paths == m_paths)
+		  {
+		    System.err.println("Eliminated " + numPathsEliminated + " total paths!");
+		    System.err.println(
+		      "Consolodated " + numUniquePathsEliminated + " redundent paths!");
+		  }
+		  else
+		  {
+		    System.err.println("Eliminated " + numPathsEliminated + " total global paths!");
+		    System.err.println(
+		      "Consolodated " + numUniquePathsEliminated + " redundent global paths!");
+		  }
+		}  
+  }
+
+
+  /**
+   * Assert that the expression is a LocPathIterator, and, if 
+   * not, try to give some diagnostic info.
+   */
+  private final void assertIsLocPathIterator(Expression expr1, ExpressionOwner eo) 
+    throws RuntimeException 
+  {
+		if(!(expr1 instanceof LocPathIterator))
+		{
+			String errMsg;
+			if(expr1 instanceof Variable)
+			{
+				errMsg = "Programmer's assertion: expr1 not an iterator: "+
+				          ((Variable)expr1).getQName();
+			}
+			else
+			{
+				errMsg = "Programmer's assertion: expr1 not an iterator: "+
+				          expr1.getClass().getName();
+			}
+			throw new RuntimeException(errMsg + ", "+
+				          eo.getClass().getName()+" "+
+				          expr1.exprGetParent());
+		}
+  }
+
+
+  /**
+   * Validate some assumptions about the new LocPathIterator and it's 
+   * owner and the state of the list.
+   */
+  private static void validateNewAddition(Vector paths, ExpressionOwner owner, 
+                                          LocPathIterator path) 
+		throws RuntimeException 
+  {
+  	assert(owner.getExpression() == path, "owner.getExpression() != path!!!");
+	int n = paths.size();
+	// There should never be any duplicates in the list!
+	for(int i = 0; i < n; i++)
+	{
+		ExpressionOwner ew = (ExpressionOwner)paths.elementAt(i);
+		assert(ew != owner, "duplicate owner on the list!!!");
+		assert(ew.getExpression() != path, "duplicate expression on the list!!!");
+	}
+  }
+  
+  /**
+   * Simple assertion.
+   */
+  protected static void assert(boolean b, String msg)
+  {
+  	if(!b)
+  	{
+  		throw new RuntimeException("Programmer's assertion in RundundentExprEliminator: "+msg);
+  	}
+  }
+  
+  /**
+   * Since we want to sort multistep expressions by length, use 
+   * a linked list with elements of type MultistepExprHolder.
+   */
+  class MultistepExprHolder implements Cloneable
+  {
+	ExpressionOwner m_exprOwner; // Will change to null once we have processed this item.
+	final int m_stepCount;
+	MultistepExprHolder m_next;
+	
+	/**
+	 * Clone this object.
+	 */
+	public Object clone()
+		throws CloneNotSupportedException
+	{
+		return super.clone();
+	}
+	
+	/**
+	 * Create a MultistepExprHolder.
+	 * 
+	 * @param exprOwner the owner of the expression we are holding.
+	 *                  It must hold a LocationPathIterator.
+	 * @param stepCount The number of steps in the location path.
+	 */
+  	MultistepExprHolder(ExpressionOwner exprOwner, int stepCount, MultistepExprHolder next)
+  	{
+  		m_exprOwner = exprOwner;
+  		assert(null != m_exprOwner, "exprOwner can not be null!");
+  		m_stepCount = stepCount;
+  		m_next = next;
+  	}
+	
+	/**
+	 * Add a new MultistepExprHolder in sorted order in the list.
+	 * 
+	 * @param exprOwner the owner of the expression we are holding.
+	 *                  It must hold a LocationPathIterator.
+	 * @param stepCount The number of steps in the location path.
+	 * @return The new head of the linked list.
+	 */
+	MultistepExprHolder addInSortedOrder(ExpressionOwner exprOwner, int stepCount)
+	{
+		MultistepExprHolder first = this;
+		MultistepExprHolder next = this;
+		MultistepExprHolder prev = null;
+		while(null != next)
+		{
+			if(stepCount >= next.m_stepCount)
+			{
+				MultistepExprHolder newholder = new MultistepExprHolder(exprOwner, stepCount, next);
+				if(null == prev)
+					first = newholder;
+				else
+					prev.m_next = newholder;
+					
+				return first;
+			}
+			prev = next;
+			next = next.m_next;
+		}
+		
+		prev.m_next = new MultistepExprHolder(exprOwner, stepCount, null);
+		return first;
+	}
+	
+	/**
+	 * Remove the given element from the list.  'this' should 
+	 * be the head of the list.  If the item to be removed is not 
+	 * found, an assertion will be made.
+	 * 
+	 * @param itemToRemove The item to remove from the list.
+	 * @return The head of the list, which may have changed if itemToRemove 
+	 * is the same as this element.  Null if the item to remove is the 
+	 * only item in the list.
+	 */
+	MultistepExprHolder unlink(MultistepExprHolder itemToRemove)
+	{
+		MultistepExprHolder first = this;
+		MultistepExprHolder next = this;
+		MultistepExprHolder prev = null;
+		while(null != next)
+		{
+			if(next == itemToRemove)
+			{
+				if(null == prev)
+					first = next.m_next;
+				else
+					prev.m_next = next.m_next;
+				
+				next.m_next = null;
+					
+				return first;
+			}
+			prev = next;
+			next = next.m_next;
+		}
+		
+		assert(false, "unlink failed!!!");
+		return null;
+	}
+		
+	/**
+	 * Get the number of linked list items.
+	 */
+	int getLength()
+	{
+		int count = 0;
+		MultistepExprHolder next = this;
+		while(null != next)
+		{
+			count++;
+			next = next.m_next;
+		}
+		return count;
+	}
+	
+    /**
+     * Print diagnostics out for the multistep list.
+     */
+    protected void diagnose()
+    {
+      System.err.print("Found multistep iterators: " + this.getLength() + "  ");
+      MultistepExprHolder next = this;
+      while (null != next)
+      {
+        System.err.print("" + next.m_stepCount);
+        next = next.m_next;
+        if (null != next)
+              System.err.print(", ");
+      }
+      System.err.println();
+    }
+	
+  }
+
+}
\ No newline at end of file
diff --git a/src/org/apache/xalan/templates/Stylesheet.java b/src/org/apache/xalan/templates/Stylesheet.java
index 24b48ec..c5f5ab2 100644
--- a/src/org/apache/xalan/templates/Stylesheet.java
+++ b/src/org/apache/xalan/templates/Stylesheet.java
@@ -1411,4 +1411,137 @@
     v.setStylesheet(this);
   }
   
+    /**
+     * Call the children visitors.
+     * @param visitor The visitor whose appropriate method will be called.
+     */
+    protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+    {
+      int s = getImportCount();
+      for (int j = 0; j < s; j++)
+      {
+      	getImport(j).callVisitors(visitor);
+      }
+   
+      s = getIncludeCount();
+      for (int j = 0; j < s; j++)
+      {
+      	getInclude(j).callVisitors(visitor);
+      }
+
+      s = getOutputCount();
+      for (int j = 0; j < s; j++)
+      {
+        visitor.visitTopLevelInstruction(getOutput(j));
+      }
+
+      // Next, add in the attribute-set elements
+
+      s = getAttributeSetCount();
+      for (int j = 0; j < s; j++)
+      {
+      	ElemAttributeSet attrSet = getAttributeSet(j);
+        if (visitor.visitTopLevelInstruction(attrSet))
+        {
+          attrSet.callChildVisitors(visitor);
+        }
+      }
+      // Now the decimal-formats
+
+      s = getDecimalFormatCount();
+      for (int j = 0; j < s; j++)
+      {
+        visitor.visitTopLevelInstruction(getDecimalFormat(j));
+      }
+
+      // Now the keys
+
+      s = getKeyCount();
+      for (int j = 0; j < s; j++)
+      {
+        visitor.visitTopLevelInstruction(getKey(j));
+      }
+
+      // And the namespace aliases
+
+      s = getNamespaceAliasCount();
+      for (int j = 0; j < s; j++)
+      {
+        visitor.visitTopLevelInstruction(getNamespaceAlias(j));
+      }
+
+      // Next comes the templates
+
+      s = getTemplateCount();
+      for (int j = 0; j < s; j++)
+      {
+        try
+        {
+          ElemTemplate template = getTemplate(j);
+          if (visitor.visitTopLevelInstruction(template))
+          {
+            template.callChildVisitors(visitor);
+          }
+        }
+        catch (TransformerException te)
+        {
+          throw new org.apache.xml.utils.WrappedRuntimeException(te);
+        }
+      }
+
+      // Then, the variables
+
+      s = getVariableOrParamCount();
+      for (int j = 0; j < s; j++)
+      {
+      	ElemVariable var = getVariableOrParam(j);
+        if (visitor.visitTopLevelVariableOrParamDecl(var))
+        {
+          var.callChildVisitors(visitor);
+        }
+      }
+
+      // And lastly the whitespace preserving and stripping elements
+
+      s = getStripSpaceCount();
+      for (int j = 0; j < s; j++)
+      {
+        visitor.visitTopLevelInstruction(getStripSpace(j));
+      }
+
+      s = getPreserveSpaceCount();
+      for (int j = 0; j < s; j++)
+      {
+        visitor.visitTopLevelInstruction(getPreserveSpace(j));
+      }
+      
+      if(null != m_NonXslTopLevel)
+      {
+      	java.util.Enumeration enum = m_NonXslTopLevel.elements();
+      	while(enum.hasMoreElements())
+      	{
+      	  ElemTemplateElement elem = (ElemTemplateElement)enum.nextElement();
+          if (visitor.visitTopLevelInstruction(elem))
+          {
+            elem.callChildVisitors(visitor);
+          }
+      		
+      	}
+      }
+    }
+        
+          
+  /**
+   * Accept a visitor and call the appropriate method 
+   * for this class.
+   * 
+   * @param visitor The visitor whose appropriate method will be called.
+   * @return true if the children of the object should be visited.
+   */
+  protected boolean accept(XSLTVisitor visitor)
+  {
+  	return visitor.visitStylesheet(this);
+  }
+
+  
 }
diff --git a/src/org/apache/xalan/templates/StylesheetRoot.java b/src/org/apache/xalan/templates/StylesheetRoot.java
index 415b8c1..7319106 100644
--- a/src/org/apache/xalan/templates/StylesheetRoot.java
+++ b/src/org/apache/xalan/templates/StylesheetRoot.java
@@ -212,7 +212,6 @@
    */
   public void recompose() throws TransformerException
   {
-
     // First, we build the global import tree.
 
     if (null == m_globalImportList)
@@ -269,6 +268,16 @@
     // Note that we're going backwards, encountering the highest precedence items first.
     for (int i = recomposableElements.size() - 1; i >= 0; i--)
       ((ElemTemplateElement) recomposableElements.elementAt(i)).recompose(this);
+      
+    // This has to be done before the initialization of the compose state, because 
+    // eleminateRedundentGlobals will add variables to the m_variables vector, which 
+    // it then copied in the ComposeState constructor.
+    if(true && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize)
+    {
+    	RedundentExprEliminator ree = new RedundentExprEliminator();
+    	callVisitors(ree);
+    	ree.eleminateRedundentGlobals(this);
+    }
     
     initComposeState();
 
@@ -278,7 +287,7 @@
     // Need to clear check for properties at the same import level.
     m_outputProperties.compose(this);
     m_outputProperties.endCompose(this);
-    
+        
     // Now call the compose() method on every element to give it a chance to adjust
     // based on composed values.
     
@@ -1155,7 +1164,7 @@
         }
         
       }
-      
+            
       private ExpandedNameTable m_ent = new ExpandedNameTable();
       
       /**
diff --git a/src/org/apache/xalan/templates/VarNameCollector.java b/src/org/apache/xalan/templates/VarNameCollector.java
new file mode 100644
index 0000000..fc86ccb
--- /dev/null
+++ b/src/org/apache/xalan/templates/VarNameCollector.java
@@ -0,0 +1,60 @@
+package org.apache.xalan.templates;
+
+import java.util.Vector;
+
+import org.apache.xml.utils.QName;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.operations.Variable;
+
+/**
+ * This class visits variable refs in an XPath and collects their QNames.
+ */
+public class VarNameCollector extends XPathVisitor
+{
+	Vector m_refs = new Vector();
+	
+	/**
+	 * Reset the list for a fresh visitation and collection.
+	 */
+	public void reset()
+	{
+		m_refs.clear();
+	}
+	
+	/**
+	 * Get the number of variable references that were collected.
+	 * @return the size of the list.
+	 */
+	public int getVarCount()
+	{
+		return m_refs.size();
+	}
+	
+	/**
+	 * Tell if the given qualified name occurs in 
+	 * the list of qualified names collected.
+	 * 
+	 * @param refName Must be a valid qualified name.
+	 * @return true if the list contains the qualified name.
+	 */
+	boolean doesOccur(QName refName)
+	{
+		return m_refs.contains(refName);
+	}
+
+	/**
+	 * Visit a variable reference.
+	 * @param owner The owner of the expression, to which the expression can 
+	 *              be reset if rewriting takes place.
+	 * @param var The variable reference object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	public boolean visitVariableRef(ExpressionOwner owner, Variable var)
+	{
+		m_refs.addElement(var.getQName());
+		return true;
+	}
+
+}
+
diff --git a/src/org/apache/xalan/templates/WhiteSpaceInfo.java b/src/org/apache/xalan/templates/WhiteSpaceInfo.java
index 732f467..9e4c2ee 100644
--- a/src/org/apache/xalan/templates/WhiteSpaceInfo.java
+++ b/src/org/apache/xalan/templates/WhiteSpaceInfo.java
@@ -81,6 +81,21 @@
   {
     return m_shouldStripSpace;
   }
+  
+  /**
+   * Constructor WhiteSpaceInfo
+   *
+   *
+   * @param matchPattern Match pattern
+   * @param shouldStripSpace Flag indicating whether or not
+   * to strip whitespaces
+   * @param thisSheet The current stylesheet
+   */
+  public WhiteSpaceInfo(Stylesheet thisSheet)
+  {
+  	setStylesheet(thisSheet);
+  }
+
 
   /**
    * Constructor WhiteSpaceInfo
diff --git a/src/org/apache/xalan/templates/XSLTVisitable.java b/src/org/apache/xalan/templates/XSLTVisitable.java
new file mode 100644
index 0000000..6d066e1
--- /dev/null
+++ b/src/org/apache/xalan/templates/XSLTVisitable.java
@@ -0,0 +1,20 @@
+package org.apache.xalan.templates;
+
+/**
+ * A class that implements this interface will call a XSLTVisitor 
+ * for itself and members within it's heararchy.  If the XSLTVistor's 
+ * method returns false, the sub-member heararchy will not be 
+ * traversed.
+ */
+public interface XSLTVisitable
+{
+	/**
+	 * This will traverse the heararchy, calling the visitor for 
+	 * each member.  If the called visitor method returns 
+	 * false, the subtree should not be called.
+	 * 
+	 * @param visitor The visitor whose appropriate method will be called.
+	 */
+	public void callVisitors(XSLTVisitor visitor);
+}
+
diff --git a/src/org/apache/xalan/templates/XSLTVisitor.java b/src/org/apache/xalan/templates/XSLTVisitor.java
new file mode 100644
index 0000000..d28b534
--- /dev/null
+++ b/src/org/apache/xalan/templates/XSLTVisitor.java
@@ -0,0 +1,165 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xalan.templates;
+
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.ExpressionOwner;
+
+/**
+ * A derivation from this class can be passed to a class that implements 
+ * the XSLTVisitable interface, to have the appropriate method called 
+ * for each component of an XSLT stylesheet.  Aside from possible other uses, the 
+ * main intention is to provide a reasonable means to perform expression 
+ * rewriting.
+ */
+public class XSLTVisitor extends XPathVisitor
+{
+	/**
+	 * Visit an XSLT instruction.  Any element that isn't called by one 
+	 * of the other visit methods, will be called by this method.
+	 * 
+	 * @param elem The xsl instruction element object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitInstruction(ElemTemplateElement elem)
+	{
+		return true;
+	}
+	
+	/**
+	 * Visit an XSLT stylesheet instruction.
+	 * 
+	 * @param elem The xsl instruction element object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitStylesheet(ElemTemplateElement elem)
+	{
+		return true;
+	}
+
+	
+	/**
+	 * Visit an XSLT top-level instruction.
+	 * 
+	 * @param elem The xsl instruction element object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitTopLevelInstruction(ElemTemplateElement elem)
+	{
+		return true;
+	}
+	
+	/**
+	 * Visit an XSLT top-level instruction.
+	 * 
+	 * @param elem The xsl instruction element object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitTopLevelVariableOrParamDecl(ElemTemplateElement elem)
+	{
+		return true;
+	}
+
+	
+	/**
+	 * Visit an XSLT variable or parameter declaration.
+	 * 
+	 * @param elem The xsl instruction element object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitVariableOrParamDecl(ElemVariable elem)
+	{
+		return true;
+	}
+	
+	/**
+	 * Visit a LiteralResultElement.
+	 * 
+	 * @param elem The literal result object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitLiteralResultElement(ElemLiteralResult elem)
+	{
+		return true;
+	}
+	
+	/**
+	 * Visit an Attribute Value Template (at the top level).
+	 * 
+	 * @param owner The owner of the expression, to which the expression can 
+	 *              be reset if rewriting takes place.
+	 * @param elem The attribute value template object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitAVT(AVT elem)
+	{
+		return true;
+	}
+
+
+	/**
+	 * Visit an extension element.
+	 * @param elem The extension object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	boolean visitExtensionElement(ElemExtensionCall elem)
+	{
+		return true;
+	}
+
+}
+
diff --git a/src/org/apache/xalan/templates/XUnresolvedVariableSimple.java b/src/org/apache/xalan/templates/XUnresolvedVariableSimple.java
new file mode 100644
index 0000000..944adb8
--- /dev/null
+++ b/src/org/apache/xalan/templates/XUnresolvedVariableSimple.java
@@ -0,0 +1,64 @@
+package org.apache.xalan.templates;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+
+
+/**
+ * This is the same as XUnresolvedVariable, but it assumes that the 
+ * context is already set up.  For use with psuedo variables.
+ * Also, it holds an Expression object, instead of an ElemVariable.
+ * It must only hold static context, since a single copy will be 
+ * held in the template.
+ */
+public class XUnresolvedVariableSimple extends XObject
+{
+  public XUnresolvedVariableSimple(ElemVariable obj)
+  {
+    super(obj);
+  }
+    
+	
+  /**
+   * For support of literal objects in xpaths.
+   *
+   * @param xctxt The XPath execution context.
+   *
+   * @return This object.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+  {
+  	Expression expr = ((ElemVariable)m_obj).getSelect().getExpression();
+    XObject xobj = expr.execute(xctxt);
+    xobj.allowDetachToRelease(false);
+    return xobj;
+  }
+  
+  /**
+   * Tell what kind of class this is.
+   *
+   * @return CLASS_UNRESOLVEDVARIABLE
+   */
+  public int getType()
+  {
+    return CLASS_UNRESOLVEDVARIABLE;
+  }
+  
+  /**
+   * Given a request type, return the equivalent string.
+   * For diagnostic purposes.
+   *
+   * @return An informational string.
+   */
+  public String getTypeString()
+  {
+    return "XUnresolvedVariableSimple (" + object().getClass().getName() + ")";
+  }
+
+
+}
+
diff --git a/src/org/apache/xalan/trace/TraceManager.java b/src/org/apache/xalan/trace/TraceManager.java
index f2e9cf3..92b7141 100644
--- a/src/org/apache/xalan/trace/TraceManager.java
+++ b/src/org/apache/xalan/trace/TraceManager.java
@@ -219,7 +219,7 @@
     {
       Node source = m_transformer.getXPathContext().getDTM(
         sourceNode).getNode(sourceNode);
-
+        
       fireSelectedEvent(new SelectionEvent(m_transformer, source, styleNode,
                                            attributeName, xpath, selection));
     }
@@ -246,7 +246,7 @@
     {
       Node source = m_transformer.getXPathContext().getDTM(
         sourceNode).getNode(sourceNode);
-
+        
       fireSelectedEndEvent(new EndSelectionEvent(m_transformer, source, styleNode,
                                            attributeName, xpath, selection));
     }
diff --git a/src/org/apache/xalan/transformer/KeyIterator.java b/src/org/apache/xalan/transformer/KeyIterator.java
index 1f4deab..a073bff 100644
--- a/src/org/apache/xalan/transformer/KeyIterator.java
+++ b/src/org/apache/xalan/transformer/KeyIterator.java
@@ -58,42 +58,29 @@
 
 import java.util.Vector;
 
-import org.apache.xpath.axes.WalkingIterator;
-import org.apache.xml.utils.PrefixResolver;
-import org.apache.xml.utils.XMLString;
-import org.apache.xml.utils.QName;
-import org.apache.xalan.templates.KeyDeclaration;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
-import org.apache.xpath.XPath;
-
-import org.apache.xml.dtm.DTM;
-
 import javax.xml.transform.TransformerException;
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xalan.res.XSLTErrorResources;
+import org.apache.xalan.templates.KeyDeclaration;
+import org.apache.xml.dtm.Axis;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.OneStepIteratorForward;
 
 /**
  * <meta name="usage" content="internal"/>
  * This class implements an optimized iterator for 
- * "key()" patterns. This iterator incrementally walks the 
- * source tree and finds all the nodes that match
- * a given key name and match pattern.
+ * "key()" patterns, matching each node to the 
+ * match attribute in one or more xsl:key declarations.
  */
-public class KeyIterator extends WalkingIterator
+public class KeyIterator extends OneStepIteratorForward
 {
-  
-  /** The key table this iterator is associated to.
-   *  @serial          */
-  private KeyTable m_keyTable;
 
   /** Key name.
    *  @serial           */
   private QName m_name;
-  
-  /** 
-   * Flag indicating whether the whole source tree has been walked.     
-   * True if we still need to finish walking the tree.
-   * */
-  transient private boolean m_lookForMoreNodes = true;
 
   /**
    * Get the key name from a key declaration this iterator will process
@@ -122,109 +109,84 @@
   }
 
   /**
-   * Constructor KeyIterator
-   *
-   *
-   * @param doc The document node
-   * @param nscontext The prefix resolver for the execution context.
-   * @param name The key name
-   * @param keyDeclarations The key declarations from the stylesheet 
-   * @param xctxt The XPath runtime state
-   */
-  public KeyIterator(int doc, PrefixResolver nscontext, QName name,
-                     Vector keyDeclarations, XPathContext xctxt)
+    * Create a KeyIterator object.
+    *
+    * @param compiler A reference to the Compiler that contains the op map.
+    * @param opPos The position within the op map, which contains the
+    * location path expression for this itterator.
+    *
+    * @throws javax.xml.transform.TransformerException
+    */
+  KeyIterator(QName name, Vector keyDeclarations)
   {
-
-    super(nscontext);
-
-    int current = xctxt.getCurrentNode();
-    setRoot(current, xctxt);
-
-    m_name = name;
+    super(Axis.ALL);
     m_keyDeclarations = keyDeclarations;
-    m_firstWalker = new KeyWalker(this);
-
-    this.setLastUsedWalker(m_firstWalker);
+    // m_prefixResolver = nscontext;
+    m_name = name;
   }
 
   /**
-   * Returns the next node in the set and advances the position of the
-   * iterator in the set. After a NodeIterator is created, the first call
-   * to nextNode() returns the first node in the set.
+   *  Test whether a specified node is visible in the logical view of a
+   * TreeWalker or NodeIterator. This function will be called by the
+   * implementation of TreeWalker and NodeIterator; it is not intended to
+   * be called directly from user code.
    * 
-   * @return  The next <code>Node</code> in the set being iterated over, or
-   *   <code>null</code> if there are no more members in that set.
+   * @param testnode  The node to check to see if it passes the filter or not.
+   *
+   * @return  a constant to determine whether the node is accepted,
+   *   rejected, or skipped, as defined  above .
    */
-  public int nextNode()
+  public short acceptNode(int testNode)
   {
+    boolean foundKey = false;
+    KeyIterator ki = (KeyIterator) m_lpi;
+    org.apache.xpath.XPathContext xctxt = ki.getXPathContext();
+    Vector keys = ki.getKeyDeclarations();
 
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    int n = super.nextNode();
+    QName name = ki.getName();
+    try
+    {
+      // System.out.println("lookupKey: "+lookupKey);
+      int nDeclarations = keys.size();
 
-    // System.out.println("--> "+((null == n) ? "null" : n.getNodeName()));
-    return n;
+      // Walk through each of the declarations made with xsl:key
+      for (int i = 0; i < nDeclarations; i++)
+      {
+        KeyDeclaration kd = (KeyDeclaration) keys.elementAt(i);
+
+        // Only continue if the name on this key declaration
+        // matches the name on the iterator for this walker. 
+        if (!kd.getName().equals(name))
+          continue;
+
+        foundKey = true;
+        // xctxt.setNamespaceContext(ki.getPrefixResolver());
+
+        // See if our node matches the given key declaration according to 
+        // the match attribute on xsl:key.
+        XPath matchExpr = kd.getMatch();
+        double score = matchExpr.getMatchScore(xctxt, testNode);
+
+        if (score == kd.getMatch().MATCH_SCORE_NONE)
+          continue;
+
+        return DTMIterator.FILTER_ACCEPT;
+
+      } // end for(int i = 0; i < nDeclarations; i++)
+    }
+    catch (TransformerException se)
+    {
+
+      // TODO: What to do?
+    }
+
+    if (!foundKey)
+      throw new RuntimeException(
+        XSLMessages.createMessage(
+          XSLTErrorResources.ER_NO_XSLKEY_DECLARATION,
+          new Object[] { name.getLocalName()}));
+          
+    return DTMIterator.FILTER_REJECT;
   }
 
-  /**
-   * Set the value of the key that this iterator will look for 
-   *
-   *
-   * @param lookupKey value of the key to look for
-   */
-  public void setLookupKey(XMLString lookupKey)
-  {
-
-    // System.out.println("setLookupKey - lookupKey: "+lookupKey);
-    ((KeyWalker) m_firstWalker).m_lookupKey = lookupKey;
-
-    int context = getContext();
-    DTM dtm = this.getDTM(context);
-    m_firstWalker.setRoot(dtm.getDocument());
-    this.setLastUsedWalker(m_firstWalker);
-    this.setNextPosition(0);
-  }
-  
-  /**
-   * Set the KeyTable associated with this iterator  
-   *
-   *
-   * @param keyTable, the KeyTable associated with this iterator
-   */
-  void setKeyTable(KeyTable keyTable)
-  {
-    m_keyTable = keyTable;
-  }  
-  
-  /**
-   * Add this value(ref) to the refsTable in KeyTable  
-   *
-   *
-   * @param ref Key value(ref)(from key use field)
-   * @param node Node matching that ref 
-   */
-  void addRefNode(XMLString ref, int node)
-  {
-    m_keyTable.addRefNode(ref, node);
-  }
-  
-  /**
-   * Indicate whether we have walked the whole tree  
-   *
-   * @param b False if we have walked the whole tree
-   */
-  void setLookForMoreNodes(boolean b)
-  {
-    m_lookForMoreNodes = b;
-  }
-  
-  /**
-   * Get flag indicating whether we have walked the whole tree  
-   *
-   */
-  boolean getLookForMoreNodes()
-  {
-    return m_lookForMoreNodes;
-  }
-  
 }
diff --git a/src/org/apache/xalan/transformer/KeyManager.java b/src/org/apache/xalan/transformer/KeyManager.java
index b7c7e5e..fdc83a7 100644
--- a/src/org/apache/xalan/transformer/KeyManager.java
+++ b/src/org/apache/xalan/transformer/KeyManager.java
@@ -68,6 +68,7 @@
 import org.apache.xml.utils.XMLString;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.objects.XNodeSet;
 
 /**
  * This class manages the key tables.
@@ -94,12 +95,12 @@
    *
    * @throws javax.xml.transform.TransformerException
    */
-  public LocPathIterator getNodeSetDTMByKey(
+  public XNodeSet getNodeSetDTMByKey(
           XPathContext xctxt, int doc, QName name, XMLString ref, PrefixResolver nscontext)
             throws javax.xml.transform.TransformerException
   {
 
-    LocPathIterator nl = null;
+    XNodeSet nl = null;
     ElemTemplateElement template = (ElemTemplateElement) nscontext;  // yuck -sb
 
     if ((null != template)
diff --git a/src/org/apache/xalan/transformer/KeyRefIterator.java b/src/org/apache/xalan/transformer/KeyRefIterator.java
index a54f2d7..2fbab46 100644
--- a/src/org/apache/xalan/transformer/KeyRefIterator.java
+++ b/src/org/apache/xalan/transformer/KeyRefIterator.java
@@ -56,55 +56,25 @@
  */
 package org.apache.xalan.transformer;
 
-import java.util.Vector;
-
-import org.apache.xpath.axes.LocPathIterator;
-import org.apache.xml.utils.QName;
-import org.apache.xml.utils.XMLString;
-import org.apache.xalan.templates.KeyDeclaration;
-import org.apache.xpath.NodeSetDTM;
-
-//import org.w3c.dom.Node;
-//import org.w3c.dom.DOMException;
-//import org.w3c.dom.traversal.NodeIterator;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.NodeVector;
+import org.apache.xml.utils.XMLString;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+import java.util.Vector;
+import org.apache.xml.utils.QName;
+import org.apache.xalan.templates.KeyDeclaration;
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xalan.res.XSLTErrorResources;
 
 /**
  * <meta name="usage" content="internal"/>
- * This class implements an optimized iterator for 
- * "key()" patterns. It uses a KeyIterator to walk the 
- * source tree and incrementally build a list of nodes that match
- * a given key name, match pattern and value.  
+ * This class filters nodes from a key iterator, according to 
+ * whether or not the use value matches the ref value.  
  */
-public class KeyRefIterator extends LocPathIterator
+public class KeyRefIterator extends org.apache.xpath.axes.ChildTestIterator
 {
-
-  /** Key name.
-   *  @serial         */
-  private final QName m_name;    
-  
-  /** Use field of key function.
-   *  @serial         */
-  private final XMLString m_lookupKey;  
-  
-  /** Main Key iterator for this iterator.
-   *  @serial    */
-  private final KeyIterator m_ki;    
-  
-  /**
-   * Get key name
-   *
-   *
-   * @return Key name
-   */
-  public QName getName()
-  {
-    return m_name;
-  }
-  
-  
-
   /**
    * Constructor KeyRefIterator
    *
@@ -112,142 +82,124 @@
    * @param ref Key value to match
    * @param ki The main key iterator used to walk the source tree 
    */
-  public KeyRefIterator(XMLString ref, KeyIterator ki)
+  public KeyRefIterator(QName name, XMLString ref, Vector keyDecls, DTMIterator ki)
   {
-
-    super(ki.getPrefixResolver());   
-    m_ki = ki;
-    m_name = ki.getName();
-    m_lookupKey = ref;
-    this.m_execContext = ki.getXPathContext();
-    setShouldCacheNodes(true);
+    super(null);
+    m_name = name;
+    m_ref = ref;
+    m_keyDeclarations = keyDecls;
+    m_keysNodes = ki;
+    setWhatToShow(org.apache.xml.dtm.DTMFilter.SHOW_ALL);
+  }
+  
+  DTMIterator m_keysNodes;
+  
+  /**
+   * Get the next node via getNextXXX.  Bottlenecked for derived class override.
+   * @return The next node on the axis, or DTM.NULL.
+   */
+  protected int getNextNode()
+  {                  
+  	int next;   
+    while(DTM.NULL != (next = m_keysNodes.nextNode()))
+    {
+    	if(DTMIterator.FILTER_ACCEPT == filterNode(next))
+    		break;
+    }
+    m_lastFetched = next;
+    
+    return next;
   }
 
+
   /**
-   *  Returns the next node in the set and advances the position of the
-   * iterator in the set. After a NodeIterator is created, the first call
-   * to nextNode() returns the first node in the set.
+   *  Test whether a specified node is visible in the logical view of a
+   * TreeWalker or NodeIterator. This function will be called by the
+   * implementation of TreeWalker and NodeIterator; it is not intended to
+   * be called directly from user code.
    * 
-   * @return  The next <code>Node</code> in the set being iterated over, or
-   *   <code>null</code> if there are no more members in that set.
+   * @param testnode  The node to check to see if it passes the filter or not.
+   *
+   * @return  a constant to determine whether the node is accepted,
+   *   rejected, or skipped, as defined  above .
    */
-  public int nextNode()
-  {   
+  public short filterNode(int testNode)
+  {
+    boolean foundKey = false;
+    Vector keys = m_keyDeclarations;
+
+    QName name = m_name;
+    KeyIterator ki = (KeyIterator)(((XNodeSet)m_keysNodes).getContainedIter());
+    org.apache.xpath.XPathContext xctxt = ki.getXPathContext();
     
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    NodeSetDTM m_cachedNodes = getCachedNodes();
-    
-    // We are not using the NodeSetDTM methods getCurrentPos() and nextNode()
-    // in this case because the nodeset is not cloned and therefore
-    // the positions it indicates may not be associated with the 
-    // current iterator.
-    if ((null != m_cachedNodes)
-        && (m_next < m_cachedNodes.size()))        
+    if(null == xctxt)
+    	assertion(false, "xctxt can not be null here!");
+
+    try
     {
-      int next = m_cachedNodes.elementAt(m_next); 
-      this.setCurrentPos(++m_next); 
-      m_lastFetched = next;
-      
-      return next;
+      XMLString lookupKey = m_ref;
+
+      // System.out.println("lookupKey: "+lookupKey);
+      int nDeclarations = keys.size();
+
+      // Walk through each of the declarations made with xsl:key
+      for (int i = 0; i < nDeclarations; i++)
+      {
+        KeyDeclaration kd = (KeyDeclaration) keys.elementAt(i);
+
+        // Only continue if the name on this key declaration
+        // matches the name on the iterator for this walker. 
+        if (!kd.getName().equals(name))
+          continue;
+
+        foundKey = true;
+        // xctxt.setNamespaceContext(ki.getPrefixResolver());
+
+        // Query from the node, according the the select pattern in the
+        // use attribute in xsl:key.
+        XObject xuse = kd.getUse().execute(xctxt, testNode, ki.getPrefixResolver());
+
+        if (xuse.getType() != xuse.CLASS_NODESET)
+        {
+          XMLString exprResult = xuse.xstr();
+
+          if (lookupKey.equals(exprResult))
+            return DTMIterator.FILTER_ACCEPT;
+        }
+        else
+        {
+          DTMIterator nl = ((XNodeSet)xuse).iterRaw();
+          int useNode;
+          
+          while (DTM.NULL != (useNode = nl.nextNode()))
+          {
+            DTM dtm = getDTM(useNode);
+            XMLString exprResult = dtm.getStringValue(useNode);
+            if ((null != exprResult) && lookupKey.equals(exprResult))
+              return DTMIterator.FILTER_ACCEPT;
+          }
+        }
+
+      } // end for(int i = 0; i < nDeclarations; i++)
     }
-    
-    if (m_foundLast)
+    catch (javax.xml.transform.TransformerException te)
     {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
+      throw new org.apache.xml.utils.WrappedRuntimeException(te);
     }
 
-    int next = DTM.NULL;       
-    if ( m_ki.getLookForMoreNodes()) 
-    {
-      ((KeyWalker)m_ki.getFirstWalker()).m_lookupKey = m_lookupKey;
-      next = m_ki.nextNode();        
-    }
-    
-    if (DTM.NULL != next)
-    {  
-      m_lastFetched = next;
-      this.setCurrentPos(++m_next);
-      return next;
-    }
-    else
-      m_foundLast = true;                      
-    
-    m_lastFetched = DTM.NULL;
-    return DTM.NULL;
-  }
-  
-  /**
-   * Get a cloned LocPathIterator that holds the same 
-   * position as this iterator.
-   *
-   * @return A clone of this iterator that holds the same node position.
-   *
-   * @throws CloneNotSupportedException 
-   */
-  public Object clone() throws CloneNotSupportedException
-  {
-    // I wonder if we really want to clone the second time.  Myriam review.
-    KeyRefIterator clone = (KeyRefIterator)super.clone();
-    // clone.m_ki = (KeyIterator)m_ki.clone();
-
-    return clone;
-  }
-  
-//  /**
-//   * Get a cloned Iterator that is reset to the beginning 
-//   * of the query.
-//   *
-//   * @return A cloned NodeIterator set of the start of the query.
-//   *
-//   * @throws CloneNotSupportedException
-//   */
-//  public NodeIterator cloneWithReset() throws CloneNotSupportedException
-//  {
-//    KeyRefIterator clone = (KeyRefIterator)super.cloneWithReset();
-//
-//    return clone;
-//  }
-  
-  /**
-   * Reset the iterator.
-   */
-  public void reset()
-  {
-    super.reset();
-    // setShouldCacheNodes(true);
-    setCurrentPos(0);
-  }
-  
-  /**
-   *  Detaches the iterator from the set which it iterated over, releasing
-   * any computational resources and placing the iterator in the INVALID
-   * state. After<code>detach</code> has been invoked, calls to
-   * <code>nextNode</code> or<code>previousNode</code> will raise the
-   * exception INVALID_STATE_ERR.
-   */
-  public void detach()
-  {    
-    // I don't think we want to detach at all for this iterator.
-    // Myriam needs to review.  -sb.
+    if (!foundKey)
+      throw new RuntimeException(
+        XSLMessages.createMessage(
+          XSLTErrorResources.ER_NO_XSLKEY_DECLARATION,
+          new Object[] { name.getLocalName()}));
+    return DTMIterator.FILTER_REJECT;
   }
 
-  
-  /**
-   * Add a node matching this ref to the cached nodes for this iterator 
-   *
-   *
-   * @param node Node to add to cached nodes
-   */
-  public void addNode(int node) 
-  {
-    NodeSetDTM m_cachedNodes = getCachedNodes();
-    if (null != m_cachedNodes)
-    {
-      if(!m_cachedNodes.contains(node))
-        m_cachedNodes.addElement(node);
-    }
-  }  
-       
-}
+  protected XMLString m_ref;
+  protected QName m_name;
+
+  /** Vector of Key declarations in the stylesheet.
+   *  @serial          */
+  protected Vector m_keyDeclarations;
+
+}
\ No newline at end of file
diff --git a/src/org/apache/xalan/transformer/KeyTable.java b/src/org/apache/xalan/transformer/KeyTable.java
index b29e8ef..660665d 100644
--- a/src/org/apache/xalan/transformer/KeyTable.java
+++ b/src/org/apache/xalan/transformer/KeyTable.java
@@ -56,29 +56,16 @@
  */
 package org.apache.xalan.transformer;
 
-//import org.w3c.dom.Element;
-//import org.w3c.dom.NamedNodeMap;
-//import org.w3c.dom.Node;
-//import org.w3c.dom.NodeList;
-import org.apache.xml.dtm.DTM;
-
 import java.util.Hashtable;
 import java.util.Vector;
-import java.util.Enumeration;
 
-import org.apache.xpath.NodeSetDTM;
-import org.apache.xpath.objects.XObject;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.XPathContext;
-//import org.apache.xpath.DOMHelper;
-import org.apache.xml.utils.QName;
-import org.apache.xalan.templates.KeyDeclaration;
-import org.apache.xpath.XPathContext;
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.DTM;
 import org.apache.xml.utils.PrefixResolver;
+import org.apache.xml.utils.QName;
 import org.apache.xml.utils.XMLString;
-import org.apache.xpath.axes.LocPathIterator;
-
-// import org.apache.xalan.dtm.*;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XNodeSet;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -111,16 +98,12 @@
    * The main iterator that will walk through the source  
    * tree for this key.
    */
-  private KeyIterator m_keyIter;
+  private XNodeSet m_keyNodes;
   
-  /**
-   * Hashtable of keys.
-   * The table is:
-   * a) keyed by key name,
-   * b) with a value that is a hashtable keyed by key values 
-   * with at value of KeyRefIterator(cloned).
-   */
-  private Hashtable m_defsTable;
+  KeyIterator getKeyIterator()
+  {
+  	return (KeyIterator)(m_keyNodes.getContainedIter());
+  }
 
   /**
    * Build a keys table.
@@ -133,14 +116,17 @@
    * @throws javax.xml.transform.TransformerException
    */
   public KeyTable(
-          int doc, PrefixResolver nscontext, QName name, Vector keyDeclarations, XPathContext xmlLiaison)
+          int doc, PrefixResolver nscontext, QName name, Vector keyDeclarations, XPathContext xctxt)
             throws javax.xml.transform.TransformerException
   {
 
     m_docKey = doc;
-    m_keyIter = new KeyIterator(doc, nscontext, name, keyDeclarations,
-                                xmlLiaison);
-    m_keyIter.setKeyTable(this);
+    KeyIterator ki = new KeyIterator(name, keyDeclarations);
+    
+    m_keyNodes = new XNodeSet(ki);
+    m_keyNodes.allowDetachToRelease(false);
+    
+    m_keyNodes.setRoot(xctxt.getDTM(doc).getDocument(), xctxt);
   }  
 
   /**
@@ -152,55 +138,15 @@
    * if the identifier is not found, it will return null,
    * otherwise it will return a LocPathIterator instance.
    */
-  public LocPathIterator getNodeSetDTMByKey(QName name, XMLString ref)
+  public XNodeSet getNodeSetDTMByKey(QName name, XMLString ref)
   {
+  	Vector keyDecls = getKeyIterator().getKeyDeclarations();
+  	org.apache.xml.dtm.DTMIterator keyNodes = m_keyNodes.iter();
+	XNodeSet refNodes = new XNodeSet( new KeyRefIterator(name, ref, keyDecls, keyNodes) );
+	
+	// I don't think setRoot needs to be called on refNodes!
+	return refNodes;
 
-    KeyIterator ki;
-    KeyRefIterator kiRef;
-    Hashtable refsTable = null;
-
-    // First look for the key in the existing key names table
-    if (m_defsTable != null)
-    {
-      refsTable = (Hashtable)m_defsTable.get(name);
-      if (refsTable != null)
-      {
-        Object kiObj = refsTable.get(ref);
-        if (kiObj != null)
-        {
-          // An entry already exists for this key name and value.
-          // Return a clone of the node iterator found.
-          try
-          {
-            // clone with reset??
-            kiRef = (KeyRefIterator)((KeyRefIterator)kiObj).clone();
-            return kiRef;
-          }
-          catch (CloneNotSupportedException cnse)
-          {
-            ki = null;
-          }
-        }
-      }
-    }
-
-    // No entry was found for this key name and value. Create one.
-    {
-      if (m_defsTable == null)
-        m_defsTable = new Hashtable();
-      if (refsTable == null)
-        refsTable = new Hashtable();
-      
-      // initialize walker only once!
-      if (m_keyIter.getFirstWalker().getRoot() == DTM.NULL)
-        m_keyIter.setLookupKey(ref);
-      else
-        ((KeyWalker)m_keyIter.getFirstWalker()).m_lookupKey = ref;
-      kiRef = new KeyRefIterator(ref, m_keyIter);
-      refsTable.put(ref, kiRef);
-      m_defsTable.put(name,refsTable);
-      return kiRef;              
-    } 
   }
 
   /**
@@ -211,47 +157,7 @@
    */
   public QName getKeyTableName()
   {
-    return m_keyIter.getName();
+    return getKeyIterator().getName();
   }
   
-  /**
-   * Add this node to the nodelist matching this key value. 
-   * If there was no existing entry for that key value, create
-   * one.   
-   *
-   * @param ref Key ref(from key use field)
-   * @param node Node matching that ref 
-   */
-  void addRefNode(XMLString ref, int node)
-  {
-    KeyRefIterator kiRef = null;
-    Hashtable refsTable = null;
-    if (m_defsTable != null)
-    {
-      refsTable = (Hashtable)m_defsTable.get(getKeyTableName());
-      if (refsTable != null)
-      {
-        Object kiObj = refsTable.get(ref);
-        if (kiObj != null)
-        {          
-          kiRef = (KeyRefIterator)kiObj;            
-        }
-      }
-    }
-    if (kiRef == null)
-    {  
-      if (m_defsTable == null)
-        m_defsTable = new Hashtable();
-      if (refsTable == null)
-      {  
-        refsTable = new Hashtable();
-        m_defsTable.put(getKeyTableName(),refsTable);
-      }
-      kiRef = new KeyRefIterator(ref, m_keyIter);
-      refsTable.put(ref, kiRef);      
-    }
-    kiRef.addNode(node); 
-  }
-  
-  
 }
diff --git a/src/org/apache/xalan/transformer/NodeSorter.java b/src/org/apache/xalan/transformer/NodeSorter.java
index d2fe6ce..626858a 100644
--- a/src/org/apache/xalan/transformer/NodeSorter.java
+++ b/src/org/apache/xalan/transformer/NodeSorter.java
@@ -565,7 +565,7 @@
         if (r.getType() == XObject.CLASS_NODESET)
         {
           // %REVIEW%
-          DTMIterator ni = (DTMIterator)r.object();
+          DTMIterator ni = ((XNodeSet)r).iterRaw();
           int current = ni.getCurrentNode();
           if(DTM.NULL == current)
             current = ni.nextNode();
diff --git a/src/org/apache/xalan/transformer/ResultTreeHandler.java b/src/org/apache/xalan/transformer/ResultTreeHandler.java
index 0cd3e00..4f570c0 100644
--- a/src/org/apache/xalan/transformer/ResultTreeHandler.java
+++ b/src/org/apache/xalan/transformer/ResultTreeHandler.java
@@ -978,11 +978,14 @@
     int doc = obj.rtf();
     DTM dtm = support.getDTM(doc);
 
-    for (int n = dtm.getFirstChild(doc); DTM.NULL != n;
-            n = dtm.getNextSibling(n))
+    if(null != dtm)
     {
-      flushPending(true);  // I think.
-      dtm.dispatchToEvents(n, this);
+	    for (int n = dtm.getFirstChild(doc); DTM.NULL != n;
+	            n = dtm.getNextSibling(n))
+	    {
+	      flushPending(true);  // I think.
+	      dtm.dispatchToEvents(n, this);
+	    }
     }
   }
 
diff --git a/src/org/apache/xalan/transformer/TransformerImpl.java b/src/org/apache/xalan/transformer/TransformerImpl.java
index de2e394..26d8fad 100644
--- a/src/org/apache/xalan/transformer/TransformerImpl.java
+++ b/src/org/apache/xalan/transformer/TransformerImpl.java
@@ -634,7 +634,9 @@
       }
       setBaseURLOfSource(base);
       DTMManager mgr = m_xcontext.getDTMManager();
+      // int dtmRoot = m_xcontext.getSourceTreeManager().getNode(source);
       DTM dtm = mgr.getDTM(source, false, this, true, true);
+      // m_xcontext.getSourceTreeManager().putDocumentInCache(dtm.getDocument(), source);
       dtm.setProperty(XalanProperties.SOURCE_LOCATION,
                       new Boolean(m_useSourceLocationProperty));
       
@@ -699,8 +701,8 @@
       String msg = spe.getMessage();
       SAXSourceLocator loc = new SAXSourceLocator(spe);
 
-      //m_errorHandler.fatalError(new TransformerException( msg, loc ));
-      m_errorHandler.fatalError(new TransformerException(spe));
+      m_errorHandler.fatalError(new TransformerException( msg, loc ));
+      // m_errorHandler.fatalError(new TransformerException(spe));
     }
     catch (org.xml.sax.SAXException se)
     {
diff --git a/src/org/apache/xml/dtm/ref/DTMNodeList.java b/src/org/apache/xml/dtm/ref/DTMNodeList.java
index 761485e..a7201be 100644
--- a/src/org/apache/xml/dtm/ref/DTMNodeList.java
+++ b/src/org/apache/xml/dtm/ref/DTMNodeList.java
@@ -161,6 +161,14 @@
       if(dtm_iter!=null)
       {
         int handle=dtm_iter.item(index);
+        if(DTM.NULL == handle)
+        {
+        	throw new RuntimeException(("DTM.NULL IN NODELIST!!! "+dtm_iter.getClass().getName())+"\n"+
+        	("contained: "+((org.apache.xpath.objects.XNodeSet)dtm_iter).getContainedIter().getClass().getName())+"\n"+
+        	("contained in doc order: "+((org.apache.xpath.objects.XNodeSet)dtm_iter).isDocOrdered())+"\n"+
+        	("hasCache: "+((org.apache.xpath.objects.XNodeSet)dtm_iter).hasCache())+"\n"+
+        	("length "+dtm_iter.getLength()));
+        }
         return dtm_iter.getDTM(handle).getNode(handle);
       }
       else
diff --git a/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java b/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
index ec0056e..b9fd9d2 100644
--- a/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
+++ b/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
@@ -852,7 +852,6 @@
     {
       FastStringBuffer buf = StringBufferPool.get();
       String s;
-  
       try
       {
         getNodeData(node, buf);
@@ -863,8 +862,20 @@
       {
         StringBufferPool.free(buf);
       }
-  
       return m_xstrf.newstr( s );
+ 		// sb: The following can be used to reduce the number of 
+ 		// string objects.  However, tests do not show this to 
+ 		// be a win.
+		//      getNodeData(node, buf);
+		//      if(buf.length() > 0)
+		//      {
+		//      	return m_xstrf.newstr(buf, 0, buf.length());
+		//      }
+		//      else
+		//      {
+		//      	StringBufferPool.free(buf);
+		//      	return m_xstrf.emptystr();
+		//      }
     }
     else if(TEXT_NODE == type || CDATA_SECTION_NODE == type)
     {
diff --git a/src/org/apache/xml/utils/DefaultErrorHandler.java b/src/org/apache/xml/utils/DefaultErrorHandler.java
index c6caaab..ce8ed58 100644
--- a/src/org/apache/xml/utils/DefaultErrorHandler.java
+++ b/src/org/apache/xml/utils/DefaultErrorHandler.java
@@ -93,7 +93,8 @@
    */
   public DefaultErrorHandler()
   {
-    m_pw = new PrintWriter(System.err, true);
+    // m_pw = new PrintWriter(System.err, true);
+    m_pw = null;
   }
 
 
@@ -115,6 +116,8 @@
    */
   public void warning(SAXParseException exception) throws SAXException
   {
+  	if(null == m_pw)
+  		m_pw = new PrintWriter(System.err, true);
     printLocation(m_pw, exception);
     m_pw.println("Parser warning: " + exception.getMessage());
   }
@@ -194,6 +197,9 @@
    */
   public void warning(TransformerException exception) throws TransformerException
   {
+  	if(null == m_pw)
+  		m_pw = new PrintWriter(System.err, true);
+
     printLocation(m_pw, exception);
 
     m_pw.println(exception.getMessage());
@@ -223,6 +229,9 @@
    */
   public void error(TransformerException exception) throws TransformerException
   {
+  	if(null == m_pw)
+  		m_pw = new PrintWriter(System.err, true);
+
     // printLocation(exception);
     // ensureLocationSet(exception);
 
@@ -289,9 +298,11 @@
     exception.setLocator(locator);
   }
   
-  public static void printLocation(PrintStream pw, TransformerException exception)
+  public static void printLocation(PrintStream ps, TransformerException exception)
   {
-    printLocation(new PrintWriter(pw), exception);
+  	PrintWriter pw = new PrintWriter(ps);
+    printLocation(pw, exception);
+    pw.flush();
   }
   
   public static void printLocation(PrintWriter pw, Throwable exception)
diff --git a/src/org/apache/xml/utils/NodeVector.java b/src/org/apache/xml/utils/NodeVector.java
index ccf0fbc..daa0f6c 100644
--- a/src/org/apache/xml/utils/NodeVector.java
+++ b/src/org/apache/xml/utils/NodeVector.java
@@ -561,6 +561,9 @@
       m_map = new int[m_blocksize];
       m_mapSize = m_blocksize;
     }
+    
+    if(index == -1)
+    	addElement(node);
 
     m_map[index] = node;
   }
diff --git a/src/org/apache/xml/utils/SuballocatedIntVector.java b/src/org/apache/xml/utils/SuballocatedIntVector.java
index 235d064..8b86daf 100644
--- a/src/org/apache/xml/utils/SuballocatedIntVector.java
+++ b/src/org/apache/xml/utils/SuballocatedIntVector.java
@@ -452,7 +452,6 @@
     // This is actually a significant optimization!
     if(i<m_blocksize)
       return m_map0[i];
-
     return m_map[i>>>m_SHIFT][i&m_MASK];
   }
 
diff --git a/src/org/apache/xpath/Expression.java b/src/org/apache/xpath/Expression.java
index 21ab37e..778a3ce 100644
--- a/src/org/apache/xpath/Expression.java
+++ b/src/org/apache/xpath/Expression.java
@@ -58,6 +58,7 @@
 
 //import org.w3c.dom.Node;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XNodeSet;
 import org.apache.xpath.res.XPATHErrorResources;
 import org.apache.xalan.res.XSLMessages;
 
@@ -85,7 +86,7 @@
  * and walkers, which must be cloned in order to be used -- the original must
  * still be immutable.
  */
-public abstract class Expression implements java.io.Serializable
+public abstract class Expression implements java.io.Serializable, ExpressionNode, XPathVisitable
 {
 
   /**
@@ -93,7 +94,7 @@
    *  messages. May be null.
    *  @serial
    */
-  protected SourceLocator m_slocator;
+  private ExpressionNode m_parent;
 
   /**
    * Tell if this expression or it's subexpressions can traverse outside
@@ -105,18 +106,18 @@
   {
     return false;
   }
-
-  /**
-   * Set the location where this expression was built from.
-   *
-   *
-   * @param locator the location where this expression was built from, may be
-   *                null.
-   */
-  public void setSourceLocator(SourceLocator locator)
-  {
-    m_slocator = locator;
-  }
+  
+//  /**
+//   * Set the location where this expression was built from.
+//   *
+//   *
+//   * @param locator the location where this expression was built from, may be
+//   *                null.
+//   */
+//  public void setSourceLocator(SourceLocator locator)
+//  {
+//    m_slocator = locator;
+//  }
 
   /**
    * Execute an expression in the XPath runtime context, and return the
@@ -179,11 +180,32 @@
     throws javax.xml.transform.TransformerException;
 
   /**
+   * Execute an expression in the XPath runtime context, and return the
+   * result of the expression, but tell that a "safe" object doesn't have 
+   * to be returned.  The default implementation just calls execute(xctxt).
+   *
+   *
+   * @param xctxt The XPath runtime context.
+   * @param destructiveOK true if a "safe" object doesn't need to be returned.
+   *
+   * @return The result of the expression in the form of a <code>XObject</code>.
+   *
+   * @throws javax.xml.transform.TransformerException if a runtime exception
+   *         occurs.
+   */
+  public XObject execute(XPathContext xctxt, boolean destructiveOK)
+    throws javax.xml.transform.TransformerException
+  {
+  	return execute(xctxt);
+  }
+
+
+  /**
    * Evaluate expression to a number.
    *
    *
-   * NEEDSDOC @param xctxt
-   * @return 0.0
+   * @param xctxt The XPath runtime context.
+   * @return The expression evaluated as a double.
    *
    * @throws javax.xml.transform.TransformerException
    */
@@ -197,7 +219,7 @@
    * Evaluate expression to a boolean.
    *
    *
-   * NEEDSDOC @param xctxt
+   * @param xctxt The XPath runtime context.
    * @return false
    *
    * @throws javax.xml.transform.TransformerException
@@ -212,7 +234,7 @@
    * Cast result object to a string.
    *
    *
-   * NEEDSDOC @param xctxt
+   * @param xctxt The XPath runtime context.
    * @return The string this wraps or the empty string if null
    *
    * @throws javax.xml.transform.TransformerException
@@ -244,7 +266,8 @@
   public int asNode(XPathContext xctxt)
           throws javax.xml.transform.TransformerException
   {
-    return execute(xctxt).iter().nextNode();
+  	DTMIterator iter = execute(xctxt).iter();
+    return iter.nextNode();
   }
 
   /**
@@ -256,7 +279,7 @@
    * @param contextNode The node that "." expresses.
    *
    *
-   * NEEDSDOC ($objectName$) @return
+   * @return A valid DTMIterator.
    * @throws TransformerException thrown if the active ProblemListener decides
    * the error condition is severe enough to halt processing.
    *
@@ -277,6 +300,39 @@
       xctxt.popCurrentNodeAndExpression();
     }
   }
+  
+  /**
+   * <meta name="usage" content="experimental"/>
+   * Given an select expression and a context, evaluate the XPath
+   * and return the resulting iterator, but do not clone.
+   *
+   * @param xctxt The execution context.
+   * @param contextNode The node that "." expresses.
+   *
+   *
+   * @return A valid DTMIterator.
+   * @throws TransformerException thrown if the active ProblemListener decides
+   * the error condition is severe enough to halt processing.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public DTMIterator asIteratorRaw(XPathContext xctxt, int contextNode)
+          throws javax.xml.transform.TransformerException
+  {
+
+    try
+    {
+      xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
+
+      XNodeSet nodeset = (XNodeSet)execute(xctxt);
+      return nodeset.iterRaw();
+    }
+    finally
+    {
+      xctxt.popCurrentNodeAndExpression();
+    }
+  }
+
 
   /**
    * Execute an expression in the XPath runtime context, and return the
@@ -301,6 +357,7 @@
     XObject obj = execute(xctxt);
 
     obj.dispatchCharactersEvents(handler);
+    obj.detach();
   }
 
   /**
@@ -328,6 +385,34 @@
    * NEEDSDOC @param globalsSize
    */
   public abstract void fixupVariables(java.util.Vector vars, int globalsSize);
+  
+  /**
+   * Compare this object with another object and see 
+   * if they are equal, include the sub heararchy.
+   * 
+   * @param expr Another expression object.
+   * @return true if this objects class and the expr
+   * object's class are the same, and the data contained 
+   * within both objects are considered equal.
+   */
+  public abstract boolean deepEquals(Expression expr);
+  
+  /**
+   * This is a utility method to tell if the passed in 
+   * class is the same class as this.  It is to be used by
+   * the deepEquals method.  I'm bottlenecking it here 
+   * because I'm not totally confident that comparing the 
+   * class objects is the best way to do this.
+   * @return true of the passed in class is the exact same 
+   * class as this class.
+   */
+  protected final boolean isSameClass(Expression expr)
+  {
+  	if(null == expr)
+  	  return false;
+  	  
+  	return (getClass() == expr.getClass());
+  }
 
   /**
    * Warn the user of an problem.
@@ -371,7 +456,6 @@
    * @throws javax.xml.transform.TransformerException
    */
   public void assertion(boolean b, java.lang.String msg)
-          throws javax.xml.transform.TransformerException
   {
 
     if (!b)
@@ -409,9 +493,141 @@
     if (null != xctxt)
     {
       ErrorListener eh = xctxt.getErrorListener();
-      TransformerException te = new TransformerException(fmsg, m_slocator);
+      TransformerException te = new TransformerException(fmsg, this);
 
       eh.fatalError(te);
     }
   }
+  
+  /**
+   * Get the first non-Expression parent of this node.
+   * @return null or first ancestor that is not an Expression.
+   */
+  public ExpressionNode getExpressionOwner()
+  {
+  	ExpressionNode parent = exprGetParent();
+  	while((null != parent) && (parent instanceof Expression))
+  		parent = parent.exprGetParent();
+  	return parent;
+  }
+  
+  //=============== ExpressionNode methods ================
+  
+  /** This pair of methods are used to inform the node of its
+    parent. */
+  public void exprSetParent(ExpressionNode n)
+  {
+  	assertion(n != this, "Can not parent an expression to itself!");
+  	m_parent = n;
+  }
+  
+  public ExpressionNode exprGetParent()
+  {
+  	return m_parent;
+  }
+
+  /** This method tells the node to add its argument to the node's
+    list of children.  */
+  public void exprAddChild(ExpressionNode n, int i)
+  {
+  	assertion(false, "exprAddChild method not implemented!");
+  }
+
+  /** This method returns a child node.  The children are numbered
+     from zero, left to right. */
+  public ExpressionNode exprGetChild(int i)
+  {
+  	return null;
+  }
+
+  /** Return the number of children the node has. */
+  public int exprGetNumChildren()
+  {
+  	return 0;
+  }
+  
+  //=============== SourceLocator methods ================
+
+  /**
+   * Return the public identifier for the current document event.
+   *
+   * <p>The return value is the public identifier of the document
+   * entity or of the external parsed entity in which the markup that
+   * triggered the event appears.</p>
+   *
+   * @return A string containing the public identifier, or
+   *         null if none is available.
+   * @see #getSystemId
+   */
+  public String getPublicId()
+  {
+  	if(null == m_parent)
+  	  return null;
+  	return m_parent.getPublicId();
+  }
+
+  /**
+   * Return the system identifier for the current document event.
+   *
+   * <p>The return value is the system identifier of the document
+   * entity or of the external parsed entity in which the markup that
+   * triggered the event appears.</p>
+   *
+   * <p>If the system identifier is a URL, the parser must resolve it
+   * fully before passing it to the application.</p>
+   *
+   * @return A string containing the system identifier, or null
+   *         if none is available.
+   * @see #getPublicId
+   */
+  public String getSystemId()
+  {
+  	if(null == m_parent)
+  	  return null;
+  	return m_parent.getSystemId();
+  }
+
+  /**
+   * Return the line number where the current document event ends.
+   *
+   * <p><strong>Warning:</strong> The return value from the method
+   * is intended only as an approximation for the sake of error
+   * reporting; it is not intended to provide sufficient information
+   * to edit the character content of the original XML document.</p>
+   *
+   * <p>The return value is an approximation of the line number
+   * in the document entity or external parsed entity where the
+   * markup that triggered the event appears.</p>
+   *
+   * @return The line number, or -1 if none is available.
+   * @see #getColumnNumber
+   */
+  public int getLineNumber()
+  {
+  	if(null == m_parent)
+  	  return 0;
+  	return m_parent.getLineNumber();
+  }
+
+  /**
+   * Return the character position where the current document event ends.
+   *
+   * <p><strong>Warning:</strong> The return value from the method
+   * is intended only as an approximation for the sake of error
+   * reporting; it is not intended to provide sufficient information
+   * to edit the character content of the original XML document.</p>
+   *
+   * <p>The return value is an approximation of the column number
+   * in the document entity or external parsed entity where the
+   * markup that triggered the event appears.</p>
+   *
+   * @return The column number, or -1 if none is available.
+   * @see #getLineNumber
+   */
+  public int getColumnNumber()
+  {
+  	if(null == m_parent)
+  	  return 0;
+  	return m_parent.getColumnNumber();
+  }
 }
diff --git a/src/org/apache/xpath/VariableStack.java b/src/org/apache/xpath/VariableStack.java
index 5ae3b2a..7964d72 100644
--- a/src/org/apache/xpath/VariableStack.java
+++ b/src/org/apache/xpath/VariableStack.java
@@ -171,6 +171,9 @@
     // to look one under without having to check if we're at zero.
     // (As long as the caller doesn't screw up link/unlink.)
     _links[_linksTop++] = 0;
+    
+    int n = _sf.length;
+    _sf = new XObject[n];
   }
 
   /**
@@ -319,8 +322,41 @@
     if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
       return (_sf[index] = val.execute(xctxt));
 
-    return val;
+    return val.getFresh();
   }
+  
+  /**
+   * Get a local variable or parameter in the current stack frame.
+   *
+   *
+   * @param xctxt The XPath context, which must be passed in order to
+   * lazy evaluate variables.
+   *
+   * @param index Local variable index relative to the current stack
+   * frame bottom.
+   *
+   * @return The value of the variable.
+   *
+   * @throws TransformerException
+   */
+  public XObject getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)
+          throws TransformerException
+  {
+
+    index += _cfb;
+
+    XObject val = _sf[index];
+    
+    if(null == val)
+      throw new TransformerException("Variable accessed before it is bound!", xctxt.getSAXLocator());
+
+    // Lazy execution of variables.
+    if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
+      return (_sf[index] = val.execute(xctxt));
+
+    return destructiveOK ? val : val.getFresh();
+  }
+
 
   /**
    * Get a local variable or parameter in the current stack frame.
@@ -342,7 +378,7 @@
 
     XObject val = _sf[index];
 
-    return val;
+    return val.getFresh();
   }
 
   /**
@@ -418,8 +454,36 @@
     if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
       return (_sf[index] = val.execute(xctxt));
 
-    return val;
+    return val.getFresh();
   }
+  
+  /**
+   * Get a global variable or parameter from the global stack frame.
+   *
+   *
+   * @param xctxt The XPath context, which must be passed in order to
+   * lazy evaluate variables.
+   *
+   * @param index Global variable index relative to the global stack
+   * frame bottom.
+   *
+   * @return The value of the variable.
+   *
+   * @throws TransformerException
+   */
+  public XObject getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)
+          throws TransformerException
+  {
+
+    XObject val = _sf[index];
+
+    // Lazy execution of variables.
+    if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
+      return (_sf[index] = val.execute(xctxt));
+
+    return destructiveOK ? val : val.getFresh();
+  }
+
 
   /**
    * Get a variable based on it's qualified name.
diff --git a/src/org/apache/xpath/XPath.java b/src/org/apache/xpath/XPath.java
index dabfc1b..fbd4e97 100644
--- a/src/org/apache/xpath/XPath.java
+++ b/src/org/apache/xpath/XPath.java
@@ -56,48 +56,31 @@
  */
 package org.apache.xpath;
 
-//import org.w3c.dom.Node;
-//import org.w3c.dom.Document;
-//import org.w3c.dom.traversal.NodeIterator;
-//import org.w3c.dom.DocumentFragment;
-
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-
+import java.io.Serializable;
 import java.util.Vector;
 
-import java.io.Serializable;
-import java.io.ObjectInputStream;
-import java.io.IOException;
-
-import org.apache.xml.utils.PrefixResolver;
-import org.apache.xml.utils.QName;
-import org.apache.xpath.res.XPATHErrorResources;
-import org.apache.xpath.functions.Function;
-
-// import org.apache.xpath.functions.FuncLoader;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.compiler.XPathParser;
-import org.apache.xpath.compiler.OpMap;  // temp
-import org.apache.xpath.compiler.OpCodes;  // temp
-import org.apache.xpath.compiler.PsuedoNames;  // temp
-import org.apache.xpath.compiler.FunctionTable;  // temp
-import org.apache.xpath.objects.XObject;
-import org.apache.xalan.res.XSLMessages;
-import org.apache.xpath.objects.*;
-
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.SourceLocator;
 import javax.xml.transform.ErrorListener;
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.utils.PrefixResolver;
 import org.apache.xml.utils.SAXSourceLocator;
-import org.apache.xpath.patterns.NodeTest;
+import org.apache.xml.utils.WrappedRuntimeException;
+import org.apache.xpath.compiler.Compiler;
+import org.apache.xpath.compiler.FunctionTable;
+import org.apache.xpath.compiler.XPathParser;
+import org.apache.xpath.functions.Function;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.res.XPATHErrorResources;
+import org.w3c.dom.Node;
 
 /**
  * <meta name="usage" content="advanced"/>
  * The XPath class wraps an expression object and provides general services 
  * for execution of that expression.
  */
-public class XPath implements Serializable
+public class XPath implements Serializable, ExpressionOwner
 {
 
   /** The top of the expression tree. 
@@ -138,6 +121,8 @@
    */
   public void setExpression(Expression exp)
   {
+  	if(null != m_mainExp)
+    	exp.exprSetParent(m_mainExp.exprGetParent()); // a bit bogus
     m_mainExp = exp;
   }
 
@@ -149,21 +134,21 @@
    */
   public SourceLocator getLocator()
   {
-    return m_mainExp.m_slocator;
+    return m_mainExp;
   }
 
-  /**
-   * Set the SourceLocator on the expression object.
-   *
-   *
-   * @param l the SourceLocator on the expression object, which may be null.
-   */
-  public void setLocator(SourceLocator l)
-  {
-    // Note potential hazards -- l may not be serializable, or may be changed
-      // after being assigned here.
-    m_mainExp.setSourceLocator(l);
-  }
+//  /**
+//   * Set the SourceLocator on the expression object.
+//   *
+//   *
+//   * @param l the SourceLocator on the expression object, which may be null.
+//   */
+//  public void setLocator(SourceLocator l)
+//  {
+//    // Note potential hazards -- l may not be serializable, or may be changed
+//      // after being assigned here.
+//    m_mainExp.setSourceLocator(l);
+//  }
 
   /** The pattern string, mainly kept around for diagnostic purposes.
    *  @serial  */
@@ -225,6 +210,11 @@
 
     // System.out.println("expr: "+expr);
     this.setExpression(expr);
+    
+    if((null != locator) && locator instanceof ExpressionNode)
+    {
+    	expr.exprSetParent((ExpressionNode)locator);
+    }
 
   }
   
@@ -575,6 +565,20 @@
                          + slocator.getColumnNumber());
     }
   }
+  
+  /**
+   * This will traverse the heararchy, calling the visitor for 
+   * each member.  If the called visitor method returns 
+   * false, the subtree should not be called.
+   * 
+   * @param owner The owner of the visitor, where that path may be 
+   *              rewritten if needed.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	m_mainExp.callVisitors(this, visitor);
+  }
 
   /**
    * <meta name="usage" content="advanced"/>
diff --git a/src/org/apache/xpath/XPathContext.java b/src/org/apache/xpath/XPathContext.java
index e7495b0..8b645e5 100644
--- a/src/org/apache/xpath/XPathContext.java
+++ b/src/org/apache/xpath/XPathContext.java
@@ -713,7 +713,10 @@
    */
   public final void popContextNodeList()
   {
-    m_contextNodeLists.pop();
+  	if(m_contextNodeLists.isEmpty())
+  	  System.err.println("Warning: popContextNodeList when stack is empty!");
+  	else
+      m_contextNodeLists.pop();
   }
 
   /**
diff --git a/src/org/apache/xpath/axes/AttributeIterator.java b/src/org/apache/xpath/axes/AttributeIterator.java
index cc7d26e..f31fb6e 100644
--- a/src/org/apache/xpath/axes/AttributeIterator.java
+++ b/src/org/apache/xpath/axes/AttributeIterator.java
@@ -90,7 +90,7 @@
   {
     super(compiler, opPos, analysis);
   }
-  
+    
   /**
    * Get the next node via getFirstAttribute && getNextAttribute.
    */
diff --git a/src/org/apache/xpath/axes/AxesWalker.java b/src/org/apache/xpath/axes/AxesWalker.java
index 474f3e9..88aa921 100644
--- a/src/org/apache/xpath/axes/AxesWalker.java
+++ b/src/org/apache/xpath/axes/AxesWalker.java
@@ -56,36 +56,25 @@
  */
 package org.apache.xpath.axes;
 
-import java.util.Stack;
 import java.util.Vector;
 
-// Xalan imports
-import org.apache.xpath.axes.LocPathIterator;
-import org.apache.xml.utils.PrefixResolver;
-import org.apache.xpath.axes.SubContextList;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.compiler.OpCodes;
-import org.apache.xpath.Expression;
-import org.apache.xpath.objects.XObject;
-import org.apache.xpath.patterns.NodeTestFilter;
-import org.apache.xpath.patterns.NodeTest;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.XPath;
-
+import javax.xml.transform.TransformerException;
 import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
 import org.apache.xml.dtm.DTMAxisTraverser;
-import org.apache.xml.dtm.Axis;
-
-import org.apache.xml.utils.XMLString;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.compiler.Compiler;
+import org.apache.xpath.patterns.NodeTest;
 
 /**
  * Serves as common interface for axes Walkers, and stores common
  * state variables.
  */
 public class AxesWalker extends PredicatedNodeTest
-        implements Cloneable
+        implements Cloneable, PathComponent, ExpressionOwner
 {
   
   /**
@@ -215,6 +204,19 @@
     return null;    
   }
   
+  /**
+   * Detaches the walker from the set which it iterated over, releasing
+   * any computational resources and placing the iterator in the INVALID
+   * state.
+   */
+  public void detach()
+  { 
+  	m_currentNode = DTM.NULL;
+  	m_dtm = null;
+  	m_isFresh = true;
+  	m_root = DTM.NULL;
+  }
+  
   //=============== TreeWalker Implementation ===============
 
   /**
@@ -227,6 +229,17 @@
   {
     return m_root;
   }
+  
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+  	int axis = getAxis();
+  	int bit = WalkerFactory.getAnalysisBitFromAxes(axis);
+  	return bit;
+  }
 
   /**
    * Set the root node of the TreeWalker.
@@ -237,7 +250,8 @@
   public void setRoot(int root)
   {
     // %OPT% Get this directly from the lpi.
-    m_dtm = wi().getXPathContext().getDTM(root);
+    XPathContext xctxt = wi().getXPathContext();
+    m_dtm = xctxt.getDTM(root);
     m_traverser = m_dtm.getAxisTraverser(m_axis);
     m_isFresh = true;
     m_foundLast = false;
@@ -527,7 +541,59 @@
   {
     return m_axis;
   }
+  
+  /**
+   * This will traverse the heararchy, calling the visitor for 
+   * each member.  If the called visitor method returns 
+   * false, the subtree should not be called.
+   * 
+   * @param owner The owner of the visitor, where that path may be 
+   *              rewritten if needed.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	if(visitor.visitStep(owner, this))
+  	{
+  		callPredicateVisitors(visitor);
+  		if(null != m_nextWalker)
+  		{
+  			m_nextWalker.callVisitors(this, visitor);
+  		}
+  	}
+  }
+  
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_nextWalker;
+  }
 
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+  	exp.exprSetParent(this);
+  	m_nextWalker = (AxesWalker)exp;
+  }
+  
+    /**
+     * @see Expression#deepEquals(Expression)
+     */
+    public boolean deepEquals(Expression expr)
+    {
+      if (!super.deepEquals(expr))
+                return false;
+
+      AxesWalker walker = (AxesWalker)expr;
+      if(this.m_axis != walker.m_axis)
+      	return false;
+
+      return true;
+    }
 
   /**
    *  The root node of the TreeWalker, as specified when it was created.
@@ -554,5 +620,5 @@
   protected int m_axis = -1;
 
   /** The DTM inner traversal class, that corresponds to the super axis. */
-  protected DTMAxisTraverser m_traverser;   
+  protected DTMAxisTraverser m_traverser; 
 }
diff --git a/src/org/apache/xpath/axes/BasicTestIterator.java b/src/org/apache/xpath/axes/BasicTestIterator.java
new file mode 100644
index 0000000..7f822b7
--- /dev/null
+++ b/src/org/apache/xpath/axes/BasicTestIterator.java
@@ -0,0 +1,203 @@
+package org.apache.xpath.axes;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.compiler.Compiler;
+
+/**
+ * Base for iterators that handle predicates.  Does the basic next 
+ * node logic, so all the derived iterator has to do is get the 
+ * next node.
+ */
+public abstract class BasicTestIterator extends LocPathIterator
+{
+  /**
+   * Create a LocPathIterator object.
+   *
+   * @param nscontext The namespace context for this iterator,
+   * should be OK if null.
+   */
+  protected BasicTestIterator()
+  {
+  }
+
+
+  /**
+   * Create a LocPathIterator object.
+   *
+   * @param nscontext The namespace context for this iterator,
+   * should be OK if null.
+   */
+  protected BasicTestIterator(PrefixResolver nscontext)
+  {
+
+    super(nscontext);
+  }
+
+  /**
+   * Create a LocPathIterator object, including creation
+   * of step walkers from the opcode list, and call back
+   * into the Compiler to create predicate expressions.
+   *
+   * @param compiler The Compiler which is creating
+   * this expression.
+   * @param opPos The position of this iterator in the
+   * opcode list from the compiler.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  protected BasicTestIterator(Compiler compiler, int opPos, int analysis)
+          throws javax.xml.transform.TransformerException
+  {
+    super(compiler, opPos, analysis, false);
+    
+    int firstStepPos = compiler.getFirstChildPos(opPos);
+    int whatToShow = compiler.getWhatToShow(firstStepPos);
+
+    if ((0 == (whatToShow
+               & (DTMFilter.SHOW_ATTRIBUTE 
+               | DTMFilter.SHOW_NAMESPACE 
+               | DTMFilter.SHOW_ELEMENT
+               | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) 
+               || (whatToShow == DTMFilter.SHOW_ALL))
+      initNodeTest(whatToShow);
+    else
+    {
+      initNodeTest(whatToShow, compiler.getStepNS(firstStepPos),
+                              compiler.getStepLocalName(firstStepPos));
+    }
+    initPredicateInfo(compiler, firstStepPos);
+  }
+
+  /**
+   * Create a LocPathIterator object, including creation
+   * of step walkers from the opcode list, and call back
+   * into the Compiler to create predicate expressions.
+   *
+   * @param compiler The Compiler which is creating
+   * this expression.
+   * @param opPos The position of this iterator in the
+   * opcode list from the compiler.
+   * @param shouldLoadWalkers True if walkers should be
+   * loaded, or false if this is a derived iterator and
+   * it doesn't wish to load child walkers.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  protected BasicTestIterator(
+          Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
+            throws javax.xml.transform.TransformerException
+  {
+    super(compiler, opPos, analysis, shouldLoadWalkers);
+  }
+
+	
+  /**
+   * Get the next node via getNextXXX.  Bottlenecked for derived class override.
+   * @return The next node on the axis, or DTM.NULL.
+   */
+  protected abstract int getNextNode();
+
+  /**
+   *  Returns the next node in the set and advances the position of the
+   * iterator in the set. After a NodeIterator is created, the first call
+   * to nextNode() returns the first node in the set.
+   *
+   * @return  The next <code>Node</code> in the set being iterated over, or
+   *   <code>null</code> if there are no more members in that set.
+   */
+  public int nextNode()
+  {      
+  	if(m_foundLast)
+  		return DTM.NULL;
+  		
+    if(DTM.NULL == m_lastFetched)
+    {
+      resetProximityPositions();
+    }
+
+    int next;
+    
+    org.apache.xpath.VariableStack vars;
+    int savedStart;
+    if (-1 != m_stackFrame)
+    {
+      vars = m_execContext.getVarStack();
+
+      // These three statements need to be combined into one operation.
+      savedStart = vars.getStackFrame();
+
+      vars.setStackFrame(m_stackFrame);
+    }
+    else
+    {
+      // Yuck.  Just to shut up the compiler!
+      vars = null;
+      savedStart = 0;
+    }
+    
+    try
+    {
+      do
+      {
+        next = getNextNode();
+  
+        if (DTM.NULL != next)
+        {
+          if(DTMIterator.FILTER_ACCEPT == acceptNode(next))
+            break;
+          else
+            continue;
+        }
+        else
+          break;
+      }
+      while (next != DTM.NULL);
+  
+      if (DTM.NULL != next)
+      {
+      	m_pos++;
+        return next;
+      }
+      else
+      {
+        m_foundLast = true;
+  
+        return DTM.NULL;
+      }
+    }
+    finally
+    {
+      if (-1 != m_stackFrame)
+      {
+        // These two statements need to be combined into one operation.
+        vars.setStackFrame(savedStart);
+      }
+    }
+  }
+  
+  /**
+   *  Get a cloned Iterator that is reset to the beginning
+   *  of the query.
+   * 
+   *  @return A cloned NodeIterator set of the start of the query.
+   * 
+   *  @throws CloneNotSupportedException
+   */
+  public DTMIterator cloneWithReset() throws CloneNotSupportedException
+  {
+
+    ChildTestIterator clone = (ChildTestIterator) super.cloneWithReset();
+
+    clone.resetProximityPositions();
+
+    return clone;
+  }
+
+
+}
+
diff --git a/src/org/apache/xpath/axes/ChildIterator.java b/src/org/apache/xpath/axes/ChildIterator.java
index 935d371..e5e39e2 100644
--- a/src/org/apache/xpath/axes/ChildIterator.java
+++ b/src/org/apache/xpath/axes/ChildIterator.java
@@ -122,27 +122,8 @@
    */
   public int nextNode()
   {
-
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if ((null != m_cachedNodes)
-            && (m_next < m_cachedNodes.size()))
-    {
-      int next = m_cachedNodes.elementAt(m_next);
-    
-      incrementNextPosition();
-      m_currentContextNode = next;
-
-      return next;
-    }
-
-    if (m_foundLast)
-    {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
-    }
+  	if(m_foundLast)
+  		return DTM.NULL;
 
     int next;
 
@@ -153,11 +134,7 @@
     // m_lastFetched = next;
     if (DTM.NULL != next)
     {
-      if (null != m_cachedNodes)
-        m_cachedNodes.addElement(m_lastFetched);
-
-      m_next++;
-
+      m_pos++;
       return next;
     }
     else
diff --git a/src/org/apache/xpath/axes/ChildTestIterator.java b/src/org/apache/xpath/axes/ChildTestIterator.java
index f41c62f..9515a1f 100644
--- a/src/org/apache/xpath/axes/ChildTestIterator.java
+++ b/src/org/apache/xpath/axes/ChildTestIterator.java
@@ -74,7 +74,7 @@
  * children patterns that have a node test, and possibly a predicate.
  * @see org.apache.xpath.axes.WalkerFactory#newLocPathIterator
  */
-public class ChildTestIterator extends LocPathIterator
+public class ChildTestIterator extends BasicTestIterator
 {
   /** The traverser to use to navigate over the descendants. */
   transient protected DTMAxisTraverser m_traverser;
@@ -95,37 +95,17 @@
   ChildTestIterator(Compiler compiler, int opPos, int analysis)
           throws javax.xml.transform.TransformerException
   {
-
-    super(compiler, opPos, analysis, false);
-
-    int firstStepPos = compiler.getFirstChildPos(opPos);
-    int whatToShow = compiler.getWhatToShow(firstStepPos);
-
-    if ((0 == (whatToShow
-               & (DTMFilter.SHOW_ATTRIBUTE 
-               | DTMFilter.SHOW_NAMESPACE 
-               | DTMFilter.SHOW_ELEMENT
-               | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) 
-               || (whatToShow == DTMFilter.SHOW_ALL))
-      initNodeTest(whatToShow);
-    else
-    {
-      initNodeTest(whatToShow, compiler.getStepNS(firstStepPos),
-                              compiler.getStepLocalName(firstStepPos));
-    }
-    initPredicateInfo(compiler, firstStepPos);
+    super(compiler, opPos, analysis);
   }
   
   /**
    * Create a ChildTestIterator object.
    *
-   * @param compiler A reference to the Compiler that contains the op map.
-   * @param opPos The position within the op map, which contains the
-   * location path expression for this itterator.
+   * @param traverser Traverser that tells how the KeyIterator is to be handled.
    *
    * @throws javax.xml.transform.TransformerException
    */
-  ChildTestIterator(DTMAxisTraverser traverser)
+  public ChildTestIterator(DTMAxisTraverser traverser)
   {
 
     super(null);
@@ -133,25 +113,6 @@
     m_traverser = traverser;
   }
 
-  
-  /**
-   *  Get a cloned Iterator that is reset to the beginning
-   *  of the query.
-   * 
-   *  @return A cloned NodeIterator set of the start of the query.
-   * 
-   *  @throws CloneNotSupportedException
-   */
-  public DTMIterator cloneWithReset() throws CloneNotSupportedException
-  {
-
-    ChildTestIterator clone = (ChildTestIterator) super.cloneWithReset();
-
-    clone.resetProximityPositions();
-
-    return clone;
-  }
-  
   /**
    * Get the next node via getNextXXX.  Bottlenecked for derived class override.
    * @return The next node on the axis, or DTM.NULL.
@@ -175,107 +136,25 @@
     return m_lastFetched;
   }
 
+  
   /**
-   *  Returns the next node in the set and advances the position of the
-   * iterator in the set. After a NodeIterator is created, the first call
-   * to nextNode() returns the first node in the set.
-   *
-   * @return  The next <code>Node</code> in the set being iterated over, or
-   *   <code>null</code> if there are no more members in that set.
+   *  Get a cloned Iterator that is reset to the beginning
+   *  of the query.
+   * 
+   *  @return A cloned NodeIterator set of the start of the query.
+   * 
+   *  @throws CloneNotSupportedException
    */
-  public int nextNode()
+  public DTMIterator cloneWithReset() throws CloneNotSupportedException
   {
 
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if ((null != m_cachedNodes)
-            && (m_next < m_cachedNodes.size()))
-    {
-      int next = m_cachedNodes.elementAt(m_next);
-    
-      incrementNextPosition();
-      m_currentContextNode = next;
+    ChildTestIterator clone = (ChildTestIterator) super.cloneWithReset();
+    clone.m_traverser = m_traverser;
 
-      return next;
-    }
-
-    if (m_foundLast)
-    {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
-    }
-      
-    if(DTM.NULL == m_lastFetched)
-    {
-      resetProximityPositions();
-    }
-
-    int next;
-    
-    org.apache.xpath.VariableStack vars;
-    int savedStart;
-    if (-1 != m_stackFrame)
-    {
-      vars = m_execContext.getVarStack();
-
-      // These three statements need to be combined into one operation.
-      savedStart = vars.getStackFrame();
-
-      vars.setStackFrame(m_stackFrame);
-    }
-    else
-    {
-      // Yuck.  Just to shut up the compiler!
-      vars = null;
-      savedStart = 0;
-    }
-    
-    try
-    {
-      do
-      {
-        next = getNextNode();
-  
-        if (DTM.NULL != next)
-        {
-          if(DTMIterator.FILTER_ACCEPT == acceptNode(next))
-            break;
-          else
-            continue;
-        }
-        else
-          break;
-      }
-      while (next != DTM.NULL);
-  
-      if (DTM.NULL != next)
-      {
-        if (null != m_cachedNodes)
-          m_cachedNodes.addElement(m_lastFetched);
-  
-        m_next++;
-  
-        return next;
-      }
-      else
-      {
-        m_foundLast = true;
-  
-        return DTM.NULL;
-      }
-    }
-    finally
-    {
-      if (-1 != m_stackFrame)
-      {
-        // These two statements need to be combined into one operation.
-        vars.setStackFrame(savedStart);
-      }
-    }
+    return clone;
   }
   
+
   /**
    * Initialize the context values for this expression
    * after it is cloned.
diff --git a/src/org/apache/xpath/axes/DescendantIterator.java b/src/org/apache/xpath/axes/DescendantIterator.java
index 656dc6c..b336033 100644
--- a/src/org/apache/xpath/axes/DescendantIterator.java
+++ b/src/org/apache/xpath/axes/DescendantIterator.java
@@ -57,18 +57,17 @@
 package org.apache.xpath.axes;
 
 import javax.xml.transform.TransformerException;
-
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.patterns.NodeTest;
-import org.apache.xpath.objects.XObject;
-import org.apache.xpath.compiler.OpCodes;
-import org.apache.xpath.XPathContext;
-
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.DTMAxisTraverser;
 import org.apache.xml.dtm.Axis;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMAxisTraverser;
+import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xpath.Expression;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.compiler.Compiler;
+import org.apache.xpath.compiler.OpCodes;
+import org.apache.xpath.patterns.NodeTest;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -193,6 +192,7 @@
   {
 
     DescendantIterator clone = (DescendantIterator) super.cloneWithReset();
+    clone.m_traverser = m_traverser;
 
     clone.resetProximityPositions();
 
@@ -213,27 +213,9 @@
    */
   public int nextNode()
   {
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if ((null != m_cachedNodes)
-            && (m_next < m_cachedNodes.size()))
-    {
-      int next = m_cachedNodes.elementAt(m_next);
-    
-      incrementNextPosition();
-      m_currentContextNode = next;
+   	if(m_foundLast)
+  		return DTM.NULL;
 
-      return next;
-    }
-
-    if (m_foundLast)
-    {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
-    }
-      
     if(DTM.NULL == m_lastFetched)
     {
       resetProximityPositions();
@@ -291,11 +273,7 @@
   
       if (DTM.NULL != next)
       {
-        if (null != m_cachedNodes)
-          m_cachedNodes.addElement(m_lastFetched);
-  
-        m_next++;
-  
+      	m_pos++;
         return next;
       }
       else
@@ -413,7 +391,7 @@
   {
     return m_axis;
   }
-
+  
   
   /** The traverser to use to navigate over the descendants. */
   transient protected DTMAxisTraverser m_traverser;
@@ -424,4 +402,19 @@
   /** The extended type ID, not set until setRoot. */
   protected int m_extendedTypeID;
   
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	if(m_axis != ((DescendantIterator)expr).m_axis)
+  		return false;
+  		
+  	return true;
+  }
+
+  
 }
diff --git a/src/org/apache/xpath/axes/FilterExprIterator.java b/src/org/apache/xpath/axes/FilterExprIterator.java
new file mode 100644
index 0000000..eaca9e4
--- /dev/null
+++ b/src/org/apache/xpath/axes/FilterExprIterator.java
@@ -0,0 +1,203 @@
+package org.apache.xpath.axes;
+
+import java.util.Vector;
+
+import org.apache.xml.dtm.DTM;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.XNodeSet;
+
+public class FilterExprIterator extends BasicTestIterator
+{
+  /** The contained expression. Should be non-null.
+   *  @serial   */
+  private Expression m_expr;
+
+  /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
+  transient private XNodeSet m_exprObj;
+
+  private boolean m_mustHardReset = false;
+  private boolean m_canDetachNodeset = true;
+
+  /**
+   * Create a ChildTestIterator object.
+   *
+   * @param traverser Traverser that tells how the KeyIterator is to be handled.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public FilterExprIterator()
+  {
+    super(null);
+  }
+  
+  /**
+   * Create a ChildTestIterator object.
+   *
+   * @param traverser Traverser that tells how the KeyIterator is to be handled.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public FilterExprIterator(Expression expr)
+  {
+    super(null);
+    m_expr = expr;
+  }
+
+  /**
+   * Initialize the context values for this expression
+   * after it is cloned.
+   *
+   * @param execContext The XPath runtime context for this
+   * transformation.
+   */
+  public void setRoot(int context, Object environment)
+  {
+  	super.setRoot(context, environment);
+ 	
+  	m_exprObj = FilterExprIteratorSimple.executeFilterExpr(context, 
+  	                  m_execContext, getPrefixResolver(), 
+  	                  getIsTopLevel(), m_stackFrame, m_expr);
+   }
+
+
+  /**
+   * Get the next node via getNextXXX.  Bottlenecked for derived class override.
+   * @return The next node on the axis, or DTM.NULL.
+   */
+  protected int getNextNode()
+  {
+    if (null != m_exprObj)
+    {
+      m_lastFetched = m_exprObj.nextNode();
+    }
+    else
+      m_lastFetched = DTM.NULL;
+
+    return m_lastFetched;
+  }
+  
+  /**
+   * Detaches the walker from the set which it iterated over, releasing
+   * any computational resources and placing the iterator in the INVALID
+   * state.
+   */
+  public void detach()
+  {  
+  	super.detach();
+  	m_exprObj.detach();
+  	m_exprObj = null;
+  }
+
+  /**
+   * This function is used to fixup variables from QNames to stack frame 
+   * indexes at stylesheet build time.
+   * @param vars List of QNames that correspond to variables.  This list 
+   * should be searched backwards for the first qualified name that 
+   * corresponds to the variable reference qname.  The position of the 
+   * QName in the vector from the start of the vector will be its position 
+   * in the stack frame (but variables above the globalsTop value will need 
+   * to be offset to the current stack frame).
+   */
+  public void fixupVariables(java.util.Vector vars, int globalsSize)
+  {
+    super.fixupVariables(vars, globalsSize);
+    m_expr.fixupVariables(vars, globalsSize);
+  }
+
+  /**
+   * Get the inner contained expression of this filter.
+   */
+  public Expression getInnerExpression()
+  {
+    return m_expr;
+  }
+
+  /**
+   * Set the inner contained expression of this filter.
+   */
+  public void setInnerExpression(Expression expr)
+  {
+    expr.exprSetParent(this);
+    m_expr = expr;
+  }
+
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+    if (null != m_expr && m_expr instanceof PathComponent)
+    {
+      return ((PathComponent) m_expr).getAnalysisBits();
+    }
+    return WalkerFactory.BIT_FILTER;
+  }
+
+  /**
+   * Returns true if all the nodes in the iteration well be returned in document 
+   * order.
+   * Warning: This can only be called after setRoot has been called!
+   * 
+   * @return true as a default.
+   */
+  public boolean isDocOrdered()
+  {
+    return m_exprObj.isDocOrdered();
+  }
+
+  class filterExprOwner implements ExpressionOwner
+  {
+    /**
+    * @see ExpressionOwner#getExpression()
+    */
+    public Expression getExpression()
+    {
+      return m_expr;
+    }
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+      exp.exprSetParent(FilterExprIterator.this);
+      m_expr = exp;
+    }
+
+  }
+
+  /**
+   * This will traverse the heararchy, calling the visitor for 
+   * each member.  If the called visitor method returns 
+   * false, the subtree should not be called.
+   * 
+   * @param owner The owner of the visitor, where that path may be 
+   *              rewritten if needed.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  public void callPredicateVisitors(XPathVisitor visitor)
+  {
+    m_expr.callVisitors(new filterExprOwner(), visitor);
+
+    super.callPredicateVisitors(visitor);
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+    if (!super.deepEquals(expr))
+      return false;
+
+    FilterExprIterator fet = (FilterExprIterator) expr;
+    if (!m_expr.deepEquals(fet.m_expr))
+      return false;
+
+    return true;
+  }
+
+}
\ No newline at end of file
diff --git a/src/org/apache/xpath/axes/FilterExprIteratorSimple.java b/src/org/apache/xpath/axes/FilterExprIteratorSimple.java
new file mode 100644
index 0000000..55c7b87
--- /dev/null
+++ b/src/org/apache/xpath/axes/FilterExprIteratorSimple.java
@@ -0,0 +1,305 @@
+package org.apache.xpath.axes;
+
+import java.util.Vector;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.Axis;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.XNodeSet;
+
+/**
+ * Class to use for one-step iteration that doesn't have a predicate, and 
+ * doesn't need to set the context.
+ */
+public class FilterExprIteratorSimple extends LocPathIterator
+{
+  /** The contained expression. Should be non-null.
+   *  @serial   */
+  private Expression m_expr;
+
+  /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
+  transient private XNodeSet m_exprObj;
+
+  private boolean m_mustHardReset = false;
+  private boolean m_canDetachNodeset = true;
+
+  /**
+   * Create a ChildTestIterator object.
+   *
+   * @param traverser Traverser that tells how the KeyIterator is to be handled.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public FilterExprIteratorSimple()
+  {
+    super(null);
+  }
+  
+  /**
+   * Create a ChildTestIterator object.
+   *
+   * @param traverser Traverser that tells how the KeyIterator is to be handled.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public FilterExprIteratorSimple(Expression expr)
+  {
+    super(null);
+    m_expr = expr;
+  }
+  
+  /**
+   * Initialize the context values for this expression
+   * after it is cloned.
+   *
+   * @param execContext The XPath runtime context for this
+   * transformation.
+   */
+  public void setRoot(int context, Object environment)
+  {
+  	super.setRoot(context, environment);
+  	m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(), 
+  	                  getIsTopLevel(), m_stackFrame, m_expr);
+  }
+
+  /**
+   * Execute the expression.  Meant for reuse by other FilterExpr iterators 
+   * that are not derived from this object.
+   */
+  public static XNodeSet executeFilterExpr(int context, XPathContext xctxt, 
+  												PrefixResolver prefixResolver,
+  												boolean isTopLevel,
+  												int stackFrame,
+  												Expression expr )
+    throws org.apache.xml.utils.WrappedRuntimeException
+  {
+    PrefixResolver savedResolver = xctxt.getNamespaceContext();
+    XNodeSet result = null;
+
+    try
+    {
+      xctxt.pushCurrentNode(context);
+      xctxt.setNamespaceContext(prefixResolver);
+
+      // The setRoot operation can take place with a reset operation, 
+      // and so we may not be in the context of LocPathIterator#nextNode, 
+      // so we have to set up the variable context, execute the expression, 
+      // and then restore the variable context.
+
+      if (isTopLevel)
+      {
+        // System.out.println("calling m_expr.execute(getXPathContext())");
+        VariableStack vars = xctxt.getVarStack();
+
+        // These three statements need to be combined into one operation.
+        int savedStart = vars.getStackFrame();
+        vars.setStackFrame(stackFrame);
+
+        result = (org.apache.xpath.objects.XNodeSet) expr.execute(xctxt);
+        result.setShouldCacheNodes(true);
+
+        // These two statements need to be combined into one operation.
+        vars.setStackFrame(savedStart);
+      }
+      else
+          result = (org.apache.xpath.objects.XNodeSet) expr.execute(xctxt);
+
+    }
+    catch (javax.xml.transform.TransformerException se)
+    {
+
+      // TODO: Fix...
+      throw new org.apache.xml.utils.WrappedRuntimeException(se);
+    }
+    finally
+    {
+      xctxt.popCurrentNode();
+      xctxt.setNamespaceContext(savedResolver);
+    }
+    return result;
+  }
+  
+  /**
+   *  Returns the next node in the set and advances the position of the
+   * iterator in the set. After a NodeIterator is created, the first call
+   * to nextNode() returns the first node in the set.
+   *
+   * @return  The next <code>Node</code> in the set being iterated over, or
+   *   <code>null</code> if there are no more members in that set.
+   */
+  public int nextNode()
+  {
+  	if(m_foundLast)
+  		return DTM.NULL;
+
+    int next;
+
+    if (null != m_exprObj)
+    {
+      m_lastFetched = next = m_exprObj.nextNode();
+    }
+    else
+      m_lastFetched = next = DTM.NULL;
+
+    // m_lastFetched = next;
+    if (DTM.NULL != next)
+    {
+      m_pos++;
+      return next;
+    }
+    else
+    {
+      m_foundLast = true;
+
+      return DTM.NULL;
+    }
+  }
+  
+  /**
+   * Detaches the walker from the set which it iterated over, releasing
+   * any computational resources and placing the iterator in the INVALID
+   * state.
+   */
+  public void detach()
+  {  
+    if(m_allowDetach)
+    {
+  		super.detach();
+  		m_exprObj.detach();
+  		m_exprObj = null;
+    }
+  }
+
+  /**
+   * This function is used to fixup variables from QNames to stack frame 
+   * indexes at stylesheet build time.
+   * @param vars List of QNames that correspond to variables.  This list 
+   * should be searched backwards for the first qualified name that 
+   * corresponds to the variable reference qname.  The position of the 
+   * QName in the vector from the start of the vector will be its position 
+   * in the stack frame (but variables above the globalsTop value will need 
+   * to be offset to the current stack frame).
+   */
+  public void fixupVariables(java.util.Vector vars, int globalsSize)
+  {
+    super.fixupVariables(vars, globalsSize);
+    m_expr.fixupVariables(vars, globalsSize);
+  }
+
+  /**
+   * Get the inner contained expression of this filter.
+   */
+  public Expression getInnerExpression()
+  {
+    return m_expr;
+  }
+
+  /**
+   * Set the inner contained expression of this filter.
+   */
+  public void setInnerExpression(Expression expr)
+  {
+    expr.exprSetParent(this);
+    m_expr = expr;
+  }
+
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+    if (null != m_expr && m_expr instanceof PathComponent)
+    {
+      return ((PathComponent) m_expr).getAnalysisBits();
+    }
+    return WalkerFactory.BIT_FILTER;
+  }
+
+  /**
+   * Returns true if all the nodes in the iteration well be returned in document 
+   * order.
+   * Warning: This can only be called after setRoot has been called!
+   * 
+   * @return true as a default.
+   */
+  public boolean isDocOrdered()
+  {
+    return m_exprObj.isDocOrdered();
+  }
+
+  class filterExprOwner implements ExpressionOwner
+  {
+    /**
+    * @see ExpressionOwner#getExpression()
+    */
+    public Expression getExpression()
+    {
+      return m_expr;
+    }
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+      exp.exprSetParent(FilterExprIteratorSimple.this);
+      m_expr = exp;
+    }
+
+  }
+
+  /**
+   * This will traverse the heararchy, calling the visitor for 
+   * each member.  If the called visitor method returns 
+   * false, the subtree should not be called.
+   * 
+   * @param owner The owner of the visitor, where that path may be 
+   *              rewritten if needed.
+   * @param visitor The visitor whose appropriate method will be called.
+   */
+  public void callPredicateVisitors(XPathVisitor visitor)
+  {
+    m_expr.callVisitors(new filterExprOwner(), visitor);
+
+    super.callPredicateVisitors(visitor);
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+    if (!super.deepEquals(expr))
+      return false;
+
+    FilterExprIteratorSimple fet = (FilterExprIteratorSimple) expr;
+    if (!m_expr.deepEquals(fet.m_expr))
+      return false;
+
+    return true;
+  }
+  
+  /**
+   * Returns the axis being iterated, if it is known.
+   * 
+   * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple 
+   * types.
+   */
+  public int getAxis()
+  {
+  	if(null != m_exprObj)
+    	return m_exprObj.getAxis();
+    else
+    	return Axis.FILTEREDLIST;
+  }
+
+
+}
+
diff --git a/src/org/apache/xpath/axes/FilterExprWalker.java b/src/org/apache/xpath/axes/FilterExprWalker.java
index 167335b..3af0a17 100644
--- a/src/org/apache/xpath/axes/FilterExprWalker.java
+++ b/src/org/apache/xpath/axes/FilterExprWalker.java
@@ -56,23 +56,22 @@
  */
 package org.apache.xpath.axes;
 
-import org.apache.xpath.axes.LocPathIterator;
-import org.apache.xpath.XPath;
-import org.apache.xpath.Expression;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.VariableStack;
-import org.apache.xpath.objects.XObject;
-import org.apache.xml.utils.PrefixResolver;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.compiler.OpCodes;
-import org.apache.xpath.patterns.NodeTestFilter;
-
 import java.util.Vector;
 
+import javax.xml.transform.TransformerException;
+import org.apache.xalan.templates.FuncKey;
+import org.apache.xml.dtm.Axis;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.Axis;
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.compiler.Compiler;
+import org.apache.xpath.compiler.OpCodes;
+import org.apache.xpath.objects.XNodeSet;
 
 /**
  * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP,
@@ -87,7 +86,7 @@
    *
    * @param locPathIterator non-null reference to the parent iterator.
    */
-  FilterExprWalker(WalkingIterator locPathIterator)
+  public FilterExprWalker(WalkingIterator locPathIterator)
   {
     super(locPathIterator, Axis.FILTEREDLIST);
   }
@@ -110,15 +109,49 @@
     // Smooth over an anomily in the opcode map...
     switch (stepType)
     {
-    case OpCodes.OP_VARIABLE :
-    case OpCodes.OP_EXTFUNCTION :
     case OpCodes.OP_FUNCTION :
+    case OpCodes.OP_EXTFUNCTION :
+    	m_mustHardReset = true;
     case OpCodes.OP_GROUP :
+    case OpCodes.OP_VARIABLE :
       m_expr = compiler.compile(opPos);
+      m_expr.exprSetParent(this);
+      if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof org.apache.xalan.templates.FuncKey))
+      {
+      	// hack/temp workaround
+      	m_canDetachNodeset = false;
+      }
       break;
     default :
       m_expr = compiler.compile(opPos + 2);
+      m_expr.exprSetParent(this);
     }
+//    if(m_expr instanceof WalkingIterator)
+//    {
+//      WalkingIterator wi = (WalkingIterator)m_expr;
+//      if(wi.getFirstWalker() instanceof FilterExprWalker)
+//      {
+//      	FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker();
+//      	if(null == fw.getNextWalker())
+//      	{
+//      		m_expr = fw.m_expr;
+//      		m_expr.exprSetParent(this);
+//      	}
+//      }
+//      		
+//    }
+  }
+  
+  /**
+   * Detaches the walker from the set which it iterated over, releasing
+   * any computational resources and placing the iterator in the INVALID
+   * state.
+   */
+  public void detach()
+  {  
+  	super.detach();
+  	m_exprObj.detach();
+  	m_exprObj = null;
   }
 
   /**
@@ -130,51 +163,12 @@
   public void setRoot(int root)
   {
 
-    // System.out.println("root: "+root);
-    XPathContext xctxt = m_lpi.getXPathContext();
-    PrefixResolver savedResolver = xctxt.getNamespaceContext();
-
-    try
-    {
-      xctxt.pushCurrentNode(root);
-      xctxt.setNamespaceContext(m_lpi.getPrefixResolver());
-      
-      // The setRoot operation can take place with a reset operation, 
-      // and so we may not be in the context of LocPathIterator#nextNode, 
-      // so we have to set up the variable context, execute the expression, 
-      // and then restore the variable context.
-
-      if(m_lpi.getIsTopLevel())
-      {
-        // System.out.println("calling m_expr.execute(m_lpi.getXPathContext())");
-        VariableStack vars = m_lpi.m_execContext.getVarStack();
-        
-        // These three statements need to be combined into one operation.
-        int savedStart = vars.getStackFrame();
-        vars.setStackFrame(m_lpi.m_stackFrame);
-        
-        m_nodeSet = m_expr.asIterator(xctxt, root);
-        
-        // These two statements need to be combined into one operation.
-        vars.setStackFrame(savedStart);
-      }
-      else
-        m_nodeSet = m_expr.asIterator(xctxt, root);
-            
-    }
-    catch (javax.xml.transform.TransformerException se)
-    {
-
-      // TODO: Fix...
-      throw new org.apache.xml.utils.WrappedRuntimeException(se);
-    }
-    finally
-    {
-      xctxt.popCurrentNode();
-      xctxt.setNamespaceContext(savedResolver);
-    }
-
     super.setRoot(root);
+
+  	m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root, 
+  	                  m_lpi.getXPathContext(), m_lpi.getPrefixResolver(), 
+  	                  m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr);
+
   }
 
   /**
@@ -190,12 +184,12 @@
     FilterExprWalker clone = (FilterExprWalker) super.clone();
 
     // clone.m_expr = (Expression)((Expression)m_expr).clone();
-    if (null != m_nodeSet)
-      clone.m_nodeSet = (DTMIterator) m_nodeSet.clone();
+    if (null != m_exprObj)
+      clone.m_exprObj = (XNodeSet) m_exprObj.clone();
 
     return clone;
   }
-
+  
   /**
    * This method needs to override AxesWalker.acceptNode because FilterExprWalkers
    * don't need to, and shouldn't, do a node test.
@@ -236,8 +230,11 @@
   public int getNextNode()
   {
 
-    if (null != m_nodeSet)
-       return m_nodeSet.nextNode();
+    if (null != m_exprObj)
+    {
+       int next = m_exprObj.nextNode();
+       return next;
+    }
     else
       return DTM.NULL;
   }
@@ -252,7 +249,7 @@
    */
   public int getLastPos(XPathContext xctxt)
   {
-    return m_nodeSet.getLength();
+    return m_exprObj.getLength();
   }
   
   /** The contained expression. Should be non-null.
@@ -260,7 +257,10 @@
   private Expression m_expr;
 
   /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
-  transient private DTMIterator m_nodeSet;
+  transient private XNodeSet m_exprObj;
+  
+  private boolean m_mustHardReset = false;
+  private boolean m_canDetachNodeset = true;
 
   /**
    * This function is used to fixup variables from QNames to stack frame 
@@ -279,6 +279,37 @@
   }
   
   /**
+   * Get the inner contained expression of this filter.
+   */
+  public Expression getInnerExpression()
+  {
+  	return m_expr;
+  }
+  
+  /**
+   * Set the inner contained expression of this filter.
+   */
+  public void setInnerExpression(Expression expr)
+  {
+  	expr.exprSetParent(this);
+  	m_expr = expr;
+  }
+
+  
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+      if (null != m_expr && m_expr instanceof PathComponent)
+      {
+        return ((PathComponent) m_expr).getAnalysisBits();
+      }
+      return WalkerFactory.BIT_FILTER;
+  }
+  
+  /**
    * Returns true if all the nodes in the iteration well be returned in document 
    * order.
    * Warning: This can only be called after setRoot has been called!
@@ -287,7 +318,7 @@
    */
   public boolean isDocOrdered()
   {
-    return m_nodeSet.isDocOrdered();
+    return m_exprObj.isDocOrdered();
   }
   
   /**
@@ -298,9 +329,61 @@
    */
   public int getAxis()
   {
-    return m_nodeSet.getAxis();
+    return m_exprObj.getAxis();
   }
+  
+  class filterExprOwner implements ExpressionOwner
+  {
+      /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_expr;
+    }
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(FilterExprWalker.this);
+    	m_expr = exp;
+    }
+  }
+  
+	/**
+	 * This will traverse the heararchy, calling the visitor for 
+	 * each member.  If the called visitor method returns 
+	 * false, the subtree should not be called.
+	 * 
+	 * @param owner The owner of the visitor, where that path may be 
+	 *              rewritten if needed.
+	 * @param visitor The visitor whose appropriate method will be called.
+	 */
+	public void callPredicateVisitors(XPathVisitor visitor)
+	{
+	  m_expr.callVisitors(new filterExprOwner(), visitor);
+	  
+	  super.callPredicateVisitors(visitor);
+	} 
 
 
+    /**
+     * @see Expression#deepEquals(Expression)
+     */
+    public boolean deepEquals(Expression expr)
+    {
+      if (!super.deepEquals(expr))
+                return false;
+
+      FilterExprWalker walker = (FilterExprWalker)expr;
+      if(!m_expr.deepEquals(walker.m_expr))
+      	return false;
+
+      return true;
+    }
+
+	
 
 }
diff --git a/src/org/apache/xpath/axes/HasPositionalPredChecker.java b/src/org/apache/xpath/axes/HasPositionalPredChecker.java
new file mode 100644
index 0000000..37570d6
--- /dev/null
+++ b/src/org/apache/xpath/axes/HasPositionalPredChecker.java
@@ -0,0 +1,104 @@
+package org.apache.xpath.axes;
+
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.functions.FuncLast;
+import org.apache.xpath.functions.FuncPosition;
+import org.apache.xpath.functions.Function;
+import org.apache.xpath.objects.XNumber;
+import org.apache.xpath.operations.Div;
+import org.apache.xpath.operations.Minus;
+import org.apache.xpath.operations.Mod;
+import org.apache.xpath.operations.Mult;
+import org.apache.xpath.operations.Plus;
+import org.apache.xpath.operations.Quo;
+import org.apache.xpath.operations.Variable;
+
+public class HasPositionalPredChecker extends XPathVisitor
+{
+	private boolean m_hasPositionalPred = false;
+	private int m_predDepth = 0;
+	
+	/**
+	 * Process the LocPathIterator to see if it contains variables 
+	 * or functions that may make it context dependent.
+	 * @param path LocPathIterator that is assumed to be absolute, but needs checking.
+	 * @return true if the path is confirmed to be absolute, false if it 
+	 * may contain context dependencies.
+	 */
+	public static boolean check(LocPathIterator path)
+	{
+		HasPositionalPredChecker hppc = new HasPositionalPredChecker();
+		path.callVisitors(null, hppc);
+		return hppc.m_hasPositionalPred;
+	}
+	
+	/**
+	 * Visit a function.
+	 * @param owner The owner of the expression, to which the expression can 
+	 *              be reset if rewriting takes place.
+	 * @param func The function reference object.
+	 * @return true if the sub expressions should be traversed.
+	 */
+	public boolean visitFunction(ExpressionOwner owner, Function func)
+	{
+		if((func instanceof FuncPosition) ||
+		   (func instanceof FuncLast))
+			m_hasPositionalPred = true;
+		return true;
+	}
+	
+//	/**
+//	 * Visit a variable reference.
+//	 * @param owner The owner of the expression, to which the expression can 
+//	 *              be reset if rewriting takes place.
+//	 * @param var The variable reference object.
+//	 * @return true if the sub expressions should be traversed.
+//	 */
+//	public boolean visitVariableRef(ExpressionOwner owner, Variable var)
+//	{
+//		m_hasPositionalPred = true;
+//		return true;
+//	}
+	
+  /**
+   * Visit a predicate within a location path.  Note that there isn't a 
+   * proper unique component for predicates, and that the expression will 
+   * be called also for whatever type Expression is.
+   * 
+   * @param owner The owner of the expression, to which the expression can 
+   *              be reset if rewriting takes place.
+   * @param pred The predicate object.
+   * @return true if the sub expressions should be traversed.
+   */
+  public boolean visitPredicate(ExpressionOwner owner, Expression pred)
+  {
+    m_predDepth++;
+
+    if(m_predDepth == 1)
+    {
+      if((pred instanceof Variable) || 
+         (pred instanceof XNumber) ||
+         (pred instanceof Div) ||
+         (pred instanceof Plus) ||
+         (pred instanceof Minus) ||
+         (pred instanceof Mod) ||
+         (pred instanceof Quo) ||
+         (pred instanceof Mult) ||
+         (pred instanceof org.apache.xpath.operations.Number) ||
+         (pred instanceof Function))
+          m_hasPositionalPred = true;
+      else
+      	pred.callVisitors(owner, this);
+    }
+
+    m_predDepth--;
+
+    // Don't go have the caller go any further down the subtree.
+    return false;
+  }
+
+
+}
+
diff --git a/src/org/apache/xpath/axes/IteratorPool.java b/src/org/apache/xpath/axes/IteratorPool.java
index c4a75ac..7c40646 100644
--- a/src/org/apache/xpath/axes/IteratorPool.java
+++ b/src/org/apache/xpath/axes/IteratorPool.java
@@ -35,9 +35,34 @@
    *
    * @return An instance of the given object
    */
+  public synchronized DTMIterator getInstanceOrThrow()
+    throws CloneNotSupportedException
+  {
+    // Check if the pool is empty.
+    if (m_freeStack.isEmpty())
+    {
+
+      // Create a new object if so.
+      return (DTMIterator)m_orig.clone();
+    }
+    else
+    {
+      // Remove object from end of free pool.
+      DTMIterator result = (DTMIterator)m_freeStack.lastElement();
+
+      m_freeStack.setSize(m_freeStack.size() - 1);
+
+      return result;
+    }
+  }
+  
+  /**
+   * Get an instance of the given object in this pool 
+   *
+   * @return An instance of the given object
+   */
   public synchronized DTMIterator getInstance()
   {
-
     // Check if the pool is empty.
     if (m_freeStack.isEmpty())
     {
diff --git a/src/org/apache/xpath/axes/LocPathIterator.java b/src/org/apache/xpath/axes/LocPathIterator.java
index 2cbfeee..64b9710 100644
--- a/src/org/apache/xpath/axes/LocPathIterator.java
+++ b/src/org/apache/xpath/axes/LocPathIterator.java
@@ -57,31 +57,24 @@
 package org.apache.xpath.axes;
 
 // Java library imports
-import java.util.Vector;
-import java.util.Stack;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
 
+import javax.xml.transform.TransformerException;
 import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
 import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.dtm.DTMIterator;
 import org.apache.xml.dtm.DTMManager;
-
-// Xalan imports
-import org.apache.xpath.res.XPATHErrorResources;
-import org.apache.xpath.XPath;
-import org.apache.xpath.compiler.OpMap;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.compiler.OpCodes;
-import org.apache.xpath.compiler.PsuedoNames;
-import org.apache.xpath.NodeSetDTM;
-import org.apache.xpath.Expression;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
-import org.apache.xml.utils.IntStack;
 import org.apache.xml.utils.PrefixResolver;
-import org.apache.xml.utils.ObjectPool;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.compiler.Compiler;
 import org.apache.xpath.objects.XNodeSet;
-import org.apache.xpath.axes.AxesWalker;
-import org.apache.xpath.VariableStack;
+import org.apache.xpath.objects.XObject;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -96,8 +89,19 @@
  * in which case the UnionPathIterator will cache the nodes.</p>
  */
 public abstract class LocPathIterator extends PredicatedNodeTest
-        implements Cloneable, DTMIterator, java.io.Serializable
+        implements Cloneable, DTMIterator, java.io.Serializable, PathComponent
 {
+	
+  /**
+   * Create a LocPathIterator object.
+   *
+   * @param nscontext The namespace context for this iterator,
+   * should be OK if null.
+   */
+  protected LocPathIterator()
+  {
+  }
+
 
   /**
    * Create a LocPathIterator object.
@@ -109,8 +113,7 @@
   {
 
     setLocPathIterator(this);
-
-    this.m_prefixResolver = nscontext;
+    m_prefixResolver = nscontext;
   }
 
   /**
@@ -153,6 +156,17 @@
     setLocPathIterator(this);
   }
   
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+  	int axis = getAxis();
+  	int bit = WalkerFactory.getAnalysisBitFromAxes(axis);
+  	return bit;
+  }
+  
   /**
    * Read the object from a serialization stream.
    *
@@ -219,7 +233,7 @@
   {
     return m_execContext.getDTMManager();
   }
-
+  
   /**
    * Execute this iterator, meaning create a clone that can
    * store state, and initialize it for fast execution from
@@ -236,12 +250,45 @@
           throws javax.xml.transform.TransformerException
   {
 
+    XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance());
+
+    iter.setRoot(xctxt.getCurrentNode(), xctxt);
+
+    return iter;
+  }
+    
+  /**
+   * Execute an expression in the XPath runtime context, and return the
+   * result of the expression.
+   *
+   *
+   * @param xctxt The XPath runtime context.
+   * @param handler The target content handler.
+   *
+   * @return The result of the expression in the form of a <code>XObject</code>.
+   *
+   * @throws javax.xml.transform.TransformerException if a runtime exception
+   *         occurs.
+   * @throws org.xml.sax.SAXException
+   */
+  public void executeCharsToContentHandler(
+          XPathContext xctxt, org.xml.sax.ContentHandler handler)
+            throws javax.xml.transform.TransformerException,
+                   org.xml.sax.SAXException
+  {
     LocPathIterator clone = (LocPathIterator)m_clones.getInstance();
 
     int current = xctxt.getCurrentNode();
     clone.setRoot(current, xctxt);
-
-    return new XNodeSet(clone);
+    
+    int node = clone.nextNode();
+    DTM dtm = clone.getDTM(node);
+    clone.detach();
+	
+    if(node != DTM.NULL)
+    {
+      dtm.dispatchCharactersEvents(node, handler, false);
+    }
   }
   
   /**
@@ -263,9 +310,11 @@
           XPathContext xctxt, int contextNode)
             throws javax.xml.transform.TransformerException
   {
-    LocPathIterator clone = (LocPathIterator)m_clones.getInstance();
-    clone.setRoot(contextNode, xctxt);
-    return clone;
+    XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance());
+
+    iter.setRoot(contextNode, xctxt);
+
+    return iter;
   }
 
   
@@ -291,7 +340,7 @@
     throws javax.xml.transform.TransformerException
   {
     DTMIterator iter = (DTMIterator)m_clones.getInstance();
-
+    
     int current = xctxt.getCurrentNode();
     
     iter.setRoot(current, xctxt);
@@ -355,22 +404,26 @@
   {
 
     m_context = context;
+    
     XPathContext xctxt = (XPathContext)environment;
     m_execContext = xctxt;
     m_cdtm = xctxt.getDTM(context);
-    m_currentContextNode = context;
-    m_prefixResolver = xctxt.getNamespaceContext();
+    
+    m_currentContextNode = context; // only if top level?
+    
+    // Yech, shouldn't have to do this.  -sb
+    if(null == m_prefixResolver)
+    	m_prefixResolver = xctxt.getNamespaceContext();
         
-//    m_lastFetched = DTM.NULL;
-//    m_currentContextNode = DTM.NULL;
-//    m_foundLast = false;
-//    m_last = 0;
-//    m_next = 0;
+    m_lastFetched = DTM.NULL;
+    m_foundLast = false;
+    m_pos = 0;
+    m_length = -1;
 
     if (m_isTopLevel)
       this.m_stackFrame = xctxt.getVarStack().getStackFrame();
       
-    reset();
+    // reset();
   }
 
   /**
@@ -381,7 +434,7 @@
    */
   protected void setNextPosition(int next)
   {
-    m_next = next;
+    assertion(false, "setNextPosition not supported in this iterator!");
   }
 
   /**
@@ -395,16 +448,9 @@
    */
   public final int getCurrentPos()
   {
-    return m_next;
+    return m_pos;
   }
 
-  /**
-   * Add one to the current node index.
-   */
-  void incrementNextPosition()
-  {
-    m_next++;
-  }
 
   /**
    * If setShouldCacheNodes(true) is called, then nodes will
@@ -415,15 +461,7 @@
   public void setShouldCacheNodes(boolean b)
   {
 
-    if (b)
-    {
-      if(null == m_cachedNodes)
-      {
-        m_cachedNodes = new NodeSetDTM(getDTMManager());
-      }
-    }
-    else
-      m_cachedNodes = null;
+    assertion(false, "setShouldCacheNodes not supported by this iterater!");
   }
   
   /**
@@ -434,18 +472,7 @@
    */
   public boolean isMutable()
   {
-    return (m_cachedNodes != null);
-  }
-
-
-  /**
-   * Get cached nodes.
-   *
-   * @return Cached nodes.
-   */
-  public NodeSetDTM getCachedNodes()
-  {
-    return m_cachedNodes;
+    return false;
   }
 
   /**
@@ -456,17 +483,17 @@
    */
   public void setCurrentPos(int i)
   {
-
-    // System.out.println("setCurrentPos: "+i);
-    if (null == m_cachedNodes)
-      throw new RuntimeException(
-        "This NodeSetDTM can not do indexing or counting functions!");
-
-    setNextPosition(i);
-    m_cachedNodes.setCurrentPos(i);
-
-    // throw new RuntimeException("Who's resetting this thing?");
+  	assertion(false, "setCurrentPos not supported by this iterator!");
   }
+  
+  /**
+   * Increment the current position in the node set.
+   */
+  public void incrementCurrentPos()
+  {
+  	m_pos++;
+  }
+
 
   /**
    * Get the length of the cached nodes.
@@ -480,11 +507,8 @@
    */
   public int size()
   {
-
-    if (null == m_cachedNodes)
-      return 0;
-
-    return m_cachedNodes.size();
+	assertion(false, "size() not supported by this iterator!");
+	return 0;
   }
 
   /**
@@ -498,10 +522,8 @@
    */
   public int item(int index)
   {
-
-    // resetToCachedList();
-
-    return m_cachedNodes.item(index);
+	assertion(false, "item(int index) not supported by this iterator!");
+	return 0;
   }
   
   /**
@@ -519,7 +541,7 @@
    */
   public void setItem(int node, int index)
   {
-    m_cachedNodes.setElementAt(node, index);
+	assertion(false, "setItem not supported by this iterator!");
   }
 
   /**
@@ -529,36 +551,49 @@
    * @return The number of nodes in the list, always greater or equal to zero.
    */
   public int getLength()
-  {
+  {      
+  	boolean isPredicateTest = (this == m_execContext.getSubContextList());
+  	int predCount = getPredicateCount();
+  	
+  	if(-1 != m_length && !isPredicateTest)
+  		return m_length;
+  	
+  	if(m_foundLast)
+  		return m_pos;
+  		
+    int pos = (m_predicateIndex >= 0) ? getProximityPosition() : m_pos;
+              
+    LocPathIterator clone;
 
-    // resetToCachedList();
-    if(m_last > 0)
-      return m_last;
-    else if(null == m_cachedNodes || !m_foundLast)
+    try
     {
-      m_last = findLastPos(m_execContext);
+      clone = (LocPathIterator) clone();        
     }
-    else
+    catch (CloneNotSupportedException cnse)
     {
-      m_last = m_cachedNodes.getLength();
+      return -1;
     }
-    return m_last;
-  }
 
-  /**
-   * In order to implement NodeList (for extensions), try to reset
-   * to a cached list for random access.
-   */
-  private void resetToCachedList()
-  {
-    // %REVIEW% ? This doesn't seem to work so well...
-    int pos = this.getCurrentPos();
+    // We want to clip off the last predicate, but only if we are a sub 
+    // context node list, NOT if we are a context list.  See pos68 test, 
+    // also test against bug4638.
+    if(predCount > 0 && isPredicateTest)
+    {
+      // Don't call setPredicateCount, because it clones and is slower.
+      clone.m_predCount = predCount - 1;
+    }
 
-    if ((null == m_cachedNodes) || (pos != 0))
-      this.setShouldCacheNodes(true);
+    int next;
 
-    runTo(-1);
-    this.setCurrentPos(pos);
+    while (DTM.NULL != (next = clone.nextNode()))
+    {
+      pos++;
+    }
+    
+    if(!isPredicateTest)
+      m_length = pos;
+    
+    return pos;
   }
 
   /**
@@ -570,7 +605,7 @@
    */
   public boolean isFresh()
   {
-    return (m_next == 0);
+    return (m_pos == 0);
   }
 
   /**
@@ -581,12 +616,8 @@
    */
   public int previousNode()
   {
-
-    if (null == m_cachedNodes)
-      throw new RuntimeException(
-        "This NodeSetDTM can not iterate to a previous node!");
-
-    return m_cachedNodes.previousNode();
+    throw new RuntimeException(
+      "This NodeSetDTM can not iterate to a previous node!");
   }
 
   /**
@@ -654,7 +685,7 @@
   }
   
   /** Control over whether it is OK for detach to reset the iterator. */
-  private boolean m_allowDetach = true;
+  protected boolean m_allowDetach = true;
   
   /**
    * Specify if it's OK for detach to release the iterator for reuse.
@@ -678,10 +709,16 @@
   {    
     if(m_allowDetach)
     {
-      m_cachedNodes = null;
+      // sb: allow reusing of cached nodes when possible?
+      // m_cachedNodes = null;
       m_execContext = null;
-      m_prefixResolver = null;
+      // m_prefixResolver = null;  sb: Why would this ever want to be null?
       m_cdtm = null;
+      m_length = -1;
+      m_pos = 0;
+      m_lastFetched = DTM.NULL;
+      m_context = DTM.NULL;
+      m_currentContextNode = DTM.NULL;
       
       m_clones.freeInstance(this);
     }
@@ -692,12 +729,7 @@
    */
   public void reset()
   {
-
-    // super.reset();
-    m_foundLast = false;
-    m_lastFetched = DTM.NULL;
-    m_next = 0;
-    m_last = 0;
+  	assertion(false, "This iterator can not reset!");
   }
 
   /**
@@ -710,10 +742,17 @@
    */
   public DTMIterator cloneWithReset() throws CloneNotSupportedException
   {
+    LocPathIterator clone;
+//    clone = (LocPathIterator) clone();
+    clone = (LocPathIterator)m_clones.getInstanceOrThrow();
+    clone.m_execContext = m_execContext;
+    clone.m_cdtm = m_cdtm;
+    
+    clone.m_context = m_context;
+    clone.m_currentContextNode = m_currentContextNode;
+    clone.m_stackFrame = m_stackFrame;
 
-    LocPathIterator clone = (LocPathIterator) clone();
-
-    clone.reset();
+    // clone.reset();
 
     return clone;
   }
@@ -756,10 +795,7 @@
 
     if (DTM.NULL != nextNode)
     {
-      if (null != m_cachedNodes)
-        m_cachedNodes.addElement(nextNode);
-
-      this.incrementNextPosition();
+      m_pos++;
     }
 
     m_lastFetched = nextNode;
@@ -882,101 +918,14 @@
    */
   public final PrefixResolver getPrefixResolver()
   {
+  	if(null == m_prefixResolver)
+  	{
+    	m_prefixResolver = (PrefixResolver)getExpressionOwner();
+  	}
+
     return m_prefixResolver;
   }
-
-  /**
-   * Get the index of the last node in the iteration.
-   *
-   *
-   * @return the index of the last node in the iteration.
-   */
-  public int getLast()
-  {
-    return getLength();
-  }
-
-  /**
-   * Set the index of the last node in the iteration.
-   *
-   *
-   * @param last the index of the last node in the iteration.
-   */
-  public void setLast(int last)
-  {
-    m_last = last;
-  }
-  
-   /**
-   * Get the index of the last node that can be itterated to.
-   * This probably will need to be overridded by derived classes.
-   *
-   * @param xctxt XPath runtime context.
-   *
-   * @return the index of the last node that can be itterated to.
-   */
-  public int getLastPos(XPathContext xctxt)
-  {
-    return getLength();
-  }
-    
-  /**
-   * Get the index of the last node that can be itterated to.
-   * This probably will need to be overridded by derived classes.
-   *
-   * @param xctxt XPath runtime context.
-   *
-   * @return the index of the last node that can be itterated to.
-   */
-  public int findLastPos(XPathContext xctxt)
-  {
-    int savedPos;
-    if(null != m_cachedNodes)
-      savedPos = m_cachedNodes.getCurrentPos();
-    else 
-      savedPos = -1;
-      
-    int pos = (m_predicateIndex >= 0) ? getProximityPosition() : 
-              ((null != m_cachedNodes) ? m_cachedNodes.getCurrentPos() : m_next);
-              
-    LocPathIterator clone;
-
-    try
-    {
-      // %REVIEW% %OPT%
-      if(0 == pos && m_currentContextNode != DTM.NULL)
-        clone = (LocPathIterator) cloneWithReset();
-      else
-        clone = (LocPathIterator) clone();
-    }
-    catch (CloneNotSupportedException cnse)
-    {
-      return -1;
-    }
-
-    // We want to clip off the last predicate, but only if we are a sub 
-    // context node list, NOT if we are a context list.  See pos68 test, 
-    // also test against bug4638.
-    int predCount = clone.getPredicateCount();
-    if(predCount > 0 && this == m_execContext.getSubContextList())
-    {
-      // Don't call setPredicateCount, because it clones and is slower.
-      clone.m_predCount = predCount - 1;
-    }
-
-    int next;
-
-    while (DTM.NULL != (next = clone.nextNode()))
-    {
-      pos++;
-    }
-    
-    if(-1 != savedPos)
-      m_cachedNodes.setCurrentPos(savedPos);
-
-    return pos;
-  }
-  
+        
 //  /**
 //   * Get the analysis pattern built by the WalkerFactory.
 //   *
@@ -996,6 +945,19 @@
 //  {
 //    m_analysis = a;
 //  }
+
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	 	if(visitor.visitLocationPath(owner, this))
+  	 	{
+  	 		visitor.visitStep(owner, this);
+  	 		callPredicateVisitors(visitor);
+  	 	}
+  }  
+
   
   //============= State Data =============
   
@@ -1025,19 +987,10 @@
    */
   private boolean m_isTopLevel = false;
 
-  /** The index of the last node in the iteration. */
-  transient protected int m_last = 0;
-  
   /** The last node that was fetched, usually by nextNode. */
   transient public int m_lastFetched = DTM.NULL;
 
   /**
-   * If this iterator needs to cache nodes that are fetched, they
-   * are stored here.
-   */
-  transient NodeSetDTM m_cachedNodes;
-
-  /**
    * The context node for this iterator, which doesn't change through
    * the course of the iteration.
    */
@@ -1050,26 +1003,26 @@
    * expression, rather than the context for the subexpression.
    */
   transient protected int m_currentContextNode = DTM.NULL;
+  
+  /**
+   * The current position of the context node.
+   */
+  transient protected int m_pos = 0;
+  
+  transient protected int m_length = -1;
 
   /**
    * Fast access to the current prefix resolver.  It isn't really
    * clear that this is needed.
    * @serial
    */
-  protected PrefixResolver m_prefixResolver;
+  private PrefixResolver m_prefixResolver;
 
   /**
    * The XPathContext reference, needed for execution of many
    * operations.
    */
   transient protected XPathContext m_execContext;
-
-  /**
-   * The index of the next node to be fetched.  Useful if this
-   * is a cached iterator, and is being used as random access
-   * NodeList.
-   */
-  transient protected int m_next;
   
   /**
    * Returns true if all the nodes in the iteration well be returned in document 
@@ -1101,4 +1054,12 @@
 //   * @serial
 //   */
 //  protected int m_analysis = 0x00000000;
+  /**
+   * @see PredicatedNodeTest#getLastPos(XPathContext)
+   */
+  public int getLastPos(XPathContext xctxt)
+  {
+    return getLength();
+  }
+
 }
diff --git a/src/org/apache/xpath/axes/MatchPatternIterator.java b/src/org/apache/xpath/axes/MatchPatternIterator.java
index c0138a6..c577131 100644
--- a/src/org/apache/xpath/axes/MatchPatternIterator.java
+++ b/src/org/apache/xpath/axes/MatchPatternIterator.java
@@ -192,6 +192,7 @@
     
   }
   
+  
   /**
    * Initialize the context values for this expression
    * after it is cloned.
@@ -225,29 +226,10 @@
    *   <code>null</code> if there are no more members in that set.
    */
   public int nextNode()
-  {
+  {      
+  	if(m_foundLast)
+  		return DTM.NULL;
 
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if ((null != m_cachedNodes)
-            && (m_next < m_cachedNodes.size()))
-    {
-      int next = m_cachedNodes.elementAt(m_next);
-    
-      incrementNextPosition();
-      m_currentContextNode = next;
-
-      return next;
-    }
-
-    if (m_foundLast)
-    {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
-    }
-      
     int next;
     
     org.apache.xpath.VariableStack vars;
@@ -296,10 +278,7 @@
           System.out.println("next: "+next);
           System.out.println("name: "+m_cdtm.getNodeName(next));
         }
-        if (null != m_cachedNodes)
-          m_cachedNodes.addElement(m_lastFetched);
-  
-        m_next++;
+        incrementCurrentPos();
   
         return next;
       }
diff --git a/src/org/apache/xpath/axes/NodeSequence.java b/src/org/apache/xpath/axes/NodeSequence.java
new file mode 100644
index 0000000..c60aafe
--- /dev/null
+++ b/src/org/apache/xpath/axes/NodeSequence.java
@@ -0,0 +1,674 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xpath.axes;
+
+import java.io.Serializable;
+
+import java.util.Vector;
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.utils.NodeVector;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+
+/**
+ * This class is the dynamic wrapper for a Xalan DTMIterator instance, and 
+ * provides random access capabilities.
+ */
+public class NodeSequence extends XObject
+  implements DTMIterator, Cloneable, PathComponent
+{
+  /** The index of the last node in the iteration. */
+  protected int m_last = -1;
+  
+  /**
+   * The index of the next node to be fetched.  Useful if this
+   * is a cached iterator, and is being used as random access
+   * NodeList.
+   */
+  protected int m_next = 0;
+    
+  /**
+   * If this iterator needs to cache nodes that are fetched, they
+   * are stored in the Vector in the generic object.
+   */
+  protected NodeVector getVector()
+  {
+  	return (NodeVector)m_obj;
+  }
+  
+  /**
+   * Set the vector where nodes will be stored.
+   */
+  protected void SetVector(NodeVector v)
+  {
+  	m_obj = v;
+  }
+
+  
+  /**
+   * If this iterator needs to cache nodes that are fetched, they
+   * are stored here.
+   */
+  public boolean hasCache()
+  {
+  	return (m_obj != null);
+  }
+
+
+  /**
+   * The functional iterator that fetches nodes.
+   */
+  protected DTMIterator m_iter;
+  
+  /**
+   * Set the functional iterator that fetches nodes.
+   * @param iter The iterator that is to be contained.
+   */
+  public final void setIter(DTMIterator iter)
+  {
+  	m_iter = iter;
+  }
+  
+  /**
+   * Get the functional iterator that fetches nodes.
+   * @return The contained iterator.
+   */
+  public final DTMIterator getContainedIter()
+  {
+  	return m_iter;
+  }
+  
+  /**
+   * The DTMManager to use if we're using a NodeVector only.
+   * We may well want to do away with this, and store it in the NodeVector.
+   */
+  protected DTMManager m_dtmMgr;
+  
+  // ==== Constructors ====
+  
+  /**
+   * Create a new NodeSequence from a (already cloned) iterator.
+   * 
+   * @param iter Cloned (not static) DTMIterator.
+   * @param context The initial context node.
+   * @param xctxt The execution context.
+   * @param shouldCacheNodes True if this sequence can random access.
+   */
+  public NodeSequence(DTMIterator iter, int context, XPathContext xctxt, boolean shouldCacheNodes)
+  {
+  	setIter(iter);
+  	setRoot(context, xctxt);
+  	setShouldCacheNodes(shouldCacheNodes);
+  }
+  
+  /**
+   * Create a new NodeSequence from a (already cloned) iterator.
+   * 
+   * @param iter Cloned (not static) DTMIterator.
+   */
+  public NodeSequence(Object nodeVector)
+  {
+  	super(nodeVector);
+  	if(null != nodeVector)
+  	{
+  		assertion(nodeVector instanceof NodeVector, 
+  			"Must have a NodeVector as the object for NodeSequence!");
+  		if(nodeVector instanceof DTMIterator)
+  		{
+  			setIter((DTMIterator)nodeVector);
+  			m_last = ((DTMIterator)nodeVector).getLength();
+  		}
+  		
+  	}
+  }
+  
+  /**
+   * Construct an empty XNodeSet object.  This is used to create a mutable 
+   * nodeset to which random nodes may be added.
+   */
+  public NodeSequence(DTMManager dtmMgr)
+  {
+    super(new NodeVector());
+    m_last = 0;
+    m_dtmMgr = dtmMgr;
+  }
+
+  
+  /**
+   * Create a new NodeSequence in an invalid (null) state.
+   */
+  public NodeSequence()
+  {
+  }
+
+
+  /**
+   * @see DTMIterator#getDTM(int)
+   */
+  public DTM getDTM(int nodeHandle)
+  {
+  	DTMManager mgr = getDTMManager();
+  	if(null != mgr)
+    	return getDTMManager().getDTM(nodeHandle);
+    else
+    {
+    	assertion(false, "Can not get a DTM Unless a DTMManager has been set!");
+    	return null;
+    }
+  }
+
+  /**
+   * @see DTMIterator#getDTMManager()
+   */
+  public DTMManager getDTMManager()
+  {
+    return m_dtmMgr;
+  }
+
+  /**
+   * @see DTMIterator#getRoot()
+   */
+  public int getRoot()
+  {
+  	if(null != m_iter)
+    	return m_iter.getRoot();
+  	else
+  	{
+  		// NodeSetDTM will call this, and so it's not a good thing to throw 
+  		// an assertion here.
+  		// assertion(false, "Can not get the root from a non-iterated NodeSequence!");
+  		return DTM.NULL;
+  	}
+  }
+
+  /**
+   * @see DTMIterator#setRoot(int, Object)
+   */
+  public void setRoot(int nodeHandle, Object environment)
+  {
+  	if(null != m_iter)
+  	{
+  		XPathContext xctxt = (XPathContext)environment;
+  		m_dtmMgr = xctxt.getDTMManager();
+  		m_iter.setRoot(nodeHandle, environment);
+  		if(!m_iter.isDocOrdered())
+  		{
+  			if(!hasCache())
+  				setShouldCacheNodes(true);
+  			runTo(-1);
+  			m_next=0;
+  		}
+  	}
+  	else
+  		assertion(false, "Can not setRoot on a non-iterated NodeSequence!");
+  }
+
+  /**
+   * @see DTMIterator#reset()
+   */
+  public void reset()
+  {
+  	m_next = 0;
+  	// not resetting the iterator on purpose!!!
+  }
+
+  /**
+   * @see DTMIterator#getWhatToShow()
+   */
+  public int getWhatToShow()
+  {
+    return hasCache() ? (DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE) 
+    	: m_iter.getWhatToShow();
+  }
+
+  /**
+   * @see DTMIterator#getExpandEntityReferences()
+   */
+  public boolean getExpandEntityReferences()
+  {
+  	if(null != m_iter)
+  		return m_iter.getExpandEntityReferences();
+  	else
+    	return true;
+  }
+
+  /**
+   * @see DTMIterator#nextNode()
+   */
+  public int nextNode()
+  {
+    // If the cache is on, and the node has already been found, then 
+    // just return from the list.
+    NodeVector vec = getVector();
+    if (null != vec)
+    {	
+    	if(m_next < vec.size())
+    	{
+			int next = vec.elementAt(m_next);
+	    	m_next++;
+	    	return next;
+    	}
+    	else if((-1 != m_last) || (null == m_iter))
+    	{
+    		m_next++;
+    		return DTM.NULL;
+    	}
+    }
+    
+        
+ 	int next = m_iter.nextNode();
+    if(DTM.NULL != next)
+    {
+    	if(hasCache())
+    	{
+    		if(m_iter.isDocOrdered())
+    	    {
+    			getVector().addElement(next);
+    			m_next++;
+    		}
+    		else
+    		{
+    			int insertIndex = addNodeInDocOrder(next);
+    			if(insertIndex >= 0)
+    				m_next++;
+    		}
+    	}
+    	else
+    		m_next++;
+    }
+    else
+    {
+    	m_last = m_next;
+    	m_next++;
+    }
+    	
+    return next;
+  }
+
+  /**
+   * @see DTMIterator#previousNode()
+   */
+  public int previousNode()
+  {
+  	if(hasCache())
+  	{
+  		if(m_next <= 0)
+  			return DTM.NULL;
+  		else
+  		{
+  			m_next--;
+  			return item(m_next);
+  		}
+  	}
+  	else
+  	{
+	    int n = m_iter.previousNode();
+	    m_next = m_iter.getCurrentPos();
+	    return m_next;
+  	}
+  }
+
+  /**
+   * @see DTMIterator#detach()
+   */
+  public void detach()
+  {
+  	if(null != m_iter)
+  		m_iter.detach();
+  	super.detach();
+  }
+
+  /**
+   * Calling this with a value of false will cause the nodeset 
+   * to be cached.
+   * @see DTMIterator#allowDetachToRelease(boolean)
+   */
+  public void allowDetachToRelease(boolean allowRelease)
+  {
+  	if((false == allowRelease) && !hasCache())
+  	{
+  		setShouldCacheNodes(true);
+  	}
+  	
+  	if(null != m_iter)
+  		m_iter.allowDetachToRelease(allowRelease);
+  	super.allowDetachToRelease(allowRelease);
+  }
+
+  /**
+   * @see DTMIterator#getCurrentNode()
+   */
+  public int getCurrentNode()
+  {
+  	if(hasCache())
+  	{
+  		int currentIndex = m_next-1;
+  		NodeVector vec = getVector();
+  		if((currentIndex >= 0) && (currentIndex < vec.size()))
+  			return vec.elementAt(currentIndex);
+  		else
+  			return DTM.NULL;
+  	}
+  	
+  	if(null != m_iter)
+  	{
+    	return m_iter.getCurrentNode();
+  	}
+  	else
+  		return DTM.NULL;
+  }
+
+  /**
+   * @see DTMIterator#isFresh()
+   */
+  public boolean isFresh()
+  {
+    return (0 == m_next);
+  }
+
+  /**
+   * @see DTMIterator#setShouldCacheNodes(boolean)
+   */
+  public void setShouldCacheNodes(boolean b)
+  {
+    if (b)
+    {
+      if(!hasCache())
+      {
+        SetVector(new NodeVector());
+      }
+//	  else
+//	    getVector().RemoveAllNoClear();  // Is this good?
+    }
+    else
+      SetVector(null);
+  }
+
+  /**
+   * @see DTMIterator#isMutable()
+   */
+  public boolean isMutable()
+  {
+    return hasCache(); // though may be surprising if it also has an iterator!
+  }
+
+  /**
+   * @see DTMIterator#getCurrentPos()
+   */
+  public int getCurrentPos()
+  {
+    return m_next;
+  }
+
+  /**
+   * @see DTMIterator#runTo(int)
+   */
+  public void runTo(int index)
+  {
+    int n;
+    
+    if (-1 == index)
+    {
+      int pos = m_next;
+      while (DTM.NULL != (n = nextNode()));
+      m_next = pos;
+    }
+    else if(m_next == index)
+    {
+      return;
+    }
+    else if(hasCache() && m_next < getVector().size())
+    {
+      m_next = index;
+    }
+    else if((null == getVector()) && (index < m_next))
+    {
+      while ((m_next >= index) && DTM.NULL != (n = previousNode()));
+    }
+    else
+    {   
+      while ((m_next < index) && DTM.NULL != (n = nextNode()));
+    }
+    
+  }
+
+  /**
+   * @see DTMIterator#setCurrentPos(int)
+   */
+  public void setCurrentPos(int i)
+  {
+  	runTo(i);
+  }
+
+  /**
+   * @see DTMIterator#item(int)
+   */
+  public int item(int index)
+  {
+  	setCurrentPos(index);
+  	int n = nextNode();
+  	m_next = index;
+  	return n;
+  }
+
+  /**
+   * @see DTMIterator#setItem(int, int)
+   */
+  public void setItem(int node, int index)
+  {
+  	NodeVector vec = getVector();
+  	if(null != vec)
+  	{
+  		vec.setElementAt(node, index);
+  		m_last = vec.size();
+  	}
+  	else
+  		m_iter.setItem(node, index);
+  }
+
+  /**
+   * @see DTMIterator#getLength()
+   */
+  public int getLength()
+  {
+  	if(hasCache())
+  	{
+	  	if(-1 == m_last)
+	  	{
+	  		int pos = m_next;
+	  		runTo(-1);
+	  		m_next = pos;
+	  	}
+	    return m_last;
+  	}
+  	else
+  	{
+  		return m_iter.getLength();
+  	}
+  }
+
+  /**
+   * Note: Not a deep clone.
+   * @see DTMIterator#cloneWithReset()
+   */
+  public DTMIterator cloneWithReset() throws CloneNotSupportedException
+  {
+  	NodeSequence seq = (NodeSequence)super.clone();
+    seq.m_next = 0;
+    return seq;
+  }
+  
+  /**
+   * Get a clone of this iterator, but don't reset the iteration in the 
+   * process, so that it may be used from the current position.
+   * Note: Not a deep clone.
+   *
+   * @return A clone of this object.
+   *
+   * @throws CloneNotSupportedException
+   */
+  public Object clone() throws CloneNotSupportedException
+  {
+  	return super.clone();
+  }
+
+
+  /**
+   * @see DTMIterator#isDocOrdered()
+   */
+  public boolean isDocOrdered()
+  {
+  	if(null != m_iter)
+  		return m_iter.isDocOrdered();
+  	else
+    	return true; // can't be sure?
+  }
+
+  /**
+   * @see DTMIterator#getAxis()
+   */
+  public int getAxis()
+  {
+  	if(null != m_iter)
+    	return m_iter.getAxis();
+    else
+    {
+    	assertion(false, "Can not getAxis from a non-iterated node sequence!");
+    	return 0;
+    }
+  }
+
+  /**
+   * @see PathComponent#getAnalysisBits()
+   */
+  public int getAnalysisBits()
+  {
+  	if((null != m_iter) && (m_iter instanceof PathComponent))
+    	return ((PathComponent)m_iter).getAnalysisBits();
+    else
+    	return 0;
+  }
+
+  /**
+   * @see Expression#fixupVariables(Vector, int)
+   */
+  public void fixupVariables(Vector vars, int globalsSize)
+  {
+  	super.fixupVariables(vars, globalsSize);
+  }  
+  
+  /**
+   * Add the node into a vector of nodes where it should occur in
+   * document order.
+   * @param v Vector of nodes, presumably containing Nodes
+   * @param obj Node object.
+   *
+   * @param node The node to be added.
+   * @param test true if we should test for doc order
+   * @param support The XPath runtime context.
+   * @return insertIndex.
+   * @throws RuntimeException thrown if this NodeSetDTM is not of 
+   * a mutable type.
+   */
+   protected int addNodeInDocOrder(int node)
+   {
+      assertion(hasCache(), "addNodeInDocOrder must be done on a mutable sequence!");
+
+      int insertIndex = -1;
+      
+      NodeVector vec = getVector();
+
+      // This needs to do a binary search, but a binary search 
+      // is somewhat tough because the sequence test involves 
+      // two nodes.
+      int size = vec.size(), i;
+
+      for (i = size - 1; i >= 0; i--)
+      {
+        int child = vec.elementAt(i);
+
+        if (child == node)
+        {
+          i = -2; // Duplicate, suppress insert
+
+          break;
+        }
+
+        DTM dtm = m_dtmMgr.getDTM(node);
+        if (!dtm.isNodeAfter(node, child))
+        {
+          break;
+        }
+      }
+
+      if (i != -2)
+      {
+        insertIndex = i + 1;
+
+        vec.insertElementAt(node, insertIndex);
+      }
+
+      // checkDups();
+      return insertIndex;
+    } // end addNodeInDocOrder(Vector v, Object obj)
+}
+
diff --git a/src/org/apache/xpath/axes/OneStepIterator.java b/src/org/apache/xpath/axes/OneStepIterator.java
index a069940..fb9d4ce 100644
--- a/src/org/apache/xpath/axes/OneStepIterator.java
+++ b/src/org/apache/xpath/axes/OneStepIterator.java
@@ -1,17 +1,13 @@
 package org.apache.xpath.axes;
 
 import javax.xml.transform.TransformerException;
-
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMAxisIterator;
+import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xpath.Expression;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.patterns.NodeTest;
-import org.apache.xpath.objects.XObject;
-
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.Axis;
-import org.apache.xml.dtm.DTMAxisIterator;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -46,6 +42,7 @@
     
   }
   
+  
   /**
    * Create a OneStepIterator object.
    *
@@ -107,6 +104,24 @@
     }
     return clone;
   }
+  
+  /**
+   *  Get a cloned Iterator that is reset to the beginning
+   *  of the query.
+   * 
+   *  @return A cloned NodeIterator set of the start of the query.
+   * 
+   *  @throws CloneNotSupportedException
+   */
+  public DTMIterator cloneWithReset() throws CloneNotSupportedException
+  {
+
+    OneStepIterator clone = (OneStepIterator) super.cloneWithReset();
+    clone.m_iterator = m_iterator;
+
+    return clone;
+  }
+
 
 
   /**
@@ -192,61 +207,6 @@
     else if (i < m_proximityPositions.length)
       m_proximityPositions[i]--;
   }
-
-  /**
-   * Get the number of nodes in this node list.  The function is probably ill
-   * named?
-   *
-   *
-   * @param xctxt The XPath runtime context.
-   *
-   * @return the number of nodes in this node list.
-   */
-  public int findLastPos(XPathContext xctxt)
-  {
-    if(!isReverseAxes())
-      return super.getLastPos(xctxt);
-
-    int count = 0;
-
-    try
-    {
-      OneStepIterator clone = (OneStepIterator) this.clone();
-
-      int root = getRoot();
-      xctxt.pushCurrentNode(root);
-      clone.setRoot(root, xctxt);
-
-      int predCount = clone.getPredicateCount();
-      if(predCount > 0 && this == m_execContext.getSubContextList())
-      {
-        // Don't call setPredicateCount, because it clones and is slower.
-        clone.m_predCount = predCount - 1;
-      }
-
-      // Count 'em all
-      // count = 1;
-      int next;
-
-      while (DTM.NULL != (next = clone.nextNode()))
-      {
-        count++;
-      }
-    }
-    catch (CloneNotSupportedException cnse)
-    {
-
-      // can't happen
-    }
-    finally
-    {
-      xctxt.popCurrentNode();
-    }
-
-    // System.out.println("getLastPos - pos: "+count);
-    // System.out.println("pos (ReverseAxesWalker): "+count);
-    return count;
-  }
   
   /**
    * Reset the iterator.
@@ -269,6 +229,20 @@
   {
     return m_axis;
   }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	if(m_axis != ((OneStepIterator)expr).m_axis)
+  		return false;
+  		
+  	return true;
+  }
 
-
+  
 }
diff --git a/src/org/apache/xpath/axes/OneStepIteratorForward.java b/src/org/apache/xpath/axes/OneStepIteratorForward.java
index edfe596..fea0ecf 100644
--- a/src/org/apache/xpath/axes/OneStepIteratorForward.java
+++ b/src/org/apache/xpath/axes/OneStepIteratorForward.java
@@ -1,17 +1,10 @@
 package org.apache.xpath.axes;
 
 import javax.xml.transform.TransformerException;
-
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.patterns.NodeTest;
-import org.apache.xpath.objects.XObject;
-
 import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
 import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.Axis;
-import org.apache.xml.dtm.DTMAxisTraverser;
+import org.apache.xpath.Expression;
+import org.apache.xpath.compiler.Compiler;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -44,7 +37,7 @@
     m_axis = WalkerFactory.getAxisFromStep(compiler, firstStepPos);
     
   }
-  
+    
   /**
    * Create a OneStepIterator object that will just traverse the self axes.
    * 
@@ -140,5 +133,19 @@
     return m_axis;
   }
 
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	if(m_axis != ((OneStepIteratorForward)expr).m_axis)
+  		return false;
+  		
+  	return true;
+  }
+
   
 }
\ No newline at end of file
diff --git a/src/org/apache/xpath/axes/PathComponent.java b/src/org/apache/xpath/axes/PathComponent.java
new file mode 100644
index 0000000..d75fc78
--- /dev/null
+++ b/src/org/apache/xpath/axes/PathComponent.java
@@ -0,0 +1,72 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xpath.axes;
+
+/**
+ * Classes who implement this information provide information needed for 
+ * static analysis of a path component.
+ */
+public interface PathComponent
+{
+  /** 
+   * Get the analysis bits for this path component, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits();
+
+}
+
diff --git a/src/org/apache/xpath/axes/PredicatedNodeTest.java b/src/org/apache/xpath/axes/PredicatedNodeTest.java
index d622986..fa9278d 100644
--- a/src/org/apache/xpath/axes/PredicatedNodeTest.java
+++ b/src/org/apache/xpath/axes/PredicatedNodeTest.java
@@ -1,19 +1,20 @@
 package org.apache.xpath.axes;
 
-import org.apache.xpath.patterns.NodeTest;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
-import org.apache.xpath.Expression;
-import org.apache.xpath.axes.SubContextList;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Vector;
 
-import org.apache.xml.utils.PrefixResolver;
-
-//import org.w3c.dom.Node;
-//import org.w3c.dom.traversal.NodeFilter;
+import javax.xml.transform.TransformerException;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.compiler.Compiler;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.patterns.NodeTest;
 
 public abstract class PredicatedNodeTest extends NodeTest implements SubContextList
 {
@@ -146,7 +147,16 @@
     int pos = compiler.getFirstPredicateOpPos(opPos);
 
     if(pos > 0)
+    {
       m_predicates = compiler.getCompiledPredicates(pos);
+      if(null != m_predicates)
+      {
+      	for(int i = 0; i < m_predicates.length; i++)
+      	{
+      		m_predicates[i].exprSetParent(this);
+      	}
+      }
+    }
   }
 
   /**
@@ -255,8 +265,11 @@
    */
   protected void countProximityPosition(int i)
   {
-    if (i < m_proximityPositions.length)
-      m_proximityPositions[i]++;
+  	// Note that in the case of a UnionChildIterator, this may be a 
+  	// static object and so m_proximityPositions may indeed be null!
+  	int[] pp = m_proximityPositions;
+    if ((null != pp) && (i < pp.length))
+      pp[i]++;
   }
 
   /**
@@ -326,7 +339,8 @@
           }
 
           int proxPos = this.getProximityPosition(m_predicateIndex);
-          if (proxPos != (int) pred.num())
+          int predIndex = (int) pred.num();
+          if (proxPos != predIndex)
           {
             if (DEBUG_PREDICATECOUNTING)
             {
@@ -482,6 +496,8 @@
   public void setLocPathIterator(LocPathIterator li)
   {
     m_lpi = li;
+    if(this != li)
+      li.exprSetParent(this);
   }
   
   /**
@@ -501,6 +517,59 @@
     return false;
    }
    
+	/**
+	 * This will traverse the heararchy, calling the visitor for 
+	 * each member.  If the called visitor method returns 
+	 * false, the subtree should not be called.
+	 * 
+	 * @param owner The owner of the visitor, where that path may be 
+	 *              rewritten if needed.
+	 * @param visitor The visitor whose appropriate method will be called.
+	 */
+	public void callPredicateVisitors(XPathVisitor visitor)
+	{
+	  if (null != m_predicates)
+	    {
+	    int n = m_predicates.length;
+	    for (int i = 0; i < n; i++)
+	      {
+	      ExpressionOwner predOwner = new PredOwner(i);
+	      if (visitor.visitPredicate(predOwner, m_predicates[i]))
+	        {
+	        m_predicates[i].callVisitors(predOwner, visitor);
+	      }
+	
+	    }
+	  }
+	} 
+	
+    /**
+     * @see Expression#deepEquals(Expression)
+     */
+    public boolean deepEquals(Expression expr)
+    {
+      if (!super.deepEquals(expr))
+            return false;
+
+      PredicatedNodeTest pnt = (PredicatedNodeTest) expr;
+      if (null != m_predicates)
+      {
+
+        int n = m_predicates.length;
+        if ((null == pnt.m_predicates) || (pnt.m_predicates.length != n))
+              return false;
+        for (int i = 0; i < n; i++)
+        {
+          if (!m_predicates[i].deepEquals(pnt.m_predicates[i]))
+          	return false; 
+        }
+      }
+      else if (null != pnt.m_predicates)
+              return false; 
+              
+      return true; 
+    }
+    
   /** This is true if nextNode returns null. */
   transient protected boolean m_foundLast = false;
     
@@ -527,5 +596,33 @@
 
   /** If true, diagnostic messages about predicate execution will be posted.  */
   static final boolean DEBUG_PREDICATECOUNTING = false;
+  
+  class PredOwner implements ExpressionOwner
+  {
+  	int m_index;
+  	
+  	PredOwner(int index)
+  	{
+  		m_index = index;
+  	}
+  	
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_predicates[m_index];
+    }
 
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(PredicatedNodeTest.this);
+    	m_predicates[m_index] = exp;
+    }
+  }
+    
 }
\ No newline at end of file
diff --git a/src/org/apache/xpath/axes/ReverseAxesWalker.java b/src/org/apache/xpath/axes/ReverseAxesWalker.java
index ffe6885..9b18536 100644
--- a/src/org/apache/xpath/axes/ReverseAxesWalker.java
+++ b/src/org/apache/xpath/axes/ReverseAxesWalker.java
@@ -162,7 +162,9 @@
     if(predicateIndex < 0)
       return -1;
       
-    if (m_proximityPositions[predicateIndex] <= 0)
+    int count = m_proximityPositions[predicateIndex];
+      
+    if (count <= 0)
     {
       AxesWalker savedWalker = wi().getLastUsedWalker();
 
@@ -179,7 +181,7 @@
         wi().setLastUsedWalker(clone);
 
         // Count 'em all
-        int count = 1;
+        count++;
         int next;
 
         while (DTM.NULL != (next = clone.nextNode()))
@@ -187,7 +189,7 @@
           count++;
         }
 
-        m_proximityPositions[predicateIndex] += count;
+        m_proximityPositions[predicateIndex] = count;
       }
       catch (CloneNotSupportedException cnse)
       {
@@ -199,8 +201,8 @@
         wi().setLastUsedWalker(savedWalker);
       }
     }
-
-    return m_proximityPositions[predicateIndex];
+    
+    return count;
   }
 
   /**
diff --git a/src/org/apache/xpath/axes/SelfIteratorNoPredicate.java b/src/org/apache/xpath/axes/SelfIteratorNoPredicate.java
index 475cf31..0f3630c 100644
--- a/src/org/apache/xpath/axes/SelfIteratorNoPredicate.java
+++ b/src/org/apache/xpath/axes/SelfIteratorNoPredicate.java
@@ -63,28 +63,6 @@
    */
   public int nextNode()
   {
-
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if ((null != m_cachedNodes)
-            && (m_next < m_cachedNodes.size()))
-    {
-      int next = m_cachedNodes.elementAt(m_next);
-    
-      incrementNextPosition();
-      m_currentContextNode = next;
-
-      return next;
-    }
-
-    if (m_foundLast)
-    {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
-    }
-
     int next;
     DTM dtm = m_cdtm;
 
@@ -95,10 +73,7 @@
     // m_lastFetched = next;
     if (DTM.NULL != next)
     {
-      if (null != m_cachedNodes)
-        m_cachedNodes.addElement(m_lastFetched);
-
-      m_next++;
+      m_pos++;
 
       return next;
     }
diff --git a/src/org/apache/xpath/axes/UnionChildIterator.java b/src/org/apache/xpath/axes/UnionChildIterator.java
new file mode 100644
index 0000000..8f314d1
--- /dev/null
+++ b/src/org/apache/xpath/axes/UnionChildIterator.java
@@ -0,0 +1,165 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xpath.axes;
+
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.patterns.NodeTest;
+
+/**
+ * This class defines a simplified type of union iterator that only 
+ * tests along the child axes.  If the conditions are right, it is 
+ * much faster than using a UnionPathIterator.
+ */
+public class UnionChildIterator extends ChildTestIterator
+{
+  /**
+   * Even though these may hold full LocPathIterators, this array does 
+   * not have to be cloned, since only the node test and predicate 
+   * portion are used, and these only need static information.  However, 
+   * also note that index predicates can not be used!
+   */
+  private PredicatedNodeTest[] m_nodeTests = null;
+
+  /**
+   * Constructor for UnionChildIterator
+   */
+  public UnionChildIterator()
+  {
+    super(null);
+  }
+
+  /**
+   * Add a node test to the union list.
+   *
+   * @param test reference to a NodeTest, which will be added 
+   * directly to the list of node tests (in other words, it will 
+   * not be cloned).  The parent of this test will be set to 
+   * this object.
+   */
+  public void addNodeTest(PredicatedNodeTest test)
+  {
+
+    // Increase array size by only 1 at a time.  Fix this
+    // if it looks to be a problem.
+    if (null == m_nodeTests)
+    {
+      m_nodeTests = new PredicatedNodeTest[1];
+      m_nodeTests[0] = test;
+    }
+    else
+    {
+      PredicatedNodeTest[] tests = m_nodeTests;
+      int len = m_nodeTests.length;
+
+      m_nodeTests = new PredicatedNodeTest[len + 1];
+
+      System.arraycopy(tests, 0, m_nodeTests, 0, len);
+
+      m_nodeTests[len] = test;
+    }
+    test.exprSetParent(this);
+  }
+
+  /**
+   * Test whether a specified node is visible in the logical view of a
+   * TreeWalker or NodeIterator. This function will be called by the
+   * implementation of TreeWalker and NodeIterator; it is not intended to
+   * be called directly from user code.
+   * @param n  The node to check to see if it passes the filter or not.
+   * @return  a constant to determine whether the node is accepted,
+   *   rejected, or skipped, as defined  above .
+   */
+  public short acceptNode(int n)
+  {
+    XPathContext xctxt = getXPathContext();
+    try
+    {
+      xctxt.pushCurrentNode(n);
+      for (int i = 0; i < m_nodeTests.length; i++)
+      {
+        PredicatedNodeTest pnt = m_nodeTests[i];
+        XObject score = pnt.execute(xctxt, n);
+        if (score != NodeTest.SCORE_NONE)
+        {
+          // Note that we are assuming there are no positional predicates!
+          if (pnt.getPredicateCount() > 0)
+          {
+            if (pnt.executePredicates(n, xctxt))
+              return DTMIterator.FILTER_ACCEPT;
+          }
+          else
+            return DTMIterator.FILTER_ACCEPT;
+
+        }
+      }
+    }
+    catch (javax.xml.transform.TransformerException se)
+    {
+
+      // TODO: Fix this.
+      throw new RuntimeException(se.getMessage());
+    }
+    finally
+    {
+      xctxt.popCurrentNode();
+    }
+    return DTMIterator.FILTER_SKIP;
+  }
+
+}
\ No newline at end of file
diff --git a/src/org/apache/xpath/axes/UnionPathIterator.java b/src/org/apache/xpath/axes/UnionPathIterator.java
index cec62ab..f0d1876 100644
--- a/src/org/apache/xpath/axes/UnionPathIterator.java
+++ b/src/org/apache/xpath/axes/UnionPathIterator.java
@@ -56,28 +56,20 @@
  */
 package org.apache.xpath.axes;
 
-import org.apache.xpath.compiler.OpCodes;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.Vector;
 
-// DOM Imports
-//import org.w3c.dom.traversal.NodeIterator;
-//import org.w3c.dom.Node;
-//import org.w3c.dom.DOMException;
-//import org.w3c.dom.traversal.NodeFilter;
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.Axis;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.DTMManager;
-import org.apache.xml.dtm.DTMIterator;
-
-// Xalan Imports
-import org.apache.xpath.NodeSetDTM;
 import org.apache.xpath.Expression;
-import org.apache.xpath.XPath;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XNodeSet;
-import org.apache.xpath.objects.XObject;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
 import org.apache.xpath.compiler.Compiler;
-import org.apache.xml.utils.ObjectPool;
+import org.apache.xpath.compiler.OpCodes;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -87,8 +79,8 @@
  * As each node is iterated via nextNode(), the node is also stored
  * in the NodeVector, so that previousNode() can easily be done.
  */
-public class UnionPathIterator extends Expression
-        implements Cloneable, DTMIterator, java.io.Serializable
+public class UnionPathIterator extends LocPathIterator
+        implements Cloneable, DTMIterator, java.io.Serializable, PathComponent
 {
 
   /**
@@ -102,6 +94,7 @@
     // m_mutable = false;
     // m_cacheNodes = false;
     m_iterators = null;
+    m_exprs = null;
   }
 
   /**
@@ -113,26 +106,22 @@
    */
   public void setRoot(int context, Object environment)
   {
-    this.m_execContext = (XPathContext)environment;
-    this.m_currentContextNode = context;
-    this.m_context = context;
-    m_lastFetched = DTM.NULL;
-    m_next = 0;
-    m_last = 0;
-    m_foundLast = false;
+    super.setRoot(context, environment);
 
     try
     {
-      if (null != m_iterators)
+      if (null != m_exprs)
       {
-        int n = m_iterators.length;
+        int n = m_exprs.length;
+        DTMIterator newIters[] = new DTMIterator[n];
   
         for (int i = 0; i < n; i++)
         {
-          m_iterators[i] = ((LocPathIterator)m_iterators[i]).asIterator(m_execContext, context);
-          m_iterators[i].setRoot(context, environment);
-          m_iterators[i].nextNode();
+          DTMIterator iter = m_exprs[i].asIterator(m_execContext, context);
+          newIters[i] = iter;
+          iter.nextNode();
         }
+        m_iterators = newIters;
       }
     }
     catch(Exception e)
@@ -141,20 +130,37 @@
     }
   }
   
-  /** Control over whether it is OK for detach to reset the iterator. */
-  private boolean m_allowDetach = true;
-  
   /**
-   * Specify if it's OK for detach to release the iterator for reuse.
-   * 
-   * @param allowRelease true if it is OK for detach to release this iterator 
-   * for pooling.
+   * Add an iterator to the union list.
+   *
+   * @param iter non-null reference to a location path iterator.
    */
-  public void allowDetachToRelease(boolean allowRelease)
+  public void addIterator(DTMIterator expr)
   {
-    m_allowDetach = allowRelease;
-  }
 
+    // Increase array size by only 1 at a time.  Fix this
+    // if it looks to be a problem.
+    if (null == m_iterators)
+    {
+      m_iterators = new DTMIterator[1];
+      m_iterators[0] = expr;
+    }
+    else
+    {
+      DTMIterator[] exprs = m_iterators;
+      int len = m_iterators.length;
+
+      m_iterators = new DTMIterator[len + 1];
+
+      System.arraycopy(exprs, 0, m_iterators, 0, len);
+
+      m_iterators[len] = expr;
+    }
+    expr.nextNode();
+    if(expr instanceof Expression)
+    	((Expression)expr).exprSetParent(this);
+  }
+  
   /**
    *  Detaches the iterator from the set which it iterated over, releasing
    * any computational resources and placing the iterator in the INVALID
@@ -163,238 +169,18 @@
    * exception INVALID_STATE_ERR.
    */
   public void detach()
-  {
-
-    if(m_allowDetach)
+  {    
+    if(null != m_iterators)
     {
-      m_cachedNodes = null;
-      m_execContext = null;
-      // m_prefixResolver = null;
-      // m_cdtm = null;
-      
-      if (null != m_iterators)
-      {
-        int n = m_iterators.length;
-  
-        for (int i = 0; i < n; i++)
-        {
-          m_iterators[i].detach();
-        }
-      }
-
-  
-  //    int n = m_iterators.length;
-  //
-  //    for (int i = 0; i < n; i++)
-  //    {
-  //      m_iterators[i].detach();
-  //    }
-  
-      m_clones.freeInstance(this);
+    	int n = m_iterators.length;
+    	for(int i = 0; i < n; i++)
+    	{
+    		m_iterators[i].detach();
+    	}
+    	m_iterators = null;
     }
   }
 
-  /** Pool of UnionPathIterators.  (The need for this has to be re-evaluated.  -sb) */
-  transient protected IteratorPool m_clones = new IteratorPool(this);
-
-  /**
-   * Execute this iterator, meaning create a clone that can  
-   * store state, and initialize it for fast execution from 
-   * the current runtime state.  When this is called, no actual 
-   * query from the current context node is performed.
-   *
-   * @param xctxt The XPath execution context.
-   *
-   * @return An XNodeSet reference that holds this iterator.
-   *
-   * @throws javax.xml.transform.TransformerException
-   */
-  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
-  {
-
-    UnionPathIterator clone =
-      (UnionPathIterator) m_clones.getInstance();
-
-    int current = xctxt.getCurrentNode();
-    clone.setRoot(current, xctxt);
-
-    return new XNodeSet(clone);
-  }
-
-  /** If this iterator needs to cache nodes that are fetched, they
-   * are stored here.   */
-  transient NodeSetDTM m_cachedNodes = null;
-
-  /** The index of the next node to be fetched.  Useful if this 
-   * is a cached iterator, and is being used as random access 
-   * NodeList.   */
-  transient protected int m_next = 0;
-
-  /**
-   * If setShouldCacheNodes(true) is called, then nodes will
-   * be cached.  They are not cached by default.
-   *
-   * @param b True if this iterator should cache nodes.
-   */
-  public void setShouldCacheNodes(boolean b)
-  {
-
-    if (b)
-      m_cachedNodes = new NodeSetDTM(getDTMManager());
-    else
-      m_cachedNodes = null;
-  }
-  
-  /**
-   * Tells if this iterator can have nodes added to it or set via 
-   * the <code>setItem(int node, int index)</code> method.
-   * 
-   * @return True if the nodelist can be mutated.
-   */
-  public boolean isMutable()
-  {
-    return (m_cachedNodes != null);
-  }
-
-  /**
-   * Set the current position in the node set.
-   * @param i Must be a valid index.
-   */
-  public void setCurrentPos(int i)
-  {
-
-    if (null == m_cachedNodes)
-      throw new RuntimeException(
-        "This NodeSetDTM can not do indexing or counting functions!");
-
-    m_next = i;
-
-    m_cachedNodes.setCurrentPos(i);
-  }
-
-  /**
-   * Get the length of the list.
-   *
-   * @return The length of this list, or zero is this is not a cached list.
-   */
-  public int size()
-  {
-
-    if (null == m_cachedNodes)
-      return 0;
-
-    return m_cachedNodes.size();
-  }
-
-  /**
-   * Tells if this NodeSetDTM is "fresh", in other words, if
-   * the first nextNode() that is called will return the
-   * first node in the set.
-   *
-   * @return True if the iteration has not yet begun.
-   */
-  public boolean isFresh()
-  {
-    return (m_next == 0);
-  }
-
-  /**
-   *  Returns the previous node in the set and moves the position of the
-   * iterator backwards in the set.
-   * @return  The previous <code>Node</code> in the set being iterated over,
-   *   or<code>null</code> if there are no more members in that set.
-   */
-  public int previousNode()
-  {
-
-    if (null == m_cachedNodes)
-      throw new RuntimeException(
-        "This NodeSetDTM can not iterate to a previous node!");
-
-    return m_cachedNodes.previousNode();
-  }
-
-  /**
-   *  This attribute determines which node types are presented via the
-   * iterator. The available set of constants is defined in the
-   * <code>DTMFilter</code> interface.
-   *
-   * @return A bit set that tells what node types to show (DTMFilter.SHOW_ALL at 
-   * the iterator level).
-   */
-  public int getWhatToShow()
-  {
-
-    // TODO: ??
-    return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE;
-  }
-
-  /**
-   *  The filter used to screen nodes.
-   *
-   * @return null.
-   */
-  public DTMFilter getFilter()
-  {
-    return null;
-  }
-
-  /**
-   *  The root node of the Iterator, as specified when it was created.
-   *
-   * @return The context node of this iterator.
-   */
-  public int getRoot()
-  {
-    return m_context;
-  }
-
-  /**
-   *  The value of this flag determines whether the children of entity
-   * reference nodes are visible to the iterator. If false, they will be
-   * skipped over.
-   * <br> To produce a view of the document that has entity references
-   * expanded and does not expose the entity reference node itself, use the
-   * whatToShow flags to hide the entity reference node and set
-   * expandEntityReferences to true when creating the iterator. To produce
-   * a view of the document that has entity reference nodes but no entity
-   * expansion, use the whatToShow flags to show the entity reference node
-   * and set expandEntityReferences to false.
-   *
-   * @return true.
-   */
-  public boolean getExpandEntityReferences()
-  {
-    return true;
-  }
-
-  /**
-   * Add an iterator to the union list.
-   *
-   * @param iter non-null reference to a location path iterator.
-   */
-  public void addIterator(LocPathIterator iter)
-  {
-
-    // Increase array size by only 1 at a time.  Fix this
-    // if it looks to be a problem.
-    if (null == m_iterators)
-    {
-      m_iterators = new LocPathIterator[1];
-      m_iterators[0] = iter;
-    }
-    else
-    {
-      DTMIterator[] iters = m_iterators;
-      int len = m_iterators.length;
-
-      m_iterators = new LocPathIterator[len + 1];
-
-      System.arraycopy(iters, 0, m_iterators, 0, len);
-
-      m_iterators[len] = iter;
-    }
-  }
 
   /**
    * Create a UnionPathIterator object, including creation 
@@ -420,6 +206,88 @@
   }
   
   /**
+   * This will return an iterator capable of handling the union of paths given.
+   * 
+   * @param compiler The Compiler which is creating 
+   * this expression.
+   * @param opPos The position of this iterator in the 
+   * opcode list from the compiler.
+   * 
+   * @return Object that is derived from LocPathIterator.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public static LocPathIterator createUnionIterator(Compiler compiler, int opPos)
+          throws javax.xml.transform.TransformerException
+  {
+  	// For the moment, I'm going to first create a full UnionPathIterator, and 
+  	// then see if I can reduce it to a UnionChildIterator.  It would obviously 
+  	// be more effecient to just test for the conditions for a UnionChildIterator, 
+  	// and then create that directly.
+  	UnionPathIterator upi = new UnionPathIterator(compiler, opPos);
+  	int nPaths = upi.m_exprs.length;
+  	boolean isAllChildIterators = true;
+  	for(int i = 0; i < nPaths; i++)
+  	{
+  		LocPathIterator lpi = upi.m_exprs[i];
+  		
+  		if(lpi.getAxis() != Axis.CHILD)
+  		{
+  			isAllChildIterators = false;
+  			break;
+  		}
+  		else
+  		{
+  			// check for positional predicates or position function, which won't work.
+  			if(HasPositionalPredChecker.check(lpi))
+  			{
+  				isAllChildIterators = false;
+  				break;
+  			}
+  		}
+  	}
+  	if(isAllChildIterators)
+  	{
+  		UnionChildIterator uci = new UnionChildIterator();
+  		
+	  	for(int i = 0; i < nPaths; i++)
+	  	{
+	  		PredicatedNodeTest lpi = upi.m_exprs[i];
+	  		// I could strip the lpi down to a pure PredicatedNodeTest, but 
+	  		// I don't think it's worth it.  Note that the test can be used 
+	  		// as a static object... so it doesn't have to be cloned.
+	  		uci.addNodeTest(lpi);
+	  	}
+	  	return uci;
+  		
+  	}
+  	else
+  		return upi;
+  }
+  
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+    int bits = 0;
+    
+    if (m_exprs != null)
+    {
+      int n = m_exprs.length;
+
+      for (int i = 0; i < n; i++)
+      {
+      	int bit = m_exprs[i].getAnalysisBits();
+        bits |= bit;
+      }
+    }
+
+    return bits;
+  }
+  
+  /**
    * Read the object from a serialization stream.
    *
    * @param stream Input stream to read from
@@ -442,24 +310,6 @@
   }
 
   /**
-   * Get a cloned Iterator that is reset to the beginning 
-   * of the query.
-   *
-   * @return A cloned DTMIterator set of the start of the query.
-   *
-   * @throws CloneNotSupportedException
-   */
-  public DTMIterator cloneWithReset() throws CloneNotSupportedException
-  {
-
-    UnionPathIterator clone = (UnionPathIterator) clone();
-    
-    clone.reset();
-
-    return clone;
-  }
-
-  /**
    * Get a cloned LocPathIterator that holds the same 
    * position as this iterator.
    *
@@ -471,69 +321,39 @@
   {
 
     UnionPathIterator clone = (UnionPathIterator) super.clone();
-    if (m_iterators != null)
-    {
-      int n = m_iterators.length;
-
-      clone.m_iterators = new LocPathIterator[n];
-
-      for (int i = 0; i < n; i++)
-      {
-        clone.m_iterators[i] = (LocPathIterator)m_iterators[i].clone();
-      }
-    }
+//    if (m_iterators != null)
+//    {
+//      int n = m_iterators.length;
+//
+//      clone.m_iterators = new LocPathIterator[n];
+//
+//      for (int i = 0; i < n; i++)
+//      {
+//        clone.m_iterators[i] = (LocPathIterator)m_iterators[i].clone();
+//      }
+//    }
 
     return clone;
   }
   
+  
   /**
-   * <meta name="usage" content="experimental"/>
-   * Given an select expression and a context, evaluate the XPath
-   * and return the resulting iterator.
-   * 
-   * @param xctxt The execution context.
-   * @param contextNode The node that "." expresses.
-   * @param namespaceContext The context in which namespaces in the
-   * XPath are supposed to be expanded.
-   * 
-   * @throws TransformerException thrown if the active ProblemListener decides
-   * the error condition is severe enough to halt processing.
+   * Create a new location path iterator.
+   *
+   * @param compiler The Compiler which is creating 
+   * this expression.
+   * @param opPos The position of this iterator in the 
+   *
+   * @return New location path iterator.
    *
    * @throws javax.xml.transform.TransformerException
    */
-  public DTMIterator asIterator(
-          XPathContext xctxt, int contextNode)
-            throws javax.xml.transform.TransformerException
+  protected LocPathIterator createDTMIterator(
+          Compiler compiler, int opPos) throws javax.xml.transform.TransformerException
   {
-    UnionPathIterator clone = (UnionPathIterator)m_clones.getInstance();
-    
-    clone.setRoot(contextNode, xctxt);
-    
-    return clone;
-  }
-
-  /**
-   * Reset the iterator.
-   */
-  public void reset()
-  {
-
-    // super.reset();
-    m_foundLast = false;
-    m_next = 0;
-    m_last = 0;
-    m_lastFetched = DTM.NULL;
-
-    if (m_iterators != null)
-    {
-      int n = m_iterators.length;
-
-      for (int i = 0; i < n; i++)
-      {
-        m_iterators[i].reset();
-        m_iterators[i].nextNode();
-      }
-    }
+    LocPathIterator lpi = (LocPathIterator)WalkerFactory.newDTMIterator(compiler, opPos, 
+                                      (compiler.getLocationPathDepth() <= 0));
+    return lpi;
   }
 
   /**
@@ -558,7 +378,8 @@
     {
       loadLocationPaths(compiler, compiler.getNextOpPos(opPos), count + 1);
 
-      m_iterators[count] = createDTMIterator(compiler, opPos);
+      m_exprs[count] = createDTMIterator(compiler, opPos);
+      m_exprs[count].exprSetParent(this);
     }
     else
     {
@@ -575,6 +396,7 @@
 
         WalkingIterator iter =
           new WalkingIterator(compiler.getNamespaceContext());
+        iter.exprSetParent(this);
           
         if(compiler.getLocationPathDepth() <= 0)
           iter.setIsTopLevel(true);
@@ -583,37 +405,15 @@
 
         iter.m_firstWalker.init(compiler, opPos, steptype);
 
-        m_iterators[count] = iter;
+        m_exprs[count] = iter;
         break;
       default :
-        m_iterators = new LocPathIterator[count];
+        m_exprs = new LocPathIterator[count];
       }
     }
   }
 
   /**
-   * Create a new location path iterator.
-   *
-   * @param compiler The Compiler which is creating 
-   * this expression.
-   * @param opPos The position of this iterator in the 
-   *
-   * @return New location path iterator.
-   *
-   * @throws javax.xml.transform.TransformerException
-   */
-  protected DTMIterator createDTMIterator(
-          Compiler compiler, int opPos) throws javax.xml.transform.TransformerException
-  {
-    DTMIterator lpi = WalkerFactory.newDTMIterator(compiler, opPos, 
-                                      (compiler.getLocationPathDepth() <= 0));
-    return lpi;
-  }
-
-  /** The last node that was fetched, usually by nextNode. */
-  transient int m_lastFetched = DTM.NULL;
-
-  /**
    *  Returns the next node in the set and advances the position of the
    * iterator in the set. After a DTMIterator is created, the first call
    * to nextNode() returns the first node in the set.
@@ -622,32 +422,8 @@
    */
   public int nextNode()
   {
-
-//    // If the cache is on, and the node has already been found, then 
-//    // just return from the list.
-//    if ((null != m_cachedNodes)
-//            && (m_cachedNodes.getCurrentPos() < m_cachedNodes.size()))
-//    {
-//      return m_cachedNodes.nextNode();
-//    }
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if ((null != m_cachedNodes)
-            && (m_next < m_cachedNodes.size()))
-    {
-      int next = m_cachedNodes.elementAt(m_next);
-    
-      m_next++;
-      m_currentContextNode = next;
-
-      return next;
-    }
-
-    if (m_foundLast)
-    {
-      m_lastFetched = DTM.NULL;
-      return DTM.NULL;
-    }
+  	if(m_foundLast)
+  		return DTM.NULL;
 
     // Loop through the iterators getting the current fetched 
     // node, and get the earliest occuring in document order
@@ -694,10 +470,7 @@
       {
         m_iterators[iteratorUsed].nextNode();
 
-        if (null != m_cachedNodes)
-          m_cachedNodes.addElement(earliestNode);
-
-        m_next++;
+        incrementCurrentPos();
       }
       else
         m_foundLast = true;
@@ -707,205 +480,7 @@
 
     return earliestNode;
   }
-
-  /**
-   * If an index is requested, NodeSetDTM will call this method
-   * to run the iterator to the index.  By default this sets
-   * m_next to the index.  If the index argument is -1, this
-   * signals that the iterator should be run to the end.
-   *
-   * @param index The index to run to, or -1 if the iterator 
-   * should run to the end.
-   */
-  public void runTo(int index)
-  {
-
-    if (m_foundLast || ((index >= 0) && (index <= getCurrentPos())))
-      return;
-
-    int n;
-
-    if (-1 == index)
-    {
-      while (DTM.NULL != (n = nextNode()));
-    }
-    else
-    {
-      while (DTM.NULL != (n = nextNode()))
-      {
-        if (getCurrentPos() >= index)
-          break;
-      }
-    }
-  }
-
-  /**
-   * Get the current position, which is one less than
-   * the next nextNode() call will retrieve.  i.e. if
-   * you call getCurrentPos() and the return is 0, the next
-   * fetch will take place at index 1.
-   *
-   * @return A value greater than or equal to zero that indicates the next 
-   * node position to fetch.
-   */
-  public int getCurrentPos()
-  {
-    return m_next;
-  }
-  
-  /**
-   *  The number of nodes in the list. The range of valid child node indices
-   * is 0 to <code>length-1</code> inclusive.
-   *
-   * @return The number of nodes in the list, always greater or equal to zero.
-   */
-  public int getLength()
-  {
-
-    // resetToCachedList();
-    if(m_last > 0)
-      return m_last;
-    else if(null == m_cachedNodes || !m_foundLast)
-    {
-      m_last = getLastPos(m_execContext);
-    }
-    else
-    {
-      m_last = m_cachedNodes.getLength();
-    }
-    return m_last;
-  }
-  
-  /**
-   * Get the index of the last node that can be itterated to.
-   * This probably will need to be overridded by derived classes.
-   *
-   * @param xctxt XPath runtime context.
-   *
-   * @return the index of the last node that can be itterated to.
-   */
-  public int getLastPos(XPathContext xctxt)
-  {
-    int pos = m_next;
-    UnionPathIterator clone;
-
-    int savedPos;
-    if(null != m_cachedNodes)
-      savedPos = m_cachedNodes.getCurrentPos();
-    else 
-      savedPos = -1;
-
-    try
-    {
-      // %REVIEW% %OPT%
-      if(0 == pos && m_currentContextNode != DTM.NULL)
-        clone = (UnionPathIterator) cloneWithReset();
-      else
-        clone = (UnionPathIterator) clone();
-    }
-    catch (CloneNotSupportedException cnse)
-    {
-      return -1;
-    }
-
-    int next;
-    pos = clone.getCurrentPos();
-
-    while (DTM.NULL != (next = clone.nextNode()))
-    {
-      pos++;
-    }
-    
-    if(-1 != savedPos)
-      m_cachedNodes.setCurrentPos(savedPos);
-    
-    return pos;
-  }
-
-  /**
-   *  Returns the <code>index</code> th item in the collection. If
-   * <code>index</code> is greater than or equal to the number of nodes in
-   * the list, this returns <code>null</code> .
-   * @param index  Index into the collection.
-   * @return  The node at the <code>index</code> th position in the
-   *   <code>NodeList</code> , or <code>null</code> if that is not a valid
-   *   index.
-   */
-  public int item(int index)
-  {
-    // resetToCachedList(); %TBD% ??
-
-    return m_cachedNodes.item(index);
-  }
-  
-  /**
-   * Sets the node at the specified index of this vector to be the
-   * specified node. The previous component at that position is discarded.
-   *
-   * <p>The index must be a value greater than or equal to 0 and less
-   * than the current size of the vector.  
-   * The iterator must be in cached mode.</p>
-   * 
-   * <p>Meant to be used for sorted iterators.</p>
-   *
-   * @param node Node to set
-   * @param index Index of where to set the node
-   */
-  public void setItem(int node, int index)
-  {
-    m_cachedNodes.setElementAt(node, index);
-  }
-  
-  /**
-   * Set the current context node for this iterator.
-   *
-   * @param n Must be a non-null reference to the node context.
-   */
-  public final void setRoot(int n)
-  {
-    m_context = n;
-  }
-  
-  /**
-   * Set the environment in which this iterator operates, which should provide:
-   * a node (the context node... same value as "root" defined below) 
-   * a pair of non-zero positive integers (the context position and the context size) 
-   * a set of variable bindings 
-   * a function library 
-   * the set of namespace declarations in scope for the expression.
-   * 
-   * <p>At this time the exact implementation of this environment is application 
-   * dependent.  Probably a proper interface will be created fairly soon.</p>
-   * 
-   * @param environment The environment object.
-   */
-  public void setEnvironment(Object environment)
-  {
-    // no-op for now.
-  }
-  
-  /**
-   * Get an instance of the DTMManager.  Since a node 
-   * iterator may be passed without a DTMManager, this allows the 
-   * caller to easily get the DTMManager using just the iterator.
-   *
-   * @return a non-null DTMManager reference.
-   */
-  public DTMManager getDTMManager()
-  {
-    return m_execContext.getDTMManager();
-  }
-  
-  /**
-   * Return the last fetched node.
-   *
-   * @return The last fetched node, or null if the last fetch was null.
-   */
-  public int getCurrentNode()
-  {
-    return m_lastFetched;
-  }
-  
+            
   /**
    * This function is used to fixup variables from QNames to stack frame 
    * indexes at stylesheet build time.
@@ -918,63 +493,22 @@
    */
   public void fixupVariables(java.util.Vector vars, int globalsSize)
   {
-    for (int i = 0; i < m_iterators.length; i++) 
+    for (int i = 0; i < m_exprs.length; i++) 
     {
-      DTMIterator iter = m_iterators[i];
-      if(iter instanceof Expression)
-      {
-        ((Expression)iter).fixupVariables(vars, globalsSize);
-      }
+      m_exprs[i].fixupVariables(vars, globalsSize);
     }
     
   }
-
-  /**
-   * Tells if we've found the last node yet.
-   */
-  transient protected boolean m_foundLast = false;
-
-  /**
-   * The execution context for the expression.
-   */
-  transient protected XPathContext m_execContext;
-
-  /**
-   * The node context for the expression.
-   */
-  transient protected int m_context = DTM.NULL;
-
-  /**
-   * The node context from where the Location Path is being
-   * executed from (i.e. for current() support).
-   */
-  transient protected int m_currentContextNode = DTM.NULL;
   
   /**
-   * Get an instance of a DTM that "owns" a node handle.  Since a node 
-   * iterator may be passed without a DTMManager, this allows the 
-   * caller to easily get the DTM using just the iterator.
-   *
-   * @param nodeHandle the nodeHandle.
-   *
-   * @return a non-null DTM reference.
+   * The location path iterators, one for each
+   * <a href="http://www.w3.org/TR/xpath#NT-LocationPath">location
+   * path</a> contained in the union expression.
+   * @serial
    */
-  public DTM getDTM(int nodeHandle)
-  {
-    return m_execContext.getDTM(nodeHandle);
-  }
-  
-  /**
-   * The node context from where the expression is being
-   * executed from (i.e. for current() support).
-   *
-   * @return The top-level node context of the entire expression.
-   */
-  public int getCurrentContextNode()
-  {
-    return m_currentContextNode;
-  }
+  protected LocPathIterator[] m_exprs;
 
+    
   /**
    * The location path iterators, one for each
    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath">location
@@ -982,39 +516,7 @@
    * @serial
    */
   protected DTMIterator[] m_iterators;
-  
-  /**
-   * The last index in the list.
-   */
-  transient private int m_last = 0;
-  
-  /**
-   * Get the index of the last node in the itteration.
-   */
-  public int getLast()
-  {
-    return m_last;
-  }
-  
-  /**
-   * Set the index of the last node in the itteration.
-   */
-  public void setLast(int last)
-  {
-    m_last = last;
-  }
-  
-  /**
-   * Returns true if all the nodes in the iteration well be returned in document 
-   * order.
-   * 
-   * @return true as a default.
-   */
-  public boolean isDocOrdered()
-  {
-    return true;
-  }
-  
+      
   /**
    * Returns the axis being iterated, if it is known.
    * 
@@ -1026,5 +528,98 @@
     // Could be smarter.
     return -1;
   }
+  
+  class iterOwner implements ExpressionOwner
+  {
+  	int m_index;
+  	
+  	iterOwner(int index)
+  	{
+  		m_index = index;
+  	}
+  	
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_exprs[m_index];
+    }
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	
+    	if(!(exp instanceof LocPathIterator))
+    	{
+    		// Yuck.  Need FilterExprIter.  Or make it so m_exprs can be just 
+    		// plain expressions?
+    		WalkingIterator wi = new WalkingIterator(getPrefixResolver());
+    		FilterExprWalker few = new FilterExprWalker(wi);
+    		wi.setFirstWalker(few);
+    		few.setInnerExpression(exp);
+    		wi.exprSetParent(UnionPathIterator.this);
+    		few.exprSetParent(wi);
+    		exp.exprSetParent(few);
+    		exp = wi;
+    	}
+    	else
+    		exp.exprSetParent(UnionPathIterator.this);
+    	m_exprs[m_index] = (LocPathIterator)exp;
+    }
+
+  }
+
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	 	if(visitor.visitUnionPath(owner, this))
+  	 	{
+  	 		if(null != m_exprs)
+  	 		{
+  	 			int n = m_exprs.length;
+  	 			for(int i = 0; i < n; i++)
+  	 			{
+  	 				m_exprs[i].callVisitors(new iterOwner(i), visitor);
+  	 			}
+  	 		}
+  	 	}
+  }
+  
+    /**
+     * @see Expression#deepEquals(Expression)
+     */
+    public boolean deepEquals(Expression expr)
+    {
+      if (!super.deepEquals(expr))
+            return false;
+
+      UnionPathIterator upi = (UnionPathIterator) expr;
+
+      if (null != m_exprs)
+      {
+        int n = m_exprs.length;
+        
+        if((null == upi.m_exprs) || (upi.m_exprs.length != n))
+        	return false;
+        
+        for (int i = 0; i < n; i++)
+        {
+          if(!m_exprs[i].deepEquals(upi.m_exprs[i]))
+          	return false;
+        }
+      }
+      else if (null != upi.m_exprs)
+      {
+          return false;
+      }
+
+      return true;
+    }
+
 
 }
diff --git a/src/org/apache/xpath/axes/WalkerFactory.java b/src/org/apache/xpath/axes/WalkerFactory.java
index 62f97c2..669868f 100644
--- a/src/org/apache/xpath/axes/WalkerFactory.java
+++ b/src/org/apache/xpath/axes/WalkerFactory.java
@@ -150,6 +150,7 @@
       walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis);
 
       walker.init(compiler, stepOpCodePos, stepType);
+      walker.exprSetParent(lpi);
 
       // walker.setAnalysis(analysis);
       if (null == firstWalker)
@@ -386,7 +387,59 @@
 
     throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
                                //+ stepType);
-  }
+   }
+    
+    /**
+     * Get a corresponding BIT_XXX from an axis.
+     * @param axis One of Axis.ANCESTOR, etc.
+     * @return One of BIT_ANCESTOR, etc.
+     */
+    static public int getAnalysisBitFromAxes(int axis)
+    {
+      switch (axis) // Generate new traverser
+        {
+        case Axis.ANCESTOR :
+          return BIT_ANCESTOR;
+        case Axis.ANCESTORORSELF :
+          return BIT_ANCESTOR_OR_SELF;
+        case Axis.ATTRIBUTE :
+          return BIT_ATTRIBUTE;
+        case Axis.CHILD :
+          return BIT_CHILD;
+        case Axis.DESCENDANT :
+          return BIT_DESCENDANT;
+        case Axis.DESCENDANTORSELF :
+          return BIT_DESCENDANT_OR_SELF;
+        case Axis.FOLLOWING :
+          return BIT_FOLLOWING;
+        case Axis.FOLLOWINGSIBLING :
+          return BIT_FOLLOWING_SIBLING;
+        case Axis.NAMESPACE :
+        case Axis.NAMESPACEDECLS :
+          return BIT_NAMESPACE;
+        case Axis.PARENT :
+          return BIT_PARENT;
+        case Axis.PRECEDING :
+          return BIT_PRECEDING;
+        case Axis.PRECEDINGSIBLING :
+          return BIT_PRECEDING_SIBLING;
+        case Axis.SELF :
+          return BIT_SELF;
+        case Axis.ALLFROMNODE :
+          return BIT_DESCENDANT_OR_SELF;
+          // case Axis.PRECEDINGANDANCESTOR :
+        case Axis.DESCENDANTSFROMROOT :
+        case Axis.ALL :
+        case Axis.DESCENDANTSORSELFFROMROOT :
+          return BIT_ANY_DESCENDANT_FROM_ROOT;
+        case Axis.ROOT :
+          return BIT_ROOT;
+        case Axis.FILTEREDLIST :
+          return BIT_FILTER;
+        default :
+          return BIT_FILTER;
+      }
+    }
   
   static boolean functionProximateOrContainsProximate(Compiler compiler, 
                                                       int opPos)
@@ -1399,12 +1452,18 @@
     return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
   }
   
-  public static boolean walksSubtreeOnly(int analysis)
+  public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
   {
     return walksSubtree(analysis)
            && !walksExtraNodes(analysis) 
            && !walksUp(analysis) 
            && !walksSideways(analysis) 
+           ;
+  }
+  
+  public static boolean walksSubtreeOnly(int analysis)
+  {
+    return walksSubtreeOnlyMaybeAbsolute(analysis) 
            && !isAbsolute(analysis) 
            ;
   }
@@ -1426,15 +1485,22 @@
 
   public static boolean walksInDocOrder(int analysis)
   {
-    return (walksSubtree(analysis)
-           || walksExtraNodes(analysis)
-           || isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)) 
-           && !walksUp(analysis) 
-           && !isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING) 
+    return (walksSubtreeOnlyMaybeAbsolute(analysis)
+           || walksExtraNodesOnly(analysis)
+           || walksFollowingOnlyMaybeAbsolute(analysis)) 
            && !isSet(analysis, BIT_FILTER) 
            ;
   }
   
+  public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
+  {
+    return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
+           && !walksSubtree(analysis) 
+           && !walksUp(analysis) 
+           && !walksSideways(analysis) 
+           ;
+  }
+  
   public static boolean walksUp(int analysis)
   {
     return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
@@ -1475,7 +1541,7 @@
            && !walksDescendants(analysis) 
            && !walksUp(analysis) 
            && !walksSideways(analysis) 
-           && !isAbsolute(analysis) 
+           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
            ;
   }
   
@@ -1485,7 +1551,7 @@
            && !walksDescendants(analysis) 
            && !walksUp(analysis) 
            && !walksSideways(analysis) 
-           && !isAbsolute(analysis) 
+           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
            ;
   }
   
@@ -1495,7 +1561,7 @@
            && walksDescendants(analysis) 
            && !walksUp(analysis) 
            && !walksSideways(analysis) 
-           && !isAbsolute(analysis) 
+           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
            ;
   }
   
@@ -1570,14 +1636,35 @@
    * Tell if the pattern can be 'walked' with the iteration steps in natural 
    * document order, without duplicates.
    *
+   * @param analysis The general analysis of the pattern.
+   *
+   * @return true if the walk can be done in natural order.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  static public boolean isNaturalDocOrder(int analysis)
+  {
+    if(canCrissCross(analysis) || isSet(analysis, BIT_NAMESPACE) ||
+       walksFilteredList(analysis))
+      return false;
+      
+    if(walksInDocOrder(analysis))
+      return true;
+      
+    return false;
+  }
+  
+  /**
+   * Tell if the pattern can be 'walked' with the iteration steps in natural 
+   * document order, without duplicates.
+   *
    * @param compiler non-null reference to compiler object that has processed
    *                 the XPath operations into an opcode map.
    * @param stepOpCodePos The opcode position for the step.
    * @param stepIndex The top-level step index withing the iterator.
    * @param analysis The general analysis of the pattern.
    *
-   * @return 32 bits as an integer that give information about the location
-   * path as a whole.
+   * @return true if the walk can be done in natural order.
    *
    * @throws javax.xml.transform.TransformerException
    */
diff --git a/src/org/apache/xpath/axes/WalkingIterator.java b/src/org/apache/xpath/axes/WalkingIterator.java
index 056189d..a25a347 100644
--- a/src/org/apache/xpath/axes/WalkingIterator.java
+++ b/src/org/apache/xpath/axes/WalkingIterator.java
@@ -1,33 +1,21 @@
 package org.apache.xpath.axes;
 
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.DTMManager;
+import java.util.Vector;
 
-// Xalan imports
-import org.apache.xpath.res.XPATHErrorResources;
-import org.apache.xpath.XPath;
-import org.apache.xpath.compiler.OpMap;
-import org.apache.xpath.compiler.Compiler;
-import org.apache.xpath.compiler.OpCodes;
-import org.apache.xpath.compiler.PsuedoNames;
-import org.apache.xpath.NodeSetDTM;
-import org.apache.xpath.Expression;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
-import org.apache.xml.utils.IntStack;
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.DTM;
 import org.apache.xml.utils.PrefixResolver;
-import org.apache.xml.utils.ObjectPool;
-import org.apache.xpath.objects.XNodeSet;
-import org.apache.xpath.axes.AxesWalker;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.compiler.Compiler;
 
 /**
  * Location path iterator that uses Walkers.
  */
 
-public class WalkingIterator extends LocPathIterator
+public class WalkingIterator extends LocPathIterator implements ExpressionOwner
 {
   /**
    * Create a WalkingIterator iterator, including creation
@@ -65,12 +53,33 @@
    * @param nscontext The namespace context for this iterator,
    * should be OK if null.
    */
-  protected WalkingIterator(PrefixResolver nscontext)
+  public WalkingIterator(PrefixResolver nscontext)
   {
 
     super(nscontext);
   }
+  
+  
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+    int bits = 0;
+    if (null != m_firstWalker)
+    {    	
+      AxesWalker walker = m_firstWalker;
 
+      while (null != walker)
+      {
+        int bit = walker.getAnalysisBits();
+        bits |= bit;
+        walker = walker.getNextWalker();
+      }       
+    }
+    return bits;
+  }
   
   /**
    * Get a cloned WalkingIterator that holds the same
@@ -113,6 +122,25 @@
   }
   
   /**
+   * Initialize the context values for this expression
+   * after it is cloned.
+   *
+   * @param execContext The XPath runtime context for this
+   * transformation.
+   */
+  public void setRoot(int context, Object environment)
+  {
+
+    super.setRoot(context, environment);
+    
+    if(null != m_firstWalker)
+    {
+      m_firstWalker.setRoot(context);
+      m_lastUsedWalker = m_firstWalker;
+    }
+  }
+  
+  /**
    *  Returns the next node in the set and advances the position of the
    * iterator in the set. After a NodeIterator is created, the first call
    * to nextNode() returns the first node in the set.
@@ -121,26 +149,8 @@
    */
   public int nextNode()
   {
-
-    // If the cache is on, and the node has already been found, then 
-    // just return from the list.
-    if (null != m_cachedNodes)
-    {
-      if(m_next < m_cachedNodes.size())
-      {
-        int next = m_lastFetched = m_currentContextNode 
-                                       = m_cachedNodes.elementAt(m_next);
-      
-        incrementNextPosition();
-  
-        return next;
-      }
-      else if(m_foundLast)
-      {
-        m_lastFetched = DTM.NULL;
-        return DTM.NULL;
-      }
-    }
+  	if(m_foundLast)
+  		return DTM.NULL;
 
     // If the variable stack position is not -1, we'll have to 
     // set our position in the variable stack, so our variable access 
@@ -152,14 +162,6 @@
     // from the execute method.
     if (-1 == m_stackFrame)
     {
-      if (DTM.NULL == m_firstWalker.getRoot())
-      {
-        this.setNextPosition(0);
-        m_firstWalker.setRoot(m_context);
-
-        m_lastUsedWalker = m_firstWalker;
-      }
-
       return returnNextNode(m_firstWalker.nextNode());
     }
     else
@@ -171,14 +173,6 @@
 
       vars.setStackFrame(m_stackFrame);
 
-      if (DTM.NULL == m_firstWalker.getRoot())
-      {
-        this.setNextPosition(0);
-        m_firstWalker.setRoot(m_context);
-
-        m_lastUsedWalker = m_firstWalker;
-      }
-
       int n = returnNextNode(m_firstWalker.nextNode());
 
       // These two statements need to be combined into one operation.
@@ -187,6 +181,7 @@
       return n;
     }
   }
+
   
   /**
    * <meta name="usage" content="advanced"/>
@@ -199,6 +194,18 @@
   {
     return m_firstWalker;
   }
+  
+  /**
+   * <meta name="usage" content="advanced"/>
+   * Set the head of the walker list.
+   * 
+   * @param walker Should be a valid AxesWalker.
+   */
+  public final void setFirstWalker(AxesWalker walker)
+  {
+    m_firstWalker = walker;
+  }
+
 
   /**
    * <meta name="usage" content="advanced"/>
@@ -230,11 +237,21 @@
    * exception INVALID_STATE_ERR.
    */
   public void detach()
-  {    
-    m_lastUsedWalker = null;
-    
-    // Always call the superclass detach last!
-    super.detach();
+  {   
+    if(m_allowDetach)
+    {
+	  	AxesWalker walker = m_firstWalker; 
+	    while (null != walker)
+	    {
+	      walker.detach();
+	      walker = walker.getNextWalker();
+	    }
+	
+	    m_lastUsedWalker = null;
+	    
+	    // Always call the superclass detach last!
+	    super.detach();
+    }
   }
   
   /**
@@ -259,6 +276,20 @@
       walker = walker.getNextWalker();
     }
   }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	 	if(visitor.visitLocationPath(owner, this))
+  	 	{
+  	 		if(null != m_firstWalker)
+  	 		{
+  	 			m_firstWalker.callVisitors(this, visitor);
+  	 		}
+  	 	}
+  }
 
   
   /** The last used step walker in the walker list.
@@ -269,4 +300,45 @@
    *  @serial */
   protected AxesWalker m_firstWalker;
 
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_firstWalker;
+  }
+
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+  	exp.exprSetParent(this);
+  	m_firstWalker = (AxesWalker)exp;
+  }
+  
+    /**
+     * @see Expression#deepEquals(Expression)
+     */
+    public boolean deepEquals(Expression expr)
+    {
+      if (!super.deepEquals(expr))
+                return false;
+
+      AxesWalker walker1 = m_firstWalker;
+      AxesWalker walker2 = ((WalkingIterator)expr).m_firstWalker;
+      while ((null != walker1) && (null != walker2))
+      {
+        if(!walker1.deepEquals(walker2))
+        	return false;
+        walker1 = walker1.getNextWalker();
+        walker2 = walker2.getNextWalker();
+      }
+      
+      if((null != walker1) || (null != walker2))
+      	return false;
+
+      return true;
+    }
+
 }
\ No newline at end of file
diff --git a/src/org/apache/xpath/axes/WalkingIteratorSorted.java b/src/org/apache/xpath/axes/WalkingIteratorSorted.java
index 0282ae7..b056d2c 100644
--- a/src/org/apache/xpath/axes/WalkingIteratorSorted.java
+++ b/src/org/apache/xpath/axes/WalkingIteratorSorted.java
@@ -65,13 +65,17 @@
 
 /**
  * <meta name="usage" content="internal"/>
- * NEEDSDOC Class WalkingIteratorSorted <needs-comment/>
+ * This class iterates over set of nodes that needs to be sorted.
  */
 public class WalkingIteratorSorted extends WalkingIterator
 {
 
-  /** NEEDSDOC Field m_inNaturalOrder          */
-  protected boolean m_inNaturalOrder = false;
+//  /** True if the nodes will be found in document order */
+//  protected boolean m_inNaturalOrder = false;
+  
+  /** True if the nodes will be found in document order, and this can 
+   * be determined statically. */
+  protected boolean m_inNaturalOrderStatic = false;
 
   /**
    * Create a WalkingIteratorSorted object.
@@ -85,36 +89,46 @@
   }
 
   /**
-   * Create a WalkingIteratorSorted iteratorWalkingIteratorSortedWalkingIteratorSorted.
+   * Create a WalkingIterator iterator, including creation
+   * of step walkers from the opcode list, and call back
+   * into the Compiler to create predicate expressions.
    *
    * @param compiler The Compiler which is creating
    * this expression.
    * @param opPos The position of this iterator in the
    * opcode list from the compiler.
-   * NEEDSDOC @param analysis
    * @param shouldLoadWalkers True if walkers should be
    * loaded, or false if this is a derived iterator and
    * it doesn't wish to load child walkers.
    *
    * @throws javax.xml.transform.TransformerException
    */
-  public WalkingIteratorSorted(
+  WalkingIteratorSorted(
           Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
             throws javax.xml.transform.TransformerException
   {
-
     super(compiler, opPos, analysis, shouldLoadWalkers);
-
-    //this.setShouldCacheNodes(true);
+  }
+  
+  /**
+   * Returns true if all the nodes in the iteration well be returned in document 
+   * order.
+   * 
+   * @return true as a default.
+   */
+  public boolean isDocOrdered()
+  {
+    return m_inNaturalOrderStatic;
   }
 
+    
   /**
-   * NEEDSDOC Method canBeWalkedInNaturalDocOrder 
+   * Tell if the nodeset can be walked in doc order, via static analysis. 
    *
    *
-   * NEEDSDOC (canBeWalkedInNaturalDocOrder) @return
+   * @return true if the nodeset can be walked in doc order, without sorting.
    */
-  boolean canBeWalkedInNaturalDocOrder()
+  boolean canBeWalkedInNaturalDocOrderStatic()
   {
 
     if (null != m_firstWalker)
@@ -126,12 +140,15 @@
       for(int i = 0; null != walker; i++)
       {
         int axis = walker.getAxis();
-        boolean isSimpleDownAxis = ((axis == Axis.CHILD)
-           || (axis == Axis.SELF)
-           || (axis == Axis.ROOT));
+        
         if(walker.isDocOrdered())
         {
-          if(isSimpleDownAxis)
+          boolean isSimpleDownAxis = ((axis == Axis.CHILD)
+                                   || (axis == Axis.SELF)
+                                   || (axis == Axis.ROOT));
+          // Catching the filtered list here is only OK because
+          // FilterExprWalker#isDocOrdered() did the right thing.
+          if(isSimpleDownAxis || (axis == -1))
             walker = walker.getNextWalker();
           else
           {
@@ -154,143 +171,82 @@
     return false;
   }
 
+
+//  /**
+//   * NEEDSDOC Method canBeWalkedInNaturalDocOrder 
+//   *
+//   *
+//   * NEEDSDOC (canBeWalkedInNaturalDocOrder) @return
+//   */
+//  boolean canBeWalkedInNaturalDocOrder()
+//  {
+//
+//    if (null != m_firstWalker)
+//    {
+//      AxesWalker walker = m_firstWalker;
+//      int prevAxis = -1;
+//      boolean prevIsSimpleDownAxis = true;
+//
+//      for(int i = 0; null != walker; i++)
+//      {
+//        int axis = walker.getAxis();
+//        
+//        if(walker.isDocOrdered())
+//        {
+//          boolean isSimpleDownAxis = ((axis == Axis.CHILD)
+//                                   || (axis == Axis.SELF)
+//                                   || (axis == Axis.ROOT));
+//          // Catching the filtered list here is only OK because
+//          // FilterExprWalker#isDocOrdered() did the right thing.
+//          if(isSimpleDownAxis || (axis == -1))
+//            walker = walker.getNextWalker();
+//          else
+//          {
+//            boolean isLastWalker = (null == walker.getNextWalker());
+//            if(isLastWalker)
+//            {
+//              if(walker.isDocOrdered() && (axis == Axis.DESCENDANT || 
+//                 axis == Axis.DESCENDANTORSELF || axis == Axis.DESCENDANTSFROMROOT
+//                 || axis == Axis.DESCENDANTSORSELFFROMROOT) || (axis == Axis.ATTRIBUTE))
+//                return true;
+//            }
+//            return false;
+//          }
+//        }
+//        else
+//          return false;
+//      }
+//      return true;
+//    }
+//    return false;
+//  }
+  
   /**
-   * Initialize the context values for this expression
-   * after it is cloned.
-   *
-   * @param execContext The XPath runtime context for this
-   * transformation.
-   *
-   * NEEDSDOC @param context
-   * NEEDSDOC @param environment
+   * This function is used to perform some extra analysis of the iterator.
+   * 
+   * @param vars List of QNames that correspond to variables.  This list 
+   * should be searched backwards for the first qualified name that 
+   * corresponds to the variable reference qname.  The position of the 
+   * QName in the vector from the start of the vector will be its position 
+   * in the stack frame (but variables above the globalsTop value will need 
+   * to be offset to the current stack frame).
    */
-  public void setRoot(int context, Object environment)
+  public void fixupVariables(java.util.Vector vars, int globalsSize)
   {
+    super.fixupVariables(vars, globalsSize);
 
-    super.setRoot(context, environment);
-
-    m_inNaturalOrder = canBeWalkedInNaturalDocOrder();
-
-    if (!m_inNaturalOrder)
+    int analysis = getAnalysisBits();
+    if(WalkerFactory.isNaturalDocOrder(analysis))
     {
-      this.setShouldCacheNodes(true);
-
-      // This should really be done in the super's setRoot, but if I do that 
-      // it becomes unhappy in the minitest... possibly something to do with 
-      // the keyref iterator.  -sb
-      m_cachedNodes.setLast(0);
-      m_cachedNodes.reset();
-      m_cachedNodes.RemoveAllNoClear();
-      setNextPosition(0);
-      m_firstWalker.setRoot(context);
-
-      m_lastUsedWalker = m_firstWalker;
-
-      int nextNode = DTM.NULL;
-      AxesWalker walker = getLastUsedWalker();
-      XPathContext execContext = (XPathContext) environment;
-
-      execContext.pushCurrentNodeAndExpression(context, context);
-
-      try
-      {
-        do
-        {
-          while (true)
-          {
-            if (null == walker)
-              break;
-
-            nextNode = walker.getNextNode();
-
-            if (DTM.NULL == nextNode)
-            {
-              walker = walker.m_prevWalker;
-            }
-            else
-            {
-              if (walker.acceptNode(nextNode) != DTMIterator.FILTER_ACCEPT)
-              {
-                continue;
-              }
-
-              if (null == walker.m_nextWalker)
-              {
-                setLastUsedWalker(walker);
-
-                // return walker.returnNextNode(nextNode);
-                break;
-              }
-              else
-              {
-                AxesWalker prev = walker;
-
-                walker = walker.m_nextWalker;
-
-                walker.setRoot(nextNode);
-
-                walker.m_prevWalker = prev;
-
-                continue;
-              }
-            }  // if(null != nextNode)
-          }  // while(null != walker)
-
-          if (DTM.NULL != nextNode)
-          {
-            incrementNextPosition();
-
-            // m_currentContextNode = nextNode;
-            m_cachedNodes.addNodeInDocOrder(nextNode, execContext);
-
-            walker = getLastUsedWalker();
-          }
-        }
-        while (DTM.NULL != nextNode);
-      }
-      finally
-      {
-        execContext.popCurrentNodeAndExpression();
-      }
-
-      // m_prevReturned = nextNode;
-      setNextPosition(0);
-
-      m_last = m_cachedNodes.size();
-      m_lastFetched = DTM.NULL;
-      m_currentContextNode = DTM.NULL;
-      m_foundLast = true;
+    	m_inNaturalOrderStatic = true;
     }
-  }
-
-  //  public int nextNode()
-  //  {
-  //    return super.nextNode();
-  //  }
-
-  /**
-   * Reset the iterator.
-   */
-  public void reset()
-  {
-
-    if (m_inNaturalOrder)
-      super.reset();
     else
     {
-
-      // super.reset();
-      // m_foundLast = false;
-      m_lastFetched = DTM.NULL;
-      m_next = 0;
-
-      // m_last = 0;
-      if (null != m_firstWalker)
-      {
-        m_lastUsedWalker = m_firstWalker;
-
-        m_firstWalker.setRoot(m_context);
-      }
+    	m_inNaturalOrderStatic = false;
+    	// System.out.println("Setting natural doc order to false: "+
+    	//    WalkerFactory.getAnalysisString(analysis));
     }
+    
   }
+
 }
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index 99def8a..9537e74 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -112,20 +112,13 @@
    * @param errorHandler Error listener where messages will be sent, or null 
    *                     if messages should be sent to System err.
    * @param locator The location object where the expression lives, which 
-   *                may be null.
+   *                may be null, but which, if not null, must be valid over 
+   *                the long haul, in other words, it will not be cloned.
    */
   public Compiler(ErrorListener errorHandler, SourceLocator locator)
   {
     m_errorHandler = errorHandler;
-    if(null != locator)
-    {
-      SAXSourceLocator ssl = new SAXSourceLocator();
-      ssl.setColumnNumber(locator.getColumnNumber());
-      ssl.setLineNumber(locator.getLineNumber());
-      ssl.setPublicId(locator.getPublicId());
-      ssl.setSystemId(locator.getSystemId());
-      m_locator = ssl;
-    }
+    m_locator = locator;
   }
 
   /**
@@ -229,8 +222,8 @@
       error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
             new Object[]{ Integer.toString(m_opMap[opPos]) });  //"ERROR! Unknown op code: "+m_opMap[opPos]);
     }
-    if(null != expr)
-      expr.setSourceLocator(m_locator);
+//    if(null != expr)
+//      expr.setSourceLocator(m_locator);
 
     return expr;
   }
@@ -631,7 +624,7 @@
    * 
    * @param opPos The current position in the m_opMap array.
    *
-   * @return reference to {@link org.apache.xpath.axes.UnionPathIterator} instance.
+   * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance.
    *
    * @throws TransformerException if a error occurs creating the Expression.
    */
@@ -640,7 +633,7 @@
     locPathDepth++;
     try
     {
-      return new UnionPathIterator(this, opPos);
+      return UnionPathIterator.createUnionIterator(this, opPos);
     }
     finally
     {
diff --git a/src/org/apache/xpath/functions/FuncBoolean.java b/src/org/apache/xpath/functions/FuncBoolean.java
index f2b9c5e..95966ce 100644
--- a/src/org/apache/xpath/functions/FuncBoolean.java
+++ b/src/org/apache/xpath/functions/FuncBoolean.java
@@ -84,4 +84,5 @@
   {
     return m_arg0.execute(xctxt).bool() ? XBoolean.S_TRUE : XBoolean.S_FALSE;
   }
+  
 }
diff --git a/src/org/apache/xpath/functions/FuncCount.java b/src/org/apache/xpath/functions/FuncCount.java
index 9f9bffd..2368fd2 100644
--- a/src/org/apache/xpath/functions/FuncCount.java
+++ b/src/org/apache/xpath/functions/FuncCount.java
@@ -89,17 +89,20 @@
   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
   {
 
-    DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
+//    DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
 
-    // We should probably make a function on the iterator for this, 
-    // as a given implementation could optimize.
-    int i = 0;
-
-    while (DTM.NULL != nl.nextNode())
-    {
-      i++;
-    }
-    nl.detach();
+//    // We should probably make a function on the iterator for this, 
+//    // as a given implementation could optimize.
+//    int i = 0;
+//
+//    while (DTM.NULL != nl.nextNode())
+//    {
+//      i++;
+//    }
+//    nl.detach();
+	DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
+	int i = nl.getLength();	
+	nl.detach();
 
     return new XNumber((double) i);
   }
diff --git a/src/org/apache/xpath/functions/FuncExtFunction.java b/src/org/apache/xpath/functions/FuncExtFunction.java
index 339ae40..28826b4 100644
--- a/src/org/apache/xpath/functions/FuncExtFunction.java
+++ b/src/org/apache/xpath/functions/FuncExtFunction.java
@@ -173,8 +173,10 @@
     for (int i = 0; i < nArgs; i++)
     {
       Expression arg = (Expression) m_argVec.elementAt(i);
+      
+      XObject xobj = arg.execute(xctxt);
 
-      argVec.addElement(arg.execute(xctxt));
+      argVec.addElement(xobj);
     }
 
     ExtensionsTable etable = xctxt.getExtensionsTable();
diff --git a/src/org/apache/xpath/functions/Function.java b/src/org/apache/xpath/functions/Function.java
index 1af83dd..e679bff 100644
--- a/src/org/apache/xpath/functions/Function.java
+++ b/src/org/apache/xpath/functions/Function.java
@@ -58,12 +58,12 @@
 
 //import org.w3c.dom.Node;
 
-import java.util.Vector;
-
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.XPath;
-import org.apache.xpath.objects.XObject;
+import javax.xml.transform.TransformerException;
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.XObject;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -127,5 +127,35 @@
     return null;
   }
   
+  /**
+   * Call the visitors for the function arguments.
+   */
+  public void callArgVisitors(XPathVisitor visitor)
+  {
+  }
+
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	if(visitor.visitFunction(owner, this))
+  	{
+  		callArgVisitors(visitor);
+  	}
+  }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	return true;
+  }
+
 
 }
diff --git a/src/org/apache/xpath/functions/Function2Args.java b/src/org/apache/xpath/functions/Function2Args.java
index 4fab1e0..b071a20 100644
--- a/src/org/apache/xpath/functions/Function2Args.java
+++ b/src/org/apache/xpath/functions/Function2Args.java
@@ -56,7 +56,11 @@
  */
 package org.apache.xpath.functions;
 
+import java.util.Vector;
+
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -115,7 +119,10 @@
     if (argNum == 0)
       super.setArg(arg, argNum);
     else if (1 == argNum)
+    {
       m_arg1 = arg;
+      arg.exprSetParent(this);
+    }
     else
       throw new WrongNumberArgsException("2");
   }
@@ -145,5 +152,59 @@
     return super.canTraverseOutsideSubtree() 
     ? true : m_arg1.canTraverseOutsideSubtree();
    }
+   
+  class Arg1Owner implements ExpressionOwner
+  {
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_arg1;
+    }
+
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(Function2Args.this);
+    	m_arg1 = exp;
+    }
+  }
+
+   
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callArgVisitors(XPathVisitor visitor)
+  {
+  	super.callArgVisitors(visitor);
+  	if(null != m_arg1)
+  		m_arg1.callVisitors(new Arg1Owner(), visitor);
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	if(null != m_arg1)
+  	{
+  		if(null == ((Function2Args)expr).m_arg1)
+  			return false;
+  			
+  		if(!m_arg1.deepEquals(((Function2Args)expr).m_arg1))
+  			return false;
+  	}
+  	else if(null != ((Function2Args)expr).m_arg1)
+  		return false;
+  		
+  	return true;
+  }
 
 }
diff --git a/src/org/apache/xpath/functions/Function3Args.java b/src/org/apache/xpath/functions/Function3Args.java
index 48f67a0..6d4d78d 100644
--- a/src/org/apache/xpath/functions/Function3Args.java
+++ b/src/org/apache/xpath/functions/Function3Args.java
@@ -56,7 +56,11 @@
  */
 package org.apache.xpath.functions;
 
+import java.util.Vector;
+
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -113,7 +117,10 @@
     if (argNum < 2)
       super.setArg(arg, argNum);
     else if (2 == argNum)
+    {
       m_arg2 = arg;
+      arg.exprSetParent(this);
+    }
     else
       throw new WrongNumberArgsException("3");
   }
@@ -143,5 +150,60 @@
     return super.canTraverseOutsideSubtree() 
     ? true : m_arg2.canTraverseOutsideSubtree();
    }
+   
+  class Arg2Owner implements ExpressionOwner
+  {
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_arg2;
+    }
+
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(Function3Args.this);
+    	m_arg2 = exp;
+    }
+  }
+
+   
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callArgVisitors(XPathVisitor visitor)
+  {
+  	super.callArgVisitors(visitor);
+  	if(null != m_arg2)
+  		m_arg2.callVisitors(new Arg2Owner(), visitor);
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	if(null != m_arg2)
+  	{
+  		if(null == ((Function3Args)expr).m_arg2)
+  			return false;
+
+  		if(!m_arg2.deepEquals(((Function3Args)expr).m_arg2))
+  			return false;
+  	}
+  	else if (null != ((Function3Args)expr).m_arg2)
+  		return false;
+  		
+  	return true;
+  }
+
 
 }
diff --git a/src/org/apache/xpath/functions/FunctionMultiArgs.java b/src/org/apache/xpath/functions/FunctionMultiArgs.java
index 025884a..059cc31 100644
--- a/src/org/apache/xpath/functions/FunctionMultiArgs.java
+++ b/src/org/apache/xpath/functions/FunctionMultiArgs.java
@@ -56,7 +56,12 @@
  */
 package org.apache.xpath.functions;
 
+import java.util.Vector;
+
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.functions.Function3Args.Arg2Owner;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -104,6 +109,7 @@
         args[m_args.length] = arg;
         m_args = args;
       }
+      arg.exprSetParent(this);
     }
   }
   
@@ -163,4 +169,79 @@
       return false;
     }
   }
+  
+  class ArgMultiOwner implements ExpressionOwner
+  {
+  	int m_argIndex;
+  	
+  	ArgMultiOwner(int index)
+  	{
+  		m_argIndex = index;
+  	}
+  	
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_args[m_argIndex];
+    }
+
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(FunctionMultiArgs.this);
+    	m_args[m_argIndex] = exp;
+    }
+  }
+
+   
+    /**
+     * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+     */
+    public void callArgVisitors(XPathVisitor visitor)
+    {
+      super.callArgVisitors(visitor);
+      if (null != m_args)
+      {
+        int n = m_args.length;
+        for (int i = 0; i < n; i++)
+        {
+          m_args[i].callVisitors(new ArgMultiOwner(i), visitor);
+        }
+      }
+    }
+    
+    /**
+     * @see Expression#deepEquals(Expression)
+     */
+    public boolean deepEquals(Expression expr)
+    {
+      if (!super.deepEquals(expr))
+            return false;
+
+      FunctionMultiArgs fma = (FunctionMultiArgs) expr;
+      if (null != m_args)
+      {
+        int n = m_args.length;
+        if ((null == fma) || (fma.m_args.length != n))
+              return false;
+
+        for (int i = 0; i < n; i++)
+        {
+          if (!m_args[i].deepEquals(fma.m_args[i]))
+                return false;
+        }
+
+      }
+      else if (null != fma.m_args)
+      {
+          return false;
+      }
+
+      return true;
+    }
 }
diff --git a/src/org/apache/xpath/functions/FunctionOneArg.java b/src/org/apache/xpath/functions/FunctionOneArg.java
index 513a375..b4bbfb9 100644
--- a/src/org/apache/xpath/functions/FunctionOneArg.java
+++ b/src/org/apache/xpath/functions/FunctionOneArg.java
@@ -56,13 +56,17 @@
  */
 package org.apache.xpath.functions;
 
+import java.util.Vector;
+
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
 
 /**
  * <meta name="usage" content="advanced"/>
  * Base class for functions that accept one argument.
  */
-public class FunctionOneArg extends Function
+public class FunctionOneArg extends Function implements ExpressionOwner
 {
 
   /** The first argument passed to the function (at index 0).
@@ -94,7 +98,10 @@
   {
 
     if (0 == argNum)
+    {
       m_arg0 = arg;
+      arg.exprSetParent(this);
+    }
     else
       throw new WrongNumberArgsException("1");
   }
@@ -139,5 +146,55 @@
     if(null != m_arg0)
       m_arg0.fixupVariables(vars, globalsSize);
   }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callArgVisitors(XPathVisitor visitor)
+  {
+  	if(null != m_arg0)
+  		m_arg0.callVisitors(this, visitor);
+  }
+
+
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_arg0;
+  }
+
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+  	exp.exprSetParent(this);
+  	m_arg0 = exp;
+  }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	if(null != m_arg0)
+  	{
+  		if(null == ((FunctionOneArg)expr).m_arg0)
+  			return false;
+  			
+  		if(!m_arg0.deepEquals(((FunctionOneArg)expr).m_arg0))
+  			return false;
+  	}
+  	else if(null != ((FunctionOneArg)expr).m_arg0)
+  		return false;
+
+  	return true;
+  }
+
 
 }
diff --git a/src/org/apache/xpath/objects/XNodeSet.java b/src/org/apache/xpath/objects/XNodeSet.java
index 051a4d8..9db3b52 100644
--- a/src/org/apache/xpath/objects/XNodeSet.java
+++ b/src/org/apache/xpath/objects/XNodeSet.java
@@ -70,6 +70,7 @@
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.NodeSetDTM;
 import org.apache.xpath.axes.ContextNodeList;
+import org.apache.xpath.axes.NodeSequence;
 import org.apache.xml.utils.StringVector;
 import org.apache.xml.utils.XMLString;
 
@@ -78,15 +79,8 @@
  * This class represents an XPath nodeset object, and is capable of
  * converting the nodeset to other types, such as a string.
  */
-public class XNodeSet extends XObject
-{
-  protected DTMManager m_dtmMgr;
-  
-  public DTMManager getDTMMgr()
-  {
-    return m_dtmMgr;
-  }
-  
+public class XNodeSet extends NodeSequence
+{  
   /**
    * Default constructor for derived objects.
    */
@@ -101,18 +95,44 @@
    */
   public XNodeSet(DTMIterator val)
   {
-    super(val);
-    m_dtmMgr = val.getDTMManager();
+  	super();
+  	if(val instanceof XNodeSet)
+  	{
+	    setIter(((XNodeSet)val).m_iter);
+	    m_dtmMgr = ((XNodeSet)val).m_dtmMgr;
+	    m_last = ((XNodeSet)val).m_last;
+	    if(!((XNodeSet)val).hasCache())
+	    	((XNodeSet)val).setShouldCacheNodes(true);
+	    m_obj = ((XNodeSet)val).m_obj;
+  	}
+  	else
+    	setIter(val);
   }
+  
+  /**
+   * Construct a XNodeSet object.
+   *
+   * @param val Value of the XNodeSet object
+   */
+  public XNodeSet(XNodeSet val)
+  {
+  	super();
+    setIter(val.m_iter);
+    m_dtmMgr = val.m_dtmMgr;
+    m_last = val.m_last;
+    if(!val.hasCache())
+    	val.setShouldCacheNodes(true);
+    m_obj = val.m_obj;
+  }
+
 
   /**
    * Construct an empty XNodeSet object.  This is used to create a mutable 
    * nodeset to which random nodes may be added.
    */
-  public XNodeSet(DTMManager dtmMgr)
+  public XNodeSet(DTMManager dtmMgr) 
   {
-    super(new NodeSetDTM(dtmMgr));
-    m_dtmMgr = dtmMgr;
+    super(dtmMgr);
   }
 
   /**
@@ -129,7 +149,10 @@
     if (DTM.NULL != n)
     {
       ((NodeSetDTM) m_obj).addNode(n);
+      m_last = 1;
     }
+    else
+    	m_last = 0;
   }
 
   /**
@@ -175,9 +198,7 @@
   public double num()
   {
 
-    DTMIterator nl = iter();
-    int node = nl.nextNode();
-
+    int node = item(0);
     return (node != DTM.NULL) ? getNumberFromNode(node) : Double.NaN;
   }
   
@@ -190,8 +211,7 @@
    */
   public double numWithSideEffects()
   {
-    DTMIterator nl = iterRaw();
-    int node = nl.nextNode();
+    int node = nextNode();
 
     return (node != DTM.NULL) ? getNumberFromNode(node) : Double.NaN;
   }
@@ -204,7 +224,7 @@
    */
   public boolean bool()
   {
-    return (iter().nextNode() != DTM.NULL);
+    return (item(0) != DTM.NULL);
   }
   
   /**
@@ -215,7 +235,7 @@
    */
   public boolean boolWithSideEffects()
   {
-    return (iterRaw().nextNode() != DTM.NULL);
+    return (nextNode() != DTM.NULL);
   }
 
   
@@ -254,13 +274,13 @@
   public void dispatchCharactersEvents(org.xml.sax.ContentHandler ch)
           throws org.xml.sax.SAXException
   {
-    DTMIterator nl = iter();
-    int node = nl.nextNode();
-
+    int node = item(0);
+	
     if(node != DTM.NULL)
     {
       m_dtmMgr.getDTM(node).dispatchCharactersEvents(node, ch, false);
     }
+    
   }
   
   /**
@@ -270,9 +290,7 @@
    */
   public XMLString xstr()
   {
-    DTMIterator nl = iter();
-    int node = nl.nextNode();
-
+    int node = item(0);
     return (node != DTM.NULL) ? getStringFromNode(node) : XString.EMPTYSTRING;
   }
   
@@ -287,35 +305,6 @@
     xstring.appendToFsb(fsb);
   }
   
-  /**
-   * Specify if it's OK for detach to release the iterator for reuse.
-   * 
-   * @param allowRelease true if it is OK for detach to release this iterator 
-   * for pooling.
-   */
-  public void allowDetachToRelease(boolean allowRelease)
-  {
-    if(null != m_obj)
-      ((DTMIterator) m_obj).allowDetachToRelease(allowRelease);
-  }
-
-  /**
-   * Detaches the <code>DTMIterator</code> from the set which it iterated
-   * over, releasing any computational resources and placing the iterator
-   * in the INVALID state. After <code>detach</code> has been invoked,
-   * calls to <code>nextNode</code> or <code>previousNode</code> will
-   * raise a runtime exception.
-   */
-  public void detach()
-  {
-    if(null != m_obj)
-    {
-      Object obj = m_obj;
-      m_obj = null;
-      ((DTMIterator) obj).detach();
-    }
-  }
-
 
   /**
    * Cast result object to a string.
@@ -325,11 +314,22 @@
    */
   public String str()
   {
-
-    DTMIterator nl = iter();
-    int node = nl.nextNode();
-
-    return (node != DTM.NULL) ? getStringFromNode(node).toString() : "";
+    int node = item(0);
+    return (node != DTM.NULL) ? getStringFromNode(node).toString() : "";   
+  }
+  
+  /**
+   * Return a java object that's closest to the representation
+   * that should be handed to an extension.
+   *
+   * @return The object that this class wraps
+   */
+  public Object object()
+  {
+    if(null == m_obj)
+    	return this;
+    else
+    	return m_obj;
   }
 
   // %REVIEW%
@@ -361,9 +361,9 @@
 //  }
 
   /**
-   * Cast result object to a nodelist. Always issues an error.
+   * Cast result object to a nodelist.
    *
-   * @return null
+   * @return a NodeIterator.
    *
    * @throws javax.xml.transform.TransformerException
    */
@@ -373,9 +373,9 @@
   }
   
   /**
-   * Cast result object to a nodelist. Always issues an error.
+   * Cast result object to a nodelist.
    *
-   * @return null
+   * @return a NodeList.
    *
    * @throws javax.xml.transform.TransformerException
    */
@@ -401,9 +401,11 @@
    */
   public DTMIterator iterRaw()
   {
-
-    // System.out.println("In XNodeSet.iter()");
-    return (DTMIterator) m_obj;
+    return this;
+  }
+  
+  public void release(DTMIterator iter)
+  {
   }
   
   /**
@@ -415,7 +417,30 @@
   {
     try
     {
-      return ((DTMIterator) m_obj).cloneWithReset();
+    	if(hasCache())
+      		return cloneWithReset();
+      	else
+      		return this; // don't bother to clone... won't do any good!
+    }
+    catch (CloneNotSupportedException cnse)
+    {
+      throw new RuntimeException(cnse.getMessage());
+    }
+  }
+  
+  /**
+   * Get a fresh copy of the object.  For use with variables.
+   *
+   * @return A fresh nodelist.
+   */
+  public XObject getFresh()
+  {
+    try
+    {
+    	if(hasCache())
+      		return (XObject)cloneWithReset();
+      	else
+      		return this; // don't bother to clone... won't do any good!
     }
     catch (CloneNotSupportedException cnse)
     {
@@ -430,7 +455,6 @@
    */
   public NodeSetDTM mutableNodeset()
   {
-
     NodeSetDTM mnl;
 
     if(m_obj instanceof NodeSetDTM)
@@ -441,6 +465,7 @@
     {
       mnl = new NodeSetDTM(iter());
       m_obj = mnl;
+      setCurrentPos(0);
     }
 
     return mnl;
@@ -497,8 +522,8 @@
       // is true if and only if some node in $x has the string-value 
       // foo; the latter is true if and only if all nodes in $x have 
       // the string-value foo.
-      DTMIterator list1 = iter();
-      DTMIterator list2 = ((XNodeSet) obj2).iter();
+      DTMIterator list1 = iterRaw();
+      DTMIterator list2 = ((XNodeSet) obj2).iterRaw();
       int node1;
       java.util.Vector node2Strings = null;
 
@@ -542,6 +567,8 @@
           }
         }
       }
+      list1.reset();
+      list2.reset();
     }
     else if (XObject.CLASS_BOOLEAN == type)
     {
@@ -567,7 +594,7 @@
       // comparison on the number to be compared and on the result of 
       // converting the string-value of that node to a number using 
       // the number function is true. 
-      DTMIterator list1 = iter();
+      DTMIterator list1 = iterRaw();
       double num2 = obj2.num();
       int node;
 
@@ -582,11 +609,12 @@
           break;
         }
       }
+      list1.reset();
     }
     else if (XObject.CLASS_RTREEFRAG == type)
     {
       XMLString s2 = obj2.xstr();
-      DTMIterator list1 = iter();
+      DTMIterator list1 = iterRaw();
       int node;
 
       while (DTM.NULL != (node = list1.nextNode()))
@@ -600,6 +628,7 @@
           break;
         }
       }
+      list1.reset();
     }
     else if (XObject.CLASS_STRING == type)
     {
@@ -611,7 +640,7 @@
       // the comparison on the string-value of the node and the other 
       // string is true. 
       XMLString s2 = obj2.xstr();
-      DTMIterator list1 = iter();
+      DTMIterator list1 = iterRaw();
       int node;
 
       while (DTM.NULL != (node = list1.nextNode()))
@@ -624,6 +653,7 @@
           break;
         }
       }
+      list1.reset();
     }
     else
     {
diff --git a/src/org/apache/xpath/objects/XNodeSetForDOM.java b/src/org/apache/xpath/objects/XNodeSetForDOM.java
index a1c236b..af76d27 100644
--- a/src/org/apache/xpath/objects/XNodeSetForDOM.java
+++ b/src/org/apache/xpath/objects/XNodeSetForDOM.java
@@ -25,6 +25,18 @@
     ((NodeSetDTM) m_obj).addNode(dtmHandle);
   }
   
+  /**
+   * Construct a XNodeSet object.
+   *
+   * @param val Value of the XNodeSet object
+   */
+  public XNodeSetForDOM(XNodeSet val)
+  {
+  	super(val);
+  	if(val instanceof XNodeSetForDOM)
+    	m_origObj = ((XNodeSetForDOM)val).m_origObj;
+  }
+  
   public XNodeSetForDOM(NodeList nodeList, XPathContext xctxt)
   {
     m_dtmMgr = xctxt.getDTMManager();
diff --git a/src/org/apache/xpath/objects/XNumber.java b/src/org/apache/xpath/objects/XNumber.java
index 4df9eab..23dbf85 100644
--- a/src/org/apache/xpath/objects/XNumber.java
+++ b/src/org/apache/xpath/objects/XNumber.java
@@ -56,9 +56,12 @@
  */
 package org.apache.xpath.objects;
 
-import org.w3c.dom.*;
 import java.math.BigDecimal;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
 
 /**
  * <meta name="usage" content="general"/>
@@ -153,155 +156,155 @@
     return (Double.isNaN(m_val) || (m_val == 0.0)) ? false : true;
   }
 
-//  /**
-//   * Cast result object to a string.
-//   *
-//   * @return "NaN" if the number is NaN, Infinity or -Infinity if
-//   * the number is infinite or the string value of the number.
-//   */
-//  private static final int PRECISION = 16;
-//  public String str()
-//  {
-//
-//    if (Double.isNaN(m_val))
-//    {
-//      return "NaN";
-//    }
-//    else if (Double.isInfinite(m_val))
-//    {
-//      if (m_val > 0)
-//        return "Infinity";
-//      else
-//        return "-Infinity";
-//    }
-//
-//    long longVal = (long)m_val;
-//    if ((double)longVal == m_val)
-//      return Long.toString(longVal);
-//
-//
-//    String s = Double.toString(m_val);
-//    int len = s.length();
-//
-//    if (s.charAt(len - 2) == '.' && s.charAt(len - 1) == '0')
-//    {
-//      return s.substring(0, len - 2);
-//    }
-//
-//    int exp = 0;
-//    int e = s.indexOf('E');
-//    if (e != -1)
-//    {
-//      exp = Integer.parseInt(s.substring(e + 1));
-//      s = s.substring(0,e);
-//      len = e;
-//    }
-//
-//    // Calculate Significant Digits:
-//    // look from start of string for first digit
-//    // look from end for last digit
-//    // significant digits = end - start + (0 or 1 depending on decimal location)
-//
-//    int decimalPos = -1;
-//    int start = (s.charAt(0) == '-') ? 1 : 0;
-//    findStart: for( ; start < len; start++ )
-//    {
-//      switch (s.charAt(start))
-//      {
-//      case '0':
-//        break;
-//      case '.':
-//        decimalPos = start;
-//        break;
-//      default:
-//        break findStart;
-//      }
-//    }
-//    int end = s.length() - 1;
-//    findEnd: for( ; end > start; end-- )
-//    {
-//      switch (s.charAt(end))
-//      {
-//      case '0':
-//        break;
-//      case '.':
-//        decimalPos = end;
-//        break;
-//      default:
-//        break findEnd;
-//      }
-//    }
-//
-//    int sigDig = end - start;
-//
-//    // clarify decimal location if it has not yet been found
-//    if (decimalPos == -1)
-//      decimalPos = s.indexOf('.');
-//
-//    // if decimal is not between start and end, add one to sigDig
-//    if (decimalPos < start || decimalPos > end)
-//      ++sigDig;
-//
-//    // reduce significant digits to PRECISION if necessary
-//    if (sigDig > PRECISION)
-//    {
-//      // re-scale BigDecimal in order to get significant digits = PRECISION
-//      BigDecimal num = new BigDecimal(s);
-//      int newScale = num.scale() - (sigDig - PRECISION);
-//      if (newScale < 0)
-//        newScale = 0;
-//      s = num.setScale(newScale, BigDecimal.ROUND_HALF_UP).toString();
-//
-//      // remove trailing '0's; keep track of decimalPos
-//      int truncatePoint = s.length();
-//      while (s.charAt(--truncatePoint) == '0')
-//        ;
-//
-//      if (s.charAt(truncatePoint) == '.')
-//      {
-//        decimalPos = truncatePoint;
-//      }
-//      else
-//      {
-//        decimalPos = s.indexOf('.');
-//        truncatePoint += 1;
-//      }
-//
-//      s = s.substring(0, truncatePoint);
-//      len = s.length();
-//    }
-//
-//    // Account for exponent by adding zeros as needed 
-//    // and moving the decimal place
-//
-//    if (exp == 0)
-//       return s;
-//
-//    start = 0;
-//    String sign;
-//    if (s.charAt(0) == '-')
-//    {
-//      sign = "-";
-//      start++;
-//    }
-//    else
-//      sign = "";
-//
-//    String wholePart = s.substring(start, decimalPos);
-//    String decimalPart = s.substring(decimalPos + 1);
-//
-//    // get the number of digits right of the decimal
-//    int decimalLen = decimalPart.length();
-//
-//    if (exp >= decimalLen)
-//      return sign + wholePart + decimalPart + zeros(exp - decimalLen);
-//
-//    if (exp > 0)
-//      return sign + wholePart + decimalPart.substring(0, exp) + "."
-//             + decimalPart.substring(exp);
-//
-//    return sign + "0." + zeros(-1 - exp) + wholePart + decimalPart;
-//  }
+  /**
+   * Cast result object to a string.
+   *
+   * @return "NaN" if the number is NaN, Infinity or -Infinity if
+   * the number is infinite or the string value of the number.
+   */
+  private static final int PRECISION = 16;
+  public String str()
+  {
+
+    if (Double.isNaN(m_val))
+    {
+      return "NaN";
+    }
+    else if (Double.isInfinite(m_val))
+    {
+      if (m_val > 0)
+        return "Infinity";
+      else
+        return "-Infinity";
+    }
+
+    long longVal = (long)m_val;
+    if ((double)longVal == m_val)
+      return Long.toString(longVal);
+
+
+    String s = Double.toString(m_val);
+    int len = s.length();
+
+    if (s.charAt(len - 2) == '.' && s.charAt(len - 1) == '0')
+    {
+      return s.substring(0, len - 2);
+    }
+
+    int exp = 0;
+    int e = s.indexOf('E');
+    if (e != -1)
+    {
+      exp = Integer.parseInt(s.substring(e + 1));
+      s = s.substring(0,e);
+      len = e;
+    }
+
+    // Calculate Significant Digits:
+    // look from start of string for first digit
+    // look from end for last digit
+    // significant digits = end - start + (0 or 1 depending on decimal location)
+
+    int decimalPos = -1;
+    int start = (s.charAt(0) == '-') ? 1 : 0;
+    findStart: for( ; start < len; start++ )
+    {
+      switch (s.charAt(start))
+      {
+      case '0':
+        break;
+      case '.':
+        decimalPos = start;
+        break;
+      default:
+        break findStart;
+      }
+    }
+    int end = s.length() - 1;
+    findEnd: for( ; end > start; end-- )
+    {
+      switch (s.charAt(end))
+      {
+      case '0':
+        break;
+      case '.':
+        decimalPos = end;
+        break;
+      default:
+        break findEnd;
+      }
+    }
+
+    int sigDig = end - start;
+
+    // clarify decimal location if it has not yet been found
+    if (decimalPos == -1)
+      decimalPos = s.indexOf('.');
+
+    // if decimal is not between start and end, add one to sigDig
+    if (decimalPos < start || decimalPos > end)
+      ++sigDig;
+
+    // reduce significant digits to PRECISION if necessary
+    if (sigDig > PRECISION)
+    {
+      // re-scale BigDecimal in order to get significant digits = PRECISION
+      BigDecimal num = new BigDecimal(s);
+      int newScale = num.scale() - (sigDig - PRECISION);
+      if (newScale < 0)
+        newScale = 0;
+      s = num.setScale(newScale, BigDecimal.ROUND_HALF_UP).toString();
+
+      // remove trailing '0's; keep track of decimalPos
+      int truncatePoint = s.length();
+      while (s.charAt(--truncatePoint) == '0')
+        ;
+
+      if (s.charAt(truncatePoint) == '.')
+      {
+        decimalPos = truncatePoint;
+      }
+      else
+      {
+        decimalPos = s.indexOf('.');
+        truncatePoint += 1;
+      }
+
+      s = s.substring(0, truncatePoint);
+      len = s.length();
+    }
+
+    // Account for exponent by adding zeros as needed 
+    // and moving the decimal place
+
+    if (exp == 0)
+       return s;
+
+    start = 0;
+    String sign;
+    if (s.charAt(0) == '-')
+    {
+      sign = "-";
+      start++;
+    }
+    else
+      sign = "";
+
+    String wholePart = s.substring(start, decimalPos);
+    String decimalPart = s.substring(decimalPos + 1);
+
+    // get the number of digits right of the decimal
+    int decimalLen = decimalPart.length();
+
+    if (exp >= decimalLen)
+      return sign + wholePart + decimalPart + zeros(exp - decimalLen);
+
+    if (exp > 0)
+      return sign + wholePart + decimalPart.substring(0, exp) + "."
+             + decimalPart.substring(exp);
+
+    return sign + "0." + zeros(-1 - exp) + wholePart + decimalPart;
+  }
 
   /**
    * Cast result object to a string.
@@ -309,7 +312,7 @@
    * @return "NaN" if the number is NaN, Infinity or -Infinity if
    * the number is infinite or the string value of the number.
    */
-  public String str()
+  public String zstr()
   {
 
     if (Double.isNaN(m_val))
@@ -447,5 +450,14 @@
   {
     return true;
   }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	visitor.visitNumberLiteral(owner, this);
+  }
+
 
 }
diff --git a/src/org/apache/xpath/objects/XObject.java b/src/org/apache/xpath/objects/XObject.java
index 13a42b6..2a91dcb 100644
--- a/src/org/apache/xpath/objects/XObject.java
+++ b/src/org/apache/xpath/objects/XObject.java
@@ -66,9 +66,11 @@
 import java.io.Serializable;
 
 import org.apache.xpath.res.XPATHErrorResources;
+import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.NodeSetDTM;
 import org.apache.xpath.XPathException;
+import org.apache.xpath.XPathVisitor;
 import org.apache.xalan.res.XSLMessages;
 import org.apache.xpath.Expression;
 import org.apache.xml.utils.XMLString;
@@ -122,6 +124,10 @@
 
   /**
    * Specify if it's OK for detach to release the iterator for reuse.
+   * This function should be called with a value of false for objects that are 
+   * stored in variables.
+   * Calling this with a value of false on a XNodeSet will cause the nodeset 
+   * to be cached.
    *
    * @param allowRelease true if it is OK for detach to release this iterator
    * for pooling.
@@ -152,6 +158,13 @@
       m_obj = null;
     }
   }
+  
+  /**
+   * Reset for fresh reuse.
+   */
+  public void reset()
+  {
+  }
 
   /**
    * Directly call the
@@ -387,7 +400,6 @@
   }
   
   
-  
   /**
    * For functions to override.
    *
@@ -436,6 +448,17 @@
   }
   
   /**
+   * Get a fresh copy of the object.  For use with variables.
+   *
+   * @return This object, unless overridden by subclass.
+   */
+  public XObject getFresh()
+  {
+    return this;
+  }
+
+  
+  /**
    * Cast result object to a nodelist. Always issues an error.
    *
    * @return null
@@ -739,4 +762,30 @@
   {
     fsb.append(str());
   }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	assertion(false, "callVisitors should not be called for this object!!!");
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	// If equals at the expression level calls deepEquals, I think we're 
+  	// still safe from infinite recursion since this object overrides 
+  	// equals.  I hope.
+  	if(!this.equals((XObject)expr))
+  		return false;
+  		
+  	return true;
+  }
+
 }
diff --git a/src/org/apache/xpath/objects/XRTreeFrag.java b/src/org/apache/xpath/objects/XRTreeFrag.java
index 4d5fec9..e45742a 100644
--- a/src/org/apache/xpath/objects/XRTreeFrag.java
+++ b/src/org/apache/xpath/objects/XRTreeFrag.java
@@ -78,7 +78,7 @@
   DTM m_dtm;
   int m_dtmRoot;
   XPathContext m_xctxt;
-  boolean m_allowRelease = true;
+  boolean m_allowRelease = false;
 
 //  /**
 //   * Create an XRTreeFrag Object.
diff --git a/src/org/apache/xpath/objects/XRTreeFragSelectWrapper.java b/src/org/apache/xpath/objects/XRTreeFragSelectWrapper.java
index 0c82d5b..f5af9e0 100644
--- a/src/org/apache/xpath/objects/XRTreeFragSelectWrapper.java
+++ b/src/org/apache/xpath/objects/XRTreeFragSelectWrapper.java
@@ -53,8 +53,9 @@
   {
     try
     {
+      m_selected = ((Expression)m_obj).execute(xctxt);
+      m_selected.allowDetachToRelease(m_allowRelease);
       XRTreeFragSelectWrapper xrtf = (XRTreeFragSelectWrapper)this.clone();
-      xrtf.m_selected = ((Expression)m_obj).execute(xctxt);
       return xrtf;
     }
     catch(CloneNotSupportedException cnse)
@@ -65,6 +66,26 @@
   }
   
   /**
+   * Detaches the <code>DTMIterator</code> from the set which it iterated
+   * over, releasing any computational resources and placing the iterator
+   * in the INVALID state. After <code>detach</code> has been invoked,
+   * calls to <code>nextNode</code> or <code>previousNode</code> will
+   * raise a runtime exception.
+   * 
+   * In general, detach should only be called once on the object.
+   */
+  public void detach()
+  {
+    if(m_allowRelease)
+    {
+      m_selected.detach();
+      m_selected = null;
+    }
+    
+    super.detach();
+  }
+  
+  /**
    * Cast result object to a number.
    *
    * @return The result tree fragment as a number or NaN
diff --git a/src/org/apache/xpath/objects/XString.java b/src/org/apache/xpath/objects/XString.java
index 0a3618a..a4ef4ac 100644
--- a/src/org/apache/xpath/objects/XString.java
+++ b/src/org/apache/xpath/objects/XString.java
@@ -57,16 +57,18 @@
 package org.apache.xpath.objects;
 
 //import org.w3c.dom.*;
+import java.util.Locale;
+
 import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xpath.XPathContext;
+import org.apache.xml.utils.XMLCharacterRecognizer;
 import org.apache.xml.utils.XMLString;
 import org.apache.xml.utils.XMLStringFactory;
-import org.apache.xml.utils.XMLCharacterRecognizer;
-import org.apache.xml.utils.FastStringBuffer;
-
-import java.util.Locale;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 
 /**
  * <meta name="usage" content="general"/>
@@ -397,7 +399,8 @@
     // In order to handle the 'all' semantics of 
     // nodeset comparisons, we always call the 
     // nodeset function.
-    if (obj2.getType() == XObject.CLASS_NODESET)
+    int t = obj2.getType();
+    if ((XObject.CLASS_NODESET == t) || (XObject.CLASS_NUMBER == t) )
       return obj2.equals(this);
 
     return str().equals(obj2.str());
@@ -453,6 +456,8 @@
       // nodeset function.
     else if (obj2 instanceof XNodeSet)
       return obj2.equals(this);
+    else if(obj2 instanceof XNumber)
+    	return obj2.equals(this);
     else
       return str().equals(obj2.toString());
   }
@@ -1178,4 +1183,13 @@
 
     return edit ? xsf.newstr(new String(buf, start, d - start)) : this;
   }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	visitor.visitStringLiteral(owner, this);
+  }
+
 }
diff --git a/src/org/apache/xpath/objects/XStringForFSB.java b/src/org/apache/xpath/objects/XStringForFSB.java
index e009dab..f2eb872 100644
--- a/src/org/apache/xpath/objects/XStringForFSB.java
+++ b/src/org/apache/xpath/objects/XStringForFSB.java
@@ -371,6 +371,8 @@
     {
       return true;
     }
+    if(obj2.getType() == XObject.CLASS_NUMBER)
+    	return obj2.equals(this);
 
     String str = obj2.str();
     int n = m_length;
@@ -457,6 +459,9 @@
 
     if (null == obj2)
       return false;
+      
+    if(obj2 instanceof XNumber)
+    	return obj2.equals(this);
 
       // In order to handle the 'all' semantics of 
       // nodeset comparisons, we always call the 
diff --git a/src/org/apache/xpath/operations/Bool.java b/src/org/apache/xpath/operations/Bool.java
index f4fecf4..fbde925 100644
--- a/src/org/apache/xpath/operations/Bool.java
+++ b/src/org/apache/xpath/operations/Bool.java
@@ -56,6 +56,8 @@
  */
 package org.apache.xpath.operations;
 
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathVisitor;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.objects.XBoolean;
 import org.apache.xpath.XPathContext;
diff --git a/src/org/apache/xpath/operations/Equals.java b/src/org/apache/xpath/operations/Equals.java
index b302ca9..ca5250b 100644
--- a/src/org/apache/xpath/operations/Equals.java
+++ b/src/org/apache/xpath/operations/Equals.java
@@ -56,8 +56,10 @@
  */
 package org.apache.xpath.operations;
 
-import org.apache.xpath.objects.XObject;
+import javax.xml.transform.TransformerException;
+import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.XBoolean;
+import org.apache.xpath.objects.XObject;
 
 /**
  * The '=' operation expression executer.
@@ -81,4 +83,28 @@
   {
     return left.equals(right) ? XBoolean.S_TRUE : XBoolean.S_FALSE;
   }
+  
+  /**
+   * Execute a binary operation by calling execute on each of the operands,
+   * and then calling the operate method on the derived class.
+   *
+   *
+   * @param xctxt The runtime execution context.
+   *
+   * @return The XObject result of the operation.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public boolean bool(XPathContext xctxt)
+          throws javax.xml.transform.TransformerException
+  {
+    XObject left = m_left.execute(xctxt, true);
+    XObject right = m_right.execute(xctxt, true);
+
+    boolean result = left.equals(right) ? true : false;
+	left.detach();
+	right.detach();
+    return result;
+  }
+
 }
diff --git a/src/org/apache/xpath/operations/Operation.java b/src/org/apache/xpath/operations/Operation.java
index a2ef870..9a04b4f 100644
--- a/src/org/apache/xpath/operations/Operation.java
+++ b/src/org/apache/xpath/operations/Operation.java
@@ -56,17 +56,19 @@
  */
 package org.apache.xpath.operations;
 
-import org.apache.xpath.Expression;
-import org.apache.xpath.XPath;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
+import java.util.Vector;
 
-import org.w3c.dom.Node;
+import javax.xml.transform.TransformerException;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.XObject;
 
 /**
  * The baseclass for a binary operation.
  */
-public class Operation extends Expression
+public class Operation extends Expression implements ExpressionOwner
 {
 
   /** The left operand expression.
@@ -123,6 +125,8 @@
   {
     m_left = l;
     m_right = r;
+    l.exprSetParent(this);
+    r.exprSetParent(this);
   }
 
   /**
@@ -140,10 +144,13 @@
           throws javax.xml.transform.TransformerException
   {
 
-    XObject left = m_left.execute(xctxt);
-    XObject right = m_right.execute(xctxt);
+    XObject left = m_left.execute(xctxt, true);
+    XObject right = m_right.execute(xctxt, true);
 
-    return operate(left, right);
+    XObject result = operate(left, right);
+    left.detach();
+    right.detach();
+    return result;
   }
 
   /**
@@ -174,5 +181,70 @@
   public Expression getRightOperand(){
     return m_right;
   }
+  
+  class LeftExprOwner implements ExpressionOwner
+  {
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_left;
+    }
 
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(Operation.this);
+    	m_left = exp;
+    }
+  }
+
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	if(visitor.visitBinaryOperation(owner, this))
+  	{
+  		m_left.callVisitors(new LeftExprOwner(), visitor);
+  		m_right.callVisitors(this, visitor);
+  	}
+  }
+
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_right;
+  }
+
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+  	exp.exprSetParent(this);
+  	m_right = exp;
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	if(!m_left.deepEquals(((Operation)expr).m_left))
+  		return false;
+  		
+  	if(!m_right.deepEquals(((Operation)expr).m_right))
+  		return false;
+  		
+  	return true;
+  }
 }
diff --git a/src/org/apache/xpath/operations/UnaryOperation.java b/src/org/apache/xpath/operations/UnaryOperation.java
index 0e80edc..19a67f7 100644
--- a/src/org/apache/xpath/operations/UnaryOperation.java
+++ b/src/org/apache/xpath/operations/UnaryOperation.java
@@ -56,17 +56,19 @@
  */
 package org.apache.xpath.operations;
 
-import org.apache.xpath.Expression;
-import org.apache.xpath.XPath;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
+import java.util.Vector;
 
-import org.w3c.dom.Node;
+import javax.xml.transform.TransformerException;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.objects.XObject;
 
 /**
  * The unary operation base class.
  */
-public abstract class UnaryOperation extends Expression
+public abstract class UnaryOperation extends Expression implements ExpressionOwner
 {
 
   /** The operand for the operation.
@@ -113,6 +115,7 @@
   public void setRight(Expression r)
   {
     m_right = r;
+    r.exprSetParent(this);
   }
 
   /**
@@ -150,5 +153,49 @@
   public Expression getOperand(){
     return m_right;
   }
+  
+  /**
+   * @see XPathVisitable#callVisitors(XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	if(visitor.visitUnaryOperation(owner, this))
+  	{
+  		m_right.callVisitors(this, visitor);
+  	}
+  }
+
+
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_right;
+  }
+
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+  	exp.exprSetParent(this);
+  	m_right = exp;
+  }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	if(!m_right.deepEquals(((UnaryOperation)expr).m_right))
+  		return false;
+  		
+  	return true;
+  }
+
 
 }
diff --git a/src/org/apache/xpath/operations/Variable.java b/src/org/apache/xpath/operations/Variable.java
index fbb6872..e1f9892 100644
--- a/src/org/apache/xpath/operations/Variable.java
+++ b/src/org/apache/xpath/operations/Variable.java
@@ -56,24 +56,34 @@
  */
 package org.apache.xpath.operations;
 
-import javax.xml.transform.TransformerException;
+import java.util.Vector;
 
+import javax.xml.transform.TransformerException;
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xalan.templates.ElemTemplateElement;
+import org.apache.xalan.templates.ElemVariable;
+import org.apache.xalan.templates.Stylesheet;
+import org.apache.xml.utils.PrefixResolver;
 import org.apache.xml.utils.QName;
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionNode;
+import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.axes.PathComponent;
+import org.apache.xpath.axes.WalkerFactory;
 import org.apache.xpath.objects.XNodeSet;
-
-import org.w3c.dom.Node;
-
+import org.apache.xpath.objects.XObject;
 import org.apache.xpath.res.XPATHErrorResources;
-import org.apache.xalan.res.XSLMessages;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
 
 /**
  * The variable reference expression executer.
  */
-public class Variable extends Expression
+public class Variable extends Expression implements PathComponent
 {
   /** Tell if fixupVariables was called.
    *  @serial   */
@@ -90,6 +100,51 @@
    */
   protected int m_index;
   
+  /**
+   * Set the index for the variable into the stack.  For advanced use only. You 
+   * must know what you are doing to use this.
+   * 
+   * @param index a global or local index.
+   */
+  public void setIndex(int index)
+  {
+  	m_index = index;
+  }
+  
+  /**
+   * Set the index for the variable into the stack.  For advanced use only.
+   * 
+   * @return index a global or local index.
+   */
+  public int getIndex()
+  {
+  	return m_index;
+  }
+  
+  /**
+   * Set whether or not this is a global reference.  For advanced use only.
+   * 
+   * @param isGlobal true if this should be a global variable reference.
+   */
+  public void setIsGlobal(boolean isGlobal)
+  {
+  	m_isGlobal = isGlobal;
+  }
+  
+  /**
+   * Set the index for the variable into the stack.  For advanced use only.
+   * 
+   * @return true if this should be a global variable reference.
+   */
+  public boolean getGlobal()
+  {
+  	return m_isGlobal;
+  }
+
+  
+  
+
+  
   protected boolean m_isGlobal = false;
   
   /**
@@ -106,6 +161,7 @@
   {
     m_fixUpWasCalled = true;
     int sz = vars.size();
+
     for (int i = vars.size()-1; i >= 0; i--) 
     {
       QName qn = (QName)vars.elementAt(i);
@@ -126,10 +182,11 @@
         return;
       }
     }
+    
     java.lang.String msg = XSLMessages.createXPATHMessage(XPATHErrorResources.ER_COULD_NOT_FIND_VAR, 
                                              new Object[]{m_qname.toString()});
                                              
-    TransformerException te = new TransformerException(msg, m_slocator);
+    TransformerException te = new TransformerException(msg, this);
                                              
     throw new org.apache.xml.utils.WrappedRuntimeException(te);
     
@@ -145,6 +202,35 @@
   {
     m_qname = qname;
   }
+  
+  /**
+   * Get the qualified name of the variable.
+   *
+   * @return A non-null reference to a qualified name.
+   */
+  public QName getQName()
+  {
+    return m_qname;
+  }
+  
+  /**
+   * Execute an expression in the XPath runtime context, and return the
+   * result of the expression.
+   *
+   *
+   * @param xctxt The XPath runtime context.
+   *
+   * @return The result of the expression in the form of a <code>XObject</code>.
+   *
+   * @throws javax.xml.transform.TransformerException if a runtime exception
+   *         occurs.
+   */
+  public XObject execute(XPathContext xctxt)
+    throws javax.xml.transform.TransformerException
+  {
+  	return execute(xctxt, false);
+  }
+
 
   /**
    * Dereference the variable, and return the reference value.  Note that lazy 
@@ -158,8 +244,9 @@
    *
    * @throws javax.xml.transform.TransformerException
    */
-  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+  public XObject execute(XPathContext xctxt, boolean destructiveOK) throws javax.xml.transform.TransformerException
   {
+  	org.apache.xml.utils.PrefixResolver xprefixResolver = xctxt.getNamespaceContext();
 
     // Is the variable fetched always the same?
     // XObject result = xctxt.getVariable(m_qname);
@@ -167,9 +254,9 @@
     {    
       XObject result;
       if(m_isGlobal)
-        result = xctxt.getVarStack().getGlobalVariable(xctxt, m_index);
+        result = xctxt.getVarStack().getGlobalVariable(xctxt, m_index, destructiveOK);
       else
-        result = xctxt.getVarStack().getLocalVariable(xctxt, m_index);
+        result = xctxt.getVarStack().getLocalVariable(xctxt, m_index, destructiveOK);
   
       if (null == result)
       {
@@ -191,63 +278,77 @@
       // pending some bright light going off in my head.  Some sort of callback?
       synchronized(this)
       {
-        org.apache.xml.utils.PrefixResolver prefixResolver = xctxt.getNamespaceContext();
-
-        // Get the current ElemTemplateElement, which must be pushed in as the 
-        // prefix resolver, and then walk backwards in document order, searching 
-        // for an xsl:param element or xsl:variable element that matches our 
-        // qname.  If we reach the top level, use the StylesheetRoot's composed
-        // list of top level variables and parameters.
-
-        if (prefixResolver instanceof org.apache.xalan.templates.ElemTemplateElement)
-        {
-
-          org.apache.xalan.templates.ElemVariable vvar;
-
-          org.apache.xalan.templates.ElemTemplateElement prev = 
-            (org.apache.xalan.templates.ElemTemplateElement) prefixResolver;
-
-          if (!(prev instanceof org.apache.xalan.templates.Stylesheet))
-          {            
-            while ( !(prev.getParentNode() instanceof org.apache.xalan.templates.Stylesheet) )
-            {
-              org.apache.xalan.templates.ElemTemplateElement savedprev = prev;
-
-              while (null != (prev = prev.getPreviousSiblingElem()))
-              {
-                if(prev instanceof org.apache.xalan.templates.ElemVariable)
-                {
-                  vvar = (org.apache.xalan.templates.ElemVariable) prev;
-                
-                  if (vvar.getName().equals(m_qname))
-                  {
-                    m_index = vvar.getIndex();
-                    m_isGlobal = false;
-                    m_fixUpWasCalled = true;
-                    return execute(xctxt);
-                  }
-                }
-              }
-              prev = savedprev.getParentElem();
-            }
-          }
-
-          vvar = prev.getStylesheetRoot().getVariableOrParamComposed(m_qname);
-          if (null != vvar)
-          {
-            m_index = vvar.getIndex();
-            m_isGlobal = true;
-            m_fixUpWasCalled = true;
-            return execute(xctxt);
-          }
-
-        }
+      	org.apache.xalan.templates.ElemVariable vvar= getElemVariable();
+      	if(null != vvar)
+      	{
+          m_index = vvar.getIndex();
+          m_isGlobal = vvar.getIsTopLevel();
+          m_fixUpWasCalled = true;
+          return execute(xctxt);
+      	}
       }
       throw new javax.xml.transform.TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{m_qname.toString()})); //"Variable not resolvable: "+m_qname);
     }
   }
   
   /**
+   * Get the XSLT ElemVariable that this sub-expression references.  In order for 
+   * this to work, the SourceLocator must be the owning ElemTemplateElement.
+   * @return The dereference to the ElemVariable, or null if not found.
+   */
+  public org.apache.xalan.templates.ElemVariable getElemVariable()
+  {
+  	
+    // Get the current ElemTemplateElement, and then walk backwards in 
+    // document order, searching 
+    // for an xsl:param element or xsl:variable element that matches our 
+    // qname.  If we reach the top level, use the StylesheetRoot's composed
+    // list of top level variables and parameters.
+    
+    org.apache.xpath.ExpressionNode owner = getExpressionOwner();
+
+    if (null != owner && owner instanceof org.apache.xalan.templates.ElemTemplateElement)
+    {
+
+      org.apache.xalan.templates.ElemVariable vvar;
+
+      org.apache.xalan.templates.ElemTemplateElement prev = 
+        (org.apache.xalan.templates.ElemTemplateElement) owner;
+
+      if (!(prev instanceof org.apache.xalan.templates.Stylesheet))
+      {            
+        while ( !(prev.getParentNode() instanceof org.apache.xalan.templates.Stylesheet) )
+        {
+          org.apache.xalan.templates.ElemTemplateElement savedprev = prev;
+
+          while (null != (prev = prev.getPreviousSiblingElem()))
+          {
+            if(prev instanceof org.apache.xalan.templates.ElemVariable)
+            {
+              vvar = (org.apache.xalan.templates.ElemVariable) prev;
+            
+              if (vvar.getName().equals(m_qname))
+              {
+                return vvar;
+              }
+            }
+          }
+          prev = savedprev.getParentElem();
+        }
+      }
+
+      vvar = prev.getStylesheetRoot().getVariableOrParamComposed(m_qname);
+      if (null != vvar)
+      {
+        return vvar;;
+      }
+
+    }
+    return null;
+
+  }
+  
+  /**
    * Tell if this expression returns a stable number that will not change during 
    * iterations within the expression.  This is used to determine if a proximity 
    * position predicate can indicate that no more searching has to occur.
@@ -259,5 +360,73 @@
   {
     return true;
   }
+  
+  /** 
+   * Get the analysis bits for this walker, as defined in the WalkerFactory.
+   * @return One of WalkerFactory#BIT_DESCENDANT, etc.
+   */
+  public int getAnalysisBits()
+  {
+  	org.apache.xalan.templates.ElemVariable vvar = getElemVariable();
+  	if(null != vvar)
+  	{
+  		XPath xpath = vvar.getSelect();
+  		if(null != xpath)
+  		{
+	  		Expression expr = xpath.getExpression();
+	  		if(null != expr && expr instanceof PathComponent)
+	  		{
+	  			return ((PathComponent)expr).getAnalysisBits();
+	  		}
+  		}
+  	}
+    return WalkerFactory.BIT_FILTER;
+  }
+
+
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	visitor.visitVariableRef(owner, this);
+  }
+
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	if(!m_qname.equals(((Variable)expr).m_qname))
+  		return false;
+  		
+  	// We have to make sure that the qname really references 
+  	// the same variable element.
+    if(getElemVariable() != ((Variable)expr).getElemVariable())
+    	return false;
+  		
+  	return true;
+  }
+  
+  static final java.lang.String PSUEDOVARNAMESPACE = "http://xml.apache.org/xalan/psuedovar";
+  
+  /**
+   * Tell if this is a psuedo variable reference, declared by Xalan instead 
+   * of by the user.
+   */
+  public boolean isPsuedoVarRef()
+  {
+  	java.lang.String ns = m_qname.getNamespaceURI();
+  	if((null != ns) && ns.equals(PSUEDOVARNAMESPACE))
+  	{
+  		if(m_qname.getLocalName().startsWith("#"))
+  			return true;
+  	}
+  	return false;
+  }
+  
 
 }
diff --git a/src/org/apache/xpath/operations/VariableSafeAbsRef.java b/src/org/apache/xpath/operations/VariableSafeAbsRef.java
new file mode 100644
index 0000000..0481956
--- /dev/null
+++ b/src/org/apache/xpath/operations/VariableSafeAbsRef.java
@@ -0,0 +1,56 @@
+package org.apache.xpath.operations;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+
+
+/**
+ * This is a "smart" variable reference that is used in situations where 
+ * an absolute path is optimized into a variable reference, but may 
+ * be used in some situations where the document context may have changed.
+ * For instance, in select="document(doc/@href)//name[//salary &gt; 7250]", the 
+ * root in the predicate will be different for each node in the set.  While 
+ * this is easy to detect statically in this case, in other cases static 
+ * detection would be very hard or impossible.  So, this class does a dynamic check 
+ * to make sure the document context of the referenced variable is the same as 
+ * the current document context, and, if it is not, execute the referenced variable's 
+ * expression with the current context instead.
+ */
+public class VariableSafeAbsRef extends Variable
+{
+	
+  /**
+   * Dereference the variable, and return the reference value.  Note that lazy 
+   * evaluation will occur.  If a variable within scope is not found, a warning 
+   * will be sent to the error listener, and an empty nodeset will be returned.
+   *
+   *
+   * @param xctxt The runtime execution context.
+   *
+   * @return The evaluated variable, or an empty nodeset if not found.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public XObject execute(XPathContext xctxt, boolean destructiveOK) 
+  	throws javax.xml.transform.TransformerException
+  {
+  	XNodeSet xns = (XNodeSet)super.execute(xctxt, destructiveOK);
+  	DTMManager dtmMgr = xctxt.getDTMManager();
+  	int context = xctxt.getContextNode();
+  	if(dtmMgr.getDTM(xns.getRoot()).getDocument() != 
+  	   dtmMgr.getDTM(context).getDocument())
+  	{
+  		Expression expr = (Expression)xns.getContainedIter();
+  		xns = (XNodeSet)expr.asIterator(xctxt, context);
+  	}
+  	return xns;
+  }
+
+}
+
diff --git a/src/org/apache/xpath/patterns/FunctionPattern.java b/src/org/apache/xpath/patterns/FunctionPattern.java
index 3e9f0c6..ffbffba 100644
--- a/src/org/apache/xpath/patterns/FunctionPattern.java
+++ b/src/org/apache/xpath/patterns/FunctionPattern.java
@@ -56,14 +56,18 @@
  */
 package org.apache.xpath.patterns;
 
-import org.apache.xpath.XPath;
-import org.apache.xpath.Expression;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XNumber;
-import org.apache.xpath.objects.XObject;
+import java.util.Vector;
+
+import javax.xml.transform.TransformerException;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.Axis;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.XNumber;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.patterns.StepPattern.PredOwner;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -252,4 +256,35 @@
 
     return score;
   }
+  
+  class FunctionOwner implements ExpressionOwner
+  {
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_functionExpr;
+    }
+
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(FunctionPattern.this);
+    	m_functionExpr = exp;
+    }
+  }
+  
+  /**
+   * Call the visitor for the function.
+   */
+  protected void callSubtreeVisitors(XPathVisitor visitor)
+  {
+    m_functionExpr.callVisitors(new FunctionOwner(), visitor);
+    super.callSubtreeVisitors(visitor);
+  }
+
 }
diff --git a/src/org/apache/xpath/patterns/NodeTest.java b/src/org/apache/xpath/patterns/NodeTest.java
index 96c8104..d82b1f4 100644
--- a/src/org/apache/xpath/patterns/NodeTest.java
+++ b/src/org/apache/xpath/patterns/NodeTest.java
@@ -56,17 +56,19 @@
  */
 package org.apache.xpath.patterns;
 
-import org.apache.xpath.compiler.OpCodes;
-import org.apache.xpath.XPath;
+import java.util.Vector;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMFilter;
+import org.apache.xml.dtm.ref.ExpandedNameTable;
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
-import org.apache.xpath.WhitespaceStrippingElementMatcher;
-import org.apache.xml.utils.PrefixResolver;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.ref.ExpandedNameTable;
 
 /**
  * <meta name="usage" content="advanced"/>
@@ -248,6 +250,45 @@
   {
     initNodeTest(whatToShow);
   }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	NodeTest nt = (NodeTest)expr;
+
+  	if(null != nt.m_name)
+  	{
+  		if(null == m_name)
+  			return false;
+  		else if(!nt.m_name.equals(m_name))
+  			return false;
+  	}
+  	else if(null != m_name)
+  		return false;
+
+  	if(null != nt.m_namespace)
+  	{
+  		if(null == m_namespace)
+  			return false;
+  		else if(!nt.m_namespace.equals(m_namespace))
+  			return false;
+  	}
+  	else if(null != m_namespace)
+  		return false;
+  		  		
+  	if(m_whatToShow != nt.m_whatToShow)
+  		return false;
+  		
+  	if(m_isTotallyWild != nt.m_isTotallyWild)
+  		return false;
+
+	return true;
+  }
 
   /**
    * Null argument constructor.
@@ -679,4 +720,12 @@
     // no-op
   }
 
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	assertion(false, "callVisitors should not be called for this object!!!");  	
+  }
+
 }
diff --git a/src/org/apache/xpath/patterns/StepPattern.java b/src/org/apache/xpath/patterns/StepPattern.java
index 2e8cd74..6dc4244 100644
--- a/src/org/apache/xpath/patterns/StepPattern.java
+++ b/src/org/apache/xpath/patterns/StepPattern.java
@@ -56,22 +56,26 @@
  */
 package org.apache.xpath.patterns;
 
+import java.util.Vector;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.Axis;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMAxisTraverser;
+import org.apache.xml.dtm.DTMFilter;
 import org.apache.xpath.Expression;
-import org.apache.xpath.objects.XObject;
+import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPathContext;
-import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.XPathVisitor;
 import org.apache.xpath.axes.SubContextList;
 import org.apache.xpath.compiler.PsuedoNames;
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMFilter;
-import org.apache.xml.dtm.DTMAxisTraverser;
-import org.apache.xml.dtm.Axis;
+import org.apache.xpath.objects.XObject;
 
 /**
  * <meta name="usage" content="advanced"/>
  * This class represents a single pattern match step.
  */
-public class StepPattern extends NodeTest implements SubContextList
+public class StepPattern extends NodeTest implements SubContextList, ExpressionOwner
 {
 
   /** The axis for this test. */
@@ -219,6 +223,7 @@
   {
 
     m_relativePathPattern = expr;
+    expr.exprSetParent(this);
 
     calcScore();
   }
@@ -317,6 +322,13 @@
   {
 
     m_predicates = predicates;
+    if(null != predicates)
+    {
+    	for(int i = 0; i < predicates.length; i++)
+    	{
+    		predicates[i].exprSetParent(this);
+    	}
+    }
 
     calcScore();
   }
@@ -958,5 +970,122 @@
   {
     return m_axis;
   }
+  
+  class PredOwner implements ExpressionOwner
+  {
+  	int m_index;
+  	
+  	PredOwner(int index)
+  	{
+  		m_index = index;
+  	}
+  	
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_predicates[m_index];
+    }
+
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(StepPattern.this);
+    	m_predicates[m_index] = exp;
+    }
+  }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	 	if(visitor.visitMatchPattern(owner, this))
+  	 	{
+  	 		callSubtreeVisitors(visitor);
+  	 	}
+  }
+
+  /**
+   * Call the visitors on the subtree.  Factored out from callVisitors 
+   * so it may be called by derived classes.
+   */
+  protected void callSubtreeVisitors(XPathVisitor visitor)
+  {
+    if (null != m_predicates)
+    {
+      int n = m_predicates.length;
+      for (int i = 0; i < n; i++)
+      {
+        ExpressionOwner predOwner = new PredOwner(i);
+        if (visitor.visitPredicate(predOwner, m_predicates[i]))
+        {
+          m_predicates[i].callVisitors(predOwner, visitor);
+        }
+      }
+    }
+    if (null != m_relativePathPattern)
+    {
+      m_relativePathPattern.callVisitors(this, visitor);
+    }
+  }
+
+
+  /**
+   * @see ExpressionOwner#getExpression()
+   */
+  public Expression getExpression()
+  {
+    return m_relativePathPattern;
+  }
+
+  /**
+   * @see ExpressionOwner#setExpression(Expression)
+   */
+  public void setExpression(Expression exp)
+  {
+    exp.exprSetParent(this);
+  	m_relativePathPattern = (StepPattern)exp;
+  }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!super.deepEquals(expr))
+  		return false;
+  		
+  	StepPattern sp = (StepPattern)expr;
+  	
+    if (null != m_predicates)
+    {
+        int n = m_predicates.length;
+        if ((null == sp.m_predicates) || (sp.m_predicates.length != n))
+              return false;
+        for (int i = 0; i < n; i++)
+        {
+          if (!m_predicates[i].deepEquals(sp.m_predicates[i]))
+          	return false; 
+        }
+    }
+    else if (null != sp.m_predicates)
+    	return false;
+  		
+  	if(null != m_relativePathPattern)
+  	{
+  		if(!m_relativePathPattern.deepEquals(sp.m_relativePathPattern))
+  			return false;
+  	}
+  	else if(sp.m_relativePathPattern != null)
+  		return false;
+  		
+  	return true;
+  }
+
 
 }
diff --git a/src/org/apache/xpath/patterns/UnionPattern.java b/src/org/apache/xpath/patterns/UnionPattern.java
index 67323d2..dac9456 100644
--- a/src/org/apache/xpath/patterns/UnionPattern.java
+++ b/src/org/apache/xpath/patterns/UnionPattern.java
@@ -56,8 +56,13 @@
  */
 package org.apache.xpath.patterns;
 
+import java.util.Vector;
+
+import javax.xml.transform.TransformerException;
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
 import org.apache.xpath.objects.XObject;
 
 /**
@@ -113,6 +118,14 @@
   public void setPatterns(StepPattern[] patterns)
   {
     m_patterns = patterns;
+    if(null != patterns)
+    {
+    	for(int i = 0; i < patterns.length; i++)
+    	{
+    		patterns[i].exprSetParent(this);
+    	}
+    }
+    
   }
 
   /**
@@ -165,4 +178,79 @@
 
     return bestScore;
   }
+  
+  class UnionPathPartOwner implements ExpressionOwner
+  {
+  	int m_index;
+  	
+  	UnionPathPartOwner(int index)
+  	{
+  		m_index = index;
+  	}
+  	
+    /**
+     * @see ExpressionOwner#getExpression()
+     */
+    public Expression getExpression()
+    {
+      return m_patterns[m_index];
+    }
+
+
+    /**
+     * @see ExpressionOwner#setExpression(Expression)
+     */
+    public void setExpression(Expression exp)
+    {
+    	exp.exprSetParent(UnionPattern.this);
+    	m_patterns[m_index] = (StepPattern)exp;
+    }
+  }
+  
+  /**
+   * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
+   */
+  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+  {
+  	visitor.visitUnionPattern(owner, this);
+  	if(null != m_patterns)
+  	{
+  		int n = m_patterns.length;
+  		for(int i = 0; i < n; i++)
+  		{
+  			m_patterns[i].callVisitors(new UnionPathPartOwner(i), visitor);
+  		}
+  	}
+  }
+  
+  /**
+   * @see Expression#deepEquals(Expression)
+   */
+  public boolean deepEquals(Expression expr)
+  {
+  	if(!isSameClass(expr))
+  		return false;
+  		
+  	UnionPattern up = (UnionPattern)expr;
+  		
+  	if(null != m_patterns)
+  	{
+  		int n = m_patterns.length;
+  		if((null == up.m_patterns) || (up.m_patterns.length != n))
+  			return false;
+  			
+  		for(int i = 0; i < n; i++)
+  		{
+  			if(!m_patterns[i].deepEquals(up.m_patterns[i]))
+  				return false;
+  		}
+  	}
+  	else if(up.m_patterns != null)
+  		return false;
+  		
+  	return true;
+  	
+  }
+
+
 }