You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by mu...@apache.org on 2023/06/09 14:02:10 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 range operation, along with few working related test cases

This is an automated email from the ASF dual-hosted git repository.

mukulg pushed a commit to branch xalan-j_xslt3.0
in repository https://gitbox.apache.org/repos/asf/xalan-java.git


The following commit(s) were added to refs/heads/xalan-j_xslt3.0 by this push:
     new 88457ebc committing implementation of xpath 3.1 range operation, along with few working related test cases
88457ebc is described below

commit 88457ebcc0996cc6e41c97007f30a841923034b5
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Jun 9 19:31:48 2023 +0530

    committing implementation of xpath 3.1 range operation, along with few working related test cases
---
 src/org/apache/xalan/templates/ElemChoose.java    |  73 +++++++++++--
 src/org/apache/xalan/templates/ElemForEach.java   |  15 +++
 src/org/apache/xalan/templates/ElemIf.java        |  12 ++-
 src/org/apache/xalan/templates/ElemValueOf.java   |  20 +++-
 src/org/apache/xml/dtm/DTMManager.java            |  63 ++++++++++--
 src/org/apache/xpath/compiler/Compiler.java       |  13 +++
 src/org/apache/xpath/compiler/OpCodes.java        |   5 +
 src/org/apache/xpath/compiler/XPathParser.java    |  19 +++-
 src/org/apache/xpath/operations/Range.java        |  71 +++++++++++++
 tests/org/apache/xalan/xpath3/RangeExprTests.java | 120 ++++++++++++++++++++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java    |   3 +-
 tests/range_expr/gold/test1.out                   |   7 ++
 tests/range_expr/gold/test2.out                   |  12 +++
 tests/range_expr/gold/test3.out                   |  12 +++
 tests/range_expr/gold/test4.out                   |  16 +++
 tests/range_expr/gold/test5.out                   |  22 ++++
 tests/range_expr/gold/test6.out                   |  26 +++++
 tests/range_expr/gold/test7.out                   |  26 +++++
 tests/range_expr/test1.xsl                        |  40 ++++++++
 tests/range_expr/test1_a.xml                      |   5 +
 tests/range_expr/test2.xsl                        |  45 ++++++++
 tests/range_expr/test3.xsl                        |  48 +++++++++
 tests/range_expr/test4.xsl                        |  60 +++++++++++
 tests/range_expr/test5.xsl                        |  50 +++++++++
 tests/range_expr/test6.xsl                        |  60 +++++++++++
 tests/range_expr/test7.xsl                        |  63 ++++++++++++
 26 files changed, 880 insertions(+), 26 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemChoose.java b/src/org/apache/xalan/templates/ElemChoose.java
index d243c94b..187e8a1a 100644
--- a/src/org/apache/xalan/templates/ElemChoose.java
+++ b/src/org/apache/xalan/templates/ElemChoose.java
@@ -24,18 +24,41 @@ import javax.xml.transform.TransformerException;
 
 import org.apache.xalan.res.XSLTErrorResources;
 import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMManager;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.xs.types.XSAnyType;
+
+/** 
+ * XSLT 3.0 xsl:choose element.
+ * 
+   <xsl:choose>
+      <!-- Content: (xsl:when+, xsl:otherwise?) -->
+   </xsl:choose>
+
+   <xsl:when
+          test = expression>
+       <!-- Content: sequence-constructor -->
+   </xsl:when>
+
+   <xsl:otherwise>
+      <!-- Content: sequence-constructor -->
+   </xsl:otherwise>
 
-/**
- * Implement xsl:choose.
- * <pre>
- * <!ELEMENT xsl:choose (xsl:when+, xsl:otherwise?)>
- * <!ATTLIST xsl:choose %space-att;>
- * </pre>
- * @see <a href="http://www.w3.org/TR/xslt#section-Conditional-Processing-with-xsl:choose">XXX in XSLT Specification</a>
  * @xsl.usage advanced
  */
+/*
+ *  Implementation of the XSLT 3.0 xsl:choose instruction.
+ *  
+ *  An XSLT xsl:choose instruction is used, to perform conditional processing.
+ *  
+ *  The xsl:choose element selects one among a number of possible alternatives. 
+ *  It consists of a sequence of one or more xsl:when elements followed by an 
+ *  optional xsl:otherwise element. Each xsl:when element has a single attribute, 
+ *  test, which specifies an expression. The content of the xsl:when and 
+ *  xsl:otherwise elements is a sequence constructor.
+ */
 public class ElemChoose extends ElemTemplateElement
 {
     static final long serialVersionUID = -3070117361903102033L;
@@ -123,12 +146,44 @@ public class ElemChoose extends ElemTemplateElement
           }
 
         }
-        else if (when.getTest().bool(xctxt, sourceNode, when))
+        /*else if (when.getTest().bool(xctxt, sourceNode, when))
         {
           transformer.executeChildTemplates(when, true);
 
           return;
-        }
+        }*/
+        else {
+            XObject xpath3ContextItem = xctxt.getXPath3ContextItem();        
+            if (xpath3ContextItem != null) {
+                XPathContext xctxtNew = new XPathContext(false);            
+                xctxtNew.setVarStack(xctxt.getVarStack());
+                
+                xctxtNew.setXPath3ContextPosition(xctxt.getXPath3ContextPosition());
+                xctxtNew.setXPath3ContextSize(xctxt.getXPath3ContextSize());
+                                  
+                DTMManager dtmMgr = xctxtNew.getDTMManager();
+                String strVal = "";
+                if (xpath3ContextItem instanceof XSAnyType) {
+                    strVal = ((XSAnyType)xpath3ContextItem).stringValue();     
+                }
+                else {
+                    strVal = xpath3ContextItem.str(); 
+                }
+                DTM docFragDtm = dtmMgr.createDTMForSimpleXMLDocument(strVal);
+          
+                int contextNode = docFragDtm.getFirstChild(docFragDtm.getDocument());            
+                xctxtNew.pushCurrentNode(contextNode);
+                xctxtNew.setSAXLocator(this);
+                if ((when.getTest()).bool(xctxtNew, contextNode, this)) {
+                    transformer.executeChildTemplates(when, true);
+                    return;
+                }  
+            }        
+            else if ((when.getTest()).bool(xctxt, sourceNode, this)) {
+               transformer.executeChildTemplates(when, true);
+               return;
+            }  
+        }        
       }
       else if (Constants.ELEMNAME_OTHERWISE == type)
       {
diff --git a/src/org/apache/xalan/templates/ElemForEach.java b/src/org/apache/xalan/templates/ElemForEach.java
index df4f3523..27d007b0 100644
--- a/src/org/apache/xalan/templates/ElemForEach.java
+++ b/src/org/apache/xalan/templates/ElemForEach.java
@@ -40,6 +40,7 @@ import org.apache.xpath.XPathContext;
 import org.apache.xpath.functions.Function;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.Operation;
 import org.apache.xpath.operations.Variable;
 
 /**
@@ -360,6 +361,15 @@ public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
         }
     }
     
+    if (m_selectExpression instanceof Operation) {
+        XObject  evalResult = m_selectExpression.execute(xctxt);
+        if (evalResult instanceof ResultSequence) {
+            processResultSequence(transformer, xctxt, evalResult);
+            transformer.setXPathContext(xctxtOriginal);
+            return;
+        }
+    }
+    
     // process the node-set, with body of xsl:for-each element as usual 
     final int sourceNode = xctxt.getCurrentNode();
     DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
@@ -585,6 +595,11 @@ public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
               elemTemplateElem.execute(transformer);              
            }
        }
+
+       // reset the, XPath context's size, item and position variables
+       xctxt.setXPath3ContextSize(-1);
+       xctxt.setXPath3ContextItem(null);
+       xctxt.setXPath3ContextPosition(-1);
    }
    
 }
diff --git a/src/org/apache/xalan/templates/ElemIf.java b/src/org/apache/xalan/templates/ElemIf.java
index 74b2226f..9bce512b 100644
--- a/src/org/apache/xalan/templates/ElemIf.java
+++ b/src/org/apache/xalan/templates/ElemIf.java
@@ -28,6 +28,7 @@ import org.apache.xml.dtm.DTMManager;
 import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.xs.types.XSAnyType;
 
 /**
  * The XSLT xsl:if element, is used to perform conditional processing,
@@ -171,8 +172,15 @@ public class ElemIf extends ElemTemplateElement
             xctxtNew.setXPath3ContextPosition(xctxt.getXPath3ContextPosition());
             xctxtNew.setXPath3ContextSize(xctxt.getXPath3ContextSize());
                               
-            DTMManager dtmMgr = xctxtNew.getDTMManager();            
-            DTM docFragDtm = dtmMgr.createDTMForSimpleXMLDocument(xpath3ContextItem.str());
+            DTMManager dtmMgr = xctxtNew.getDTMManager();
+            String strVal = "";
+            if (xpath3ContextItem instanceof XSAnyType) {
+                strVal = ((XSAnyType)xpath3ContextItem).stringValue();     
+            }
+            else {
+                strVal = xpath3ContextItem.str(); 
+            }
+            DTM docFragDtm = dtmMgr.createDTMForSimpleXMLDocument(strVal);
       
             int contextNode = docFragDtm.getFirstChild(docFragDtm.getDocument());            
             xctxtNew.pushCurrentNode(contextNode);
diff --git a/src/org/apache/xalan/templates/ElemValueOf.java b/src/org/apache/xalan/templates/ElemValueOf.java
index 66592d83..4824efad 100644
--- a/src/org/apache/xalan/templates/ElemValueOf.java
+++ b/src/org/apache/xalan/templates/ElemValueOf.java
@@ -277,12 +277,22 @@ public class ElemValueOf extends ElemTemplateElement {
           else
           {
               XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
-              if (m_isDot && xpath3ContextItem != null) {
-                  xpath3ContextItem.dispatchCharactersEvents(rth);   
+              if (m_isDot && xpath3ContextItem != null) {                  
+                  String strValue = null;
+                  
+                  if (xpath3ContextItem instanceof XSAnyType) {
+                      strValue = ((XSAnyType)xpath3ContextItem).stringValue();    
+                  }
+                  else {
+                      strValue = xpath3ContextItem.str();  
+                  }
+
+                  (new XString(strValue)).dispatchCharactersEvents(rth);
               }
               else {
                   if (expr instanceof FuncExtFunction) {                      
-                      XObject evalResult = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, expr);
+                      XObject evalResult = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn
+                                                                                              (xctxt, expr);
                       String strValue = null;
                       
                       if (evalResult instanceof XSAnyType) {
@@ -319,9 +329,9 @@ public class ElemValueOf extends ElemTemplateElement {
                   else if (expr instanceof Operation) {
                      Operation opn = (Operation)expr;
                      XObject leftOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                                                xctxt, opn.getLeftOperand());
+                                                                                         xctxt, opn.getLeftOperand());
                      XObject rightOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                                                xctxt, opn.getRightOperand());
+                                                                                         xctxt, opn.getRightOperand());
                      XObject evalResult = opn.operate(leftOperand, rightOperand);
                      
                      String strValue = null;
diff --git a/src/org/apache/xml/dtm/DTMManager.java b/src/org/apache/xml/dtm/DTMManager.java
index 4ad1169b..3a339bea 100644
--- a/src/org/apache/xml/dtm/DTMManager.java
+++ b/src/org/apache/xml/dtm/DTMManager.java
@@ -28,6 +28,9 @@ import org.apache.xml.res.XMLErrorResources;
 import org.apache.xml.res.XMLMessages;
 import org.apache.xml.utils.PrefixResolver;
 import org.apache.xml.utils.XMLStringFactory;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.xs.types.XSAnyType;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Text;
@@ -231,25 +234,71 @@ public abstract class DTMManager
     
          dbf.setNamespaceAware(true);
     
-         DocumentBuilder db = dbf.newDocumentBuilder();
-         Document doc = db.newDocument();
+         DocumentBuilder dBuilder = dbf.newDocumentBuilder();
+         Document document = dBuilder.newDocument();
          // we create a, temporary xml element name here. this xml 
          // element name, is unlikely to be present within the xml 
          // input document that is been transformed by an xslt 
          // stylesheet.
          long currentTimeMills = System.currentTimeMillis();
          String elemNameSuffix = (Long.valueOf(currentTimeMills)).toString();
-         Element elem = doc.createElement("t0_" + elemNameSuffix);
-         Text textNode = doc.createTextNode(strVal);
-         elem.appendChild(textNode);
-         doc.appendChild(elem);
+         Element documentElem = document.createElement("t0_" + elemNameSuffix);
+         Text textNode = document.createTextNode(strVal);
+         documentElem.appendChild(textNode);
+         document.appendChild(documentElem);
     
-         return getDTM(new DOMSource(doc), true, null, false, false);
+         return getDTM(new DOMSource(document), true, null, false, false);
       }
       catch (Exception ex) {
          throw new DTMException(ex);
       }
   }
+  
+  /*
+   * This method constructs a DTM object representing an XML document.
+   * The DTM object instance that is constructed by this method, represents
+   * a sequence of XML elements sourced from a 'ResultSequence' input object.
+   * 
+   * Notes : currently, this method is unused within XalanJ's XSLT 3.0 
+   *         implementation, but could possibly/likely be useful for 
+   *         future XalanJ functional implementation.
+   */
+  public DTM createDTMFromResultSequence(ResultSequence resultSeq) {
+      try {
+          DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+          
+          dbf.setNamespaceAware(true);
+     
+          DocumentBuilder dBuilder = dbf.newDocumentBuilder();
+          Document document = dBuilder.newDocument();
+          
+          long currentTimeMills = System.currentTimeMillis();
+          String elemNameSuffix = (Long.valueOf(currentTimeMills)).toString();
+          Element documentElem = document.createElement("t0_" + elemNameSuffix);          
+          for (int idx = 0; idx < resultSeq.size(); idx++) {
+              XObject obj1 = resultSeq.item(idx);
+              String strVal = null;
+              if (obj1 instanceof XSAnyType) {
+                  strVal = ((XSAnyType)obj1).stringValue();     
+              }
+              else {
+                  strVal = obj1.str();    
+              }
+              
+              Text textNode = document.createTextNode(strVal);
+              Element nTempElem = document.createElement("n0");
+              nTempElem.appendChild(textNode);
+              documentElem.appendChild(nTempElem);
+          }
+          
+          document.appendChild(documentElem);
+          
+          return getDTM(new DOMSource(document), true, null, false, false);
+      }
+      catch (Exception ex) {
+          throw new DTMException(ex);   
+      }
+  }
 
   /**
    * Release a DTM either to a lru pool, or completely remove reference.
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index 6b4193a6..0113fa77 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -55,6 +55,7 @@ import org.apache.xpath.operations.NotEquals;
 import org.apache.xpath.operations.Operation;
 import org.apache.xpath.operations.Or;
 import org.apache.xpath.operations.Plus;
+import org.apache.xpath.operations.Range;
 import org.apache.xpath.operations.UnaryOperation;
 import org.apache.xpath.operations.Variable;
 import org.apache.xpath.patterns.FunctionPattern;
@@ -140,6 +141,8 @@ public class Compiler extends OpMap
       expr = gt(opPos); break;
     case OpCodes.OP_PLUS :
       expr = plus(opPos); break;
+    case OpCodes.OP_TO :
+      expr = range(opPos); break;
     case OpCodes.OP_MINUS :
       expr = minus(opPos); break;
     case OpCodes.OP_MULT :
@@ -364,6 +367,16 @@ public class Compiler extends OpMap
   {
     return compileOperation(new Plus(), opPos);
   }
+  
+  /*
+   * Compile an XPath 3.1 "to" operation.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   */
+  protected Expression range(int opPos) throws TransformerException
+  {
+    return compileOperation(new Range(), opPos);   
+  }
 
   /**
    * Compile a '-' operation.
diff --git a/src/org/apache/xpath/compiler/OpCodes.java b/src/org/apache/xpath/compiler/OpCodes.java
index 8f402577..e8bdc2e3 100644
--- a/src/org/apache/xpath/compiler/OpCodes.java
+++ b/src/org/apache/xpath/compiler/OpCodes.java
@@ -626,6 +626,11 @@ public class OpCodes
 
   /** The end of the axes types.    */
   public static final int AXES_END_TYPES = 53;
+  
+  /*
+   * For XPath 3.1 "to" range expressions.
+   */
+  public static final int OP_TO = 54;
 
   /** The next free ID.  Please keep this up to date.  */
   private static final int NEXT_FREE_ID = 99;
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index ec989d3c..084c9a85 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -861,7 +861,7 @@ public class XPathParser
    */
   protected int EqualityExpr(int addPos) throws javax.xml.transform.TransformerException
   {
-
+      
     int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH);
 
     if (-1 == addPos)
@@ -911,7 +911,7 @@ public class XPathParser
    * | RelationalExpr '>' AdditiveExpr
    * | RelationalExpr '<=' AdditiveExpr
    * | RelationalExpr '>=' AdditiveExpr
-   *
+   * | RelationalExpr 'to' AdditiveExpr
    *
    * @param addPos Position where expression is to be added, or -1 for append.
    *
@@ -973,6 +973,21 @@ public class XPathParser
           m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen);
         addPos += 2;
       }
+      else if (tokenIs("to"))
+      {
+          // support for XPath 3.1 range expressions
+          
+          nextToken();
+          
+          insertOp(addPos, 2, OpCodes.OP_TO);
+          
+          int op1 = m_ops.getOp(OpMap.MAPINDEX_LENGTH) - addPos;
+          
+          addPos = AdditiveExpr(addPos);
+          m_ops.setOp(addPos + OpMap.MAPINDEX_LENGTH, 
+            m_ops.getOp(addPos + op1 + 1) + op1);
+          addPos += 2; 
+      }
     }
 
     return addPos;
diff --git a/src/org/apache/xpath/operations/Range.java b/src/org/apache/xpath/operations/Range.java
new file mode 100644
index 00000000..43139747
--- /dev/null
+++ b/src/org/apache/xpath/operations/Range.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the  "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id$
+ */
+package org.apache.xpath.operations;
+
+import java.math.BigInteger;
+
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.xs.types.XSInteger;
+
+/**
+ * The XPath 3.1 "to" range operation.
+ * 
+ * An XPath range expression can be used to construct a sequence of 
+ * consecutive integers. Each of the operands of the to operator 
+ * is converted as though it was an argument of a function with 
+ * the expected parameter type xs:integer.
+ */
+public class Range extends Operation
+{
+    
+   private static final long serialVersionUID = 7722428363208837859L;
+
+   /**
+   * Apply the operation to two operands, and return the result.
+   *
+   * @param left non-null reference to the evaluated left operand.
+   * @param right non-null reference to the evaluated right operand.
+   *
+   * @return non-null reference to the XObject that represents the result of the operation.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+    public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException {
+        
+      ResultSequence result = new ResultSequence();
+  
+      XObject expr1 = m_left.execute(xctxt);
+      
+      XObject expr2 = m_right.execute(xctxt);
+      
+      int fromIdx = (int)expr1.num();
+      int toIdx = (int)expr2.num();
+      
+      for (int idx = fromIdx; idx <= toIdx; idx++) {
+         result.add(new XSInteger(BigInteger.valueOf((long)idx)));    
+      }
+      
+      return result;
+    }
+
+}
diff --git a/tests/org/apache/xalan/xpath3/RangeExprTests.java b/tests/org/apache/xalan/xpath3/RangeExprTests.java
new file mode 100644
index 00000000..88435ccf
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/RangeExprTests.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xalan.xpath3;
+
+import org.apache.xalan.util.XslTransformTestsUtil;
+import org.apache.xalan.xslt3.XSLConstants;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XSLT 3.0 test cases, for using XPath 3.1 range expressions.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class RangeExprTests extends XslTransformTestsUtil {
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "range_expr/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "range_expr/gold/";
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        // no op
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() throws Exception {
+        xmlDocumentBuilderFactory = null;
+        xmlDocumentBuilder = null;
+        xslTransformerFactory = null;
+    }
+
+    @Test
+    public void xslRangeExprTest1() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslRangeExprTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslRangeExprTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslRangeExprTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslRangeExprTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslRangeExprTest6() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test6.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test6.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslRangeExprTest7() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test7.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+
+}
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index 6c68f421..870ffb84 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -21,6 +21,7 @@ import org.apache.xalan.xpath3.FnIndexOfTests;
 import org.apache.xalan.xpath3.FnStringJoinTests;
 import org.apache.xalan.xpath3.FnTokenizeTests;
 import org.apache.xalan.xpath3.FnUnparsedTextTests;
+import org.apache.xalan.xpath3.RangeExprTests;
 import org.apache.xalan.xpath3.SequenceTests;
 import org.apache.xalan.xpath3.StringTests;
 import org.apache.xalan.xpath3.XsConstructorFunctions;
@@ -45,7 +46,7 @@ import org.junit.runners.Suite.SuiteClasses;
                 GroupingWithSortTests.class, RtfMigrationTests.class, QuantifiedExprTests.class, 
                 FnUnparsedTextTests.class, FnTokenizeTests.class, FnStringJoinTests.class,
                 FnAbsTests.class, StringTests.class, XsConstructorFunctions.class, 
-                FnIndexOfTests.class, SequenceTests.class })
+                FnIndexOfTests.class, SequenceTests.class, RangeExprTests.class })
 public class AllXsl3Tests {
 
 }
diff --git a/tests/range_expr/gold/test1.out b/tests/range_expr/gold/test1.out
new file mode 100644
index 00000000..dbf19a7c
--- /dev/null
+++ b/tests/range_expr/gold/test1.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <even>2</even>
+  <even>4</even>
+  <even>6</even>
+  <even>8</even>
+  <even>10</even>
+</result>
diff --git a/tests/range_expr/gold/test2.out b/tests/range_expr/gold/test2.out
new file mode 100644
index 00000000..a78933ea
--- /dev/null
+++ b/tests/range_expr/gold/test2.out
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <odd>1</odd>
+  <even>2</even>
+  <odd>3</odd>
+  <even>4</even>
+  <odd>5</odd>
+  <even>6</even>
+  <odd>7</odd>
+  <even>8</even>
+  <odd>9</odd>
+  <even>10</even>
+</result>
diff --git a/tests/range_expr/gold/test3.out b/tests/range_expr/gold/test3.out
new file mode 100644
index 00000000..a78933ea
--- /dev/null
+++ b/tests/range_expr/gold/test3.out
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <odd>1</odd>
+  <even>2</even>
+  <odd>3</odd>
+  <even>4</even>
+  <odd>5</odd>
+  <even>6</even>
+  <odd>7</odd>
+  <even>8</even>
+  <odd>9</odd>
+  <even>10</even>
+</result>
diff --git a/tests/range_expr/gold/test4.out b/tests/range_expr/gold/test4.out
new file mode 100644
index 00000000..7ba78cc4
--- /dev/null
+++ b/tests/range_expr/gold/test4.out
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <grp numberClass="odd">
+    <num>1</num>
+    <num>3</num>
+    <num>5</num>
+    <num>7</num>
+    <num>9</num>
+  </grp>
+  <grp numberClass="even">
+    <num>2</num>
+    <num>4</num>
+    <num>6</num>
+    <num>8</num>
+    <num>10</num>
+  </grp>
+</result>
diff --git a/tests/range_expr/gold/test5.out b/tests/range_expr/gold/test5.out
new file mode 100644
index 00000000..990f97af
--- /dev/null
+++ b/tests/range_expr/gold/test5.out
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <odd>1</odd>
+  <even>2</even>
+  <odd>3</odd>
+  <even>4</even>
+  <odd>5</odd>
+  <even>6</even>
+  <odd>7</odd>
+  <even>8</even>
+  <odd>9</odd>
+  <even>10</even>
+  <odd>11</odd>
+  <even>12</even>
+  <odd>13</odd>
+  <even>14</even>
+  <odd>15</odd>
+  <even>16</even>
+  <odd>17</odd>
+  <even>18</even>
+  <odd>19</odd>
+  <even>20</even>
+</result>
diff --git a/tests/range_expr/gold/test6.out b/tests/range_expr/gold/test6.out
new file mode 100644
index 00000000..dc001554
--- /dev/null
+++ b/tests/range_expr/gold/test6.out
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <grp numberClass="odd">
+    <num>1</num>
+    <num>3</num>
+    <num>5</num>
+    <num>7</num>
+    <num>9</num>
+    <num>11</num>
+    <num>13</num>
+    <num>15</num>
+    <num>17</num>
+    <num>19</num>
+  </grp>
+  <grp numberClass="even">
+    <num>2</num>
+    <num>4</num>
+    <num>6</num>
+    <num>8</num>
+    <num>10</num>
+    <num>12</num>
+    <num>14</num>
+    <num>16</num>
+    <num>18</num>
+    <num>20</num>
+  </grp>
+</result>
diff --git a/tests/range_expr/gold/test7.out b/tests/range_expr/gold/test7.out
new file mode 100644
index 00000000..261c72c4
--- /dev/null
+++ b/tests/range_expr/gold/test7.out
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <grp numberClass="even">
+    <num>2</num>
+    <num>4</num>
+    <num>6</num>
+    <num>8</num>
+    <num>10</num>
+    <num>12</num>
+    <num>14</num>
+    <num>16</num>
+    <num>18</num>
+    <num>20</num>
+  </grp>
+  <grp numberClass="odd">
+    <num>1</num>
+    <num>3</num>
+    <num>5</num>
+    <num>7</num>
+    <num>9</num>
+    <num>11</num>
+    <num>13</num>
+    <num>15</num>
+    <num>17</num>
+    <num>19</num>
+  </grp>
+</result>
diff --git a/tests/range_expr/test1.xsl b/tests/range_expr/test1.xsl
new file mode 100644
index 00000000..b647cca7
--- /dev/null
+++ b/tests/range_expr/test1.xsl
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the 
+        XPath 3.1 range "to" expression. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/">
+      <result>
+         <xsl:for-each select="1 to 10">
+            <xsl:if test=". mod 2 = 0">
+              <even><xsl:value-of select="."/></even>
+            </xsl:if>
+         </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/range_expr/test1_a.xml b/tests/range_expr/test1_a.xml
new file mode 100644
index 00000000..79664a38
--- /dev/null
+++ b/tests/range_expr/test1_a.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+  <x>1</x>
+  <y>10</y>
+</elem>
\ No newline at end of file
diff --git a/tests/range_expr/test2.xsl b/tests/range_expr/test2.xsl
new file mode 100644
index 00000000..412d6a0d
--- /dev/null
+++ b/tests/range_expr/test2.xsl
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the 
+        XPath 3.1 range "to" expression. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/">
+      <result>
+         <xsl:for-each select="1 to 10">
+            <xsl:choose>
+	          <xsl:when test="(. mod 2) = 0">
+	             <even><xsl:value-of select="."/></even>
+	          </xsl:when>
+	          <xsl:otherwise>
+	             <odd><xsl:value-of select="."/></odd>
+	          </xsl:otherwise>
+             </xsl:choose>
+         </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/range_expr/test3.xsl b/tests/range_expr/test3.xsl
new file mode 100644
index 00000000..6cb46a64
--- /dev/null
+++ b/tests/range_expr/test3.xsl
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->                
+
+   <!-- use with test1_a.xml -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the XPath 3.1 
+        range "to" expression. This XSLT stylesheet, reads arguments
+        of XPath range "to" operation from an external XML document. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <result>
+         <xsl:for-each select="x to y">
+            <xsl:choose>
+               <xsl:when test="(. mod 2) = 0">
+                  <even><xsl:value-of select="."/></even>
+               </xsl:when>
+               <xsl:otherwise>
+                  <odd><xsl:value-of select="."/></odd>
+               </xsl:otherwise>
+            </xsl:choose>
+         </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/range_expr/test4.xsl b/tests/range_expr/test4.xsl
new file mode 100644
index 00000000..8589ca4a
--- /dev/null
+++ b/tests/range_expr/test4.xsl
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->                
+
+   <!-- use with test1_a.xml -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the XPath 3.1 
+        range "to" expression. This XSLT stylesheet, reads arguments of 
+        XPath range "to" operation from an external XML document. This 
+        stylesheet, also does grouping on data returned by the XPath 
+        range "to" operation. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <xsl:variable name="rangeOfNums">
+         <xsl:for-each select="x to y">
+           <num><xsl:value-of select="."/></num>
+         </xsl:for-each>
+      </xsl:variable>
+      <result>
+         <xsl:for-each-group select="$rangeOfNums/num" group-by="(. mod 2) = 0">
+            <xsl:variable name="numberClass">
+               <xsl:choose>
+                  <xsl:when test="current-grouping-key() = true()">
+                     even
+                  </xsl:when>
+                  <xsl:otherwise>
+                     odd
+                  </xsl:otherwise>
+               </xsl:choose>
+            </xsl:variable>
+            <grp numberClass="{normalize-space($numberClass)}">
+               <xsl:copy-of select="current-group()"/>
+            </grp>
+         </xsl:for-each-group>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/range_expr/test5.xsl b/tests/range_expr/test5.xsl
new file mode 100644
index 00000000..18d025d8
--- /dev/null
+++ b/tests/range_expr/test5.xsl
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->                
+
+   <!-- use with test1_a.xml -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the XPath 3.1 
+        range "to" expression. This XSLT stylesheet, reads arguments of 
+        XPath range "to" operation from an external XML document. This 
+        stylesheet, also does an arithmetic evaluation to compute value 
+        of one of the XPath range operand. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <result>
+         <xsl:for-each select="x to (y * 2)">
+            <xsl:choose>
+               <xsl:when test="(. mod 2) = 0">
+                  <even><xsl:value-of select="."/></even>
+               </xsl:when>
+               <xsl:otherwise>
+                  <odd><xsl:value-of select="."/></odd>
+               </xsl:otherwise>
+            </xsl:choose>
+         </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/range_expr/test6.xsl b/tests/range_expr/test6.xsl
new file mode 100644
index 00000000..7e91b1cb
--- /dev/null
+++ b/tests/range_expr/test6.xsl
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->                
+
+   <!-- use with test1_a.xml -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the XPath 3.1 
+        range "to" expression. This XSLT stylesheet, reads arguments of 
+        XPath range "to" operation from an external XML document. This 
+        stylesheet, also does an arithmetic evaluation to compute value 
+        of one of the XPath range operand, and also groups the data. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <xsl:variable name="rangeOfNums">
+         <xsl:for-each select="x to (y * 2)">
+           <num><xsl:value-of select="."/></num>
+         </xsl:for-each>
+      </xsl:variable>
+      <result>
+         <xsl:for-each-group select="$rangeOfNums/num" group-by="(. mod 2) = 0">
+            <xsl:variable name="numberClass">
+               <xsl:choose>
+                  <xsl:when test="current-grouping-key() = true()">
+                     even
+                  </xsl:when>
+                  <xsl:otherwise>
+                     odd
+                  </xsl:otherwise>
+               </xsl:choose>
+            </xsl:variable>
+            <grp numberClass="{normalize-space($numberClass)}">
+               <xsl:copy-of select="current-group()"/>
+            </grp>
+         </xsl:for-each-group>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/range_expr/test7.xsl b/tests/range_expr/test7.xsl
new file mode 100644
index 00000000..599c5404
--- /dev/null
+++ b/tests/range_expr/test7.xsl
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->                
+
+   <!-- use with test1_a.xml -->
+   
+   <!-- an XSLT stylesheet test case, demonstrating use of the XPath 3.1 
+        range "to" expression. This XSLT stylesheet, reads arguments
+        of XPath range "to" operation from an external XML document.
+        This stylesheet, also does an arithmetic evaluation to compute 
+        value of one of the XPath range operand, and also groups the 
+        data along with re-ordering the groups using xsl:sort instruction. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <xsl:variable name="rangeOfNums">
+         <xsl:for-each select="x to (y * 2)">
+           <num><xsl:value-of select="."/></num>
+         </xsl:for-each>
+      </xsl:variable>
+      <result>
+         <xsl:for-each-group select="$rangeOfNums/num" group-by="(. mod 2) = 0">
+            <xsl:sort select="current-grouping-key()" data-type="number" 
+                                                      order="descending"/>
+            <xsl:variable name="numberClass">
+               <xsl:choose>
+                  <xsl:when test="current-grouping-key() = true()">
+                     even
+                  </xsl:when>
+                  <xsl:otherwise>
+                     odd
+                  </xsl:otherwise>
+               </xsl:choose>
+            </xsl:variable>
+            <grp numberClass="{normalize-space($numberClass)}">
+               <xsl:copy-of select="current-group()"/>
+            </grp>
+         </xsl:for-each-group>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org