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/04/30 17:03:05 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing wip implementation of xslt 3.0 xsl:for-each-group instruction

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 0da6dead committing wip implementation of xslt 3.0 xsl:for-each-group instruction
0da6dead is described below

commit 0da6deadc8f06876df08d9c792fb24b4ed8fa337
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sun Apr 30 22:32:38 2023 +0530

    committing wip implementation of xslt 3.0 xsl:for-each-group instruction
---
 src/org/apache/xalan/processor/XSLTSchema.java     |  31 +-
 src/org/apache/xalan/templates/Constants.java      |  14 +-
 .../apache/xalan/templates/ElemForEachGroup.java   | 462 +++++++++++++++++++++
 .../xalan/templates/ElemTemplateElement.java       |  16 +
 .../apache/xalan/transformer/TransformerImpl.java  |  86 ++++
 5 files changed, 595 insertions(+), 14 deletions(-)

diff --git a/src/org/apache/xalan/processor/XSLTSchema.java b/src/org/apache/xalan/processor/XSLTSchema.java
index 50bf910a..e71d9a25 100644
--- a/src/org/apache/xalan/processor/XSLTSchema.java
+++ b/src/org/apache/xalan/processor/XSLTSchema.java
@@ -38,6 +38,7 @@ import org.apache.xalan.templates.ElemExtensionDecl;
 import org.apache.xalan.templates.ElemExtensionScript;
 import org.apache.xalan.templates.ElemFallback;
 import org.apache.xalan.templates.ElemForEach;
+import org.apache.xalan.templates.ElemForEachGroup;
 import org.apache.xalan.templates.ElemIf;
 import org.apache.xalan.templates.ElemLiteralResult;
 import org.apache.xalan.templates.ElemMessage;
@@ -192,10 +193,16 @@ public class XSLTSchema extends XSLTElementDef
       
       
     // Required.                                       
-    // xsl:value-of, xsl:for-each, xsl:copy-of                             
+    // xsl:value-of, xsl:for-each, xsl:copy-of, xsl:for-each-group                             
     XSLTAttributeDef selectAttrRequired = new XSLTAttributeDef(null,
                                             "select",
-                                            XSLTAttributeDef.T_EXPR, true, false,XSLTAttributeDef.ERROR);
+                                            XSLTAttributeDef.T_EXPR, true, false, XSLTAttributeDef.ERROR);
+    
+    // Optional.                                       
+    // xsl:for-each-group                             
+    XSLTAttributeDef groupByAttrOpt = new XSLTAttributeDef(null,
+                                            "group-by",
+                                            XSLTAttributeDef.T_EXPR, false, false, XSLTAttributeDef.ERROR);
 
     // Optional.                                          
     // xsl:variable, xsl:param, xsl:with-param                                       
@@ -343,13 +350,13 @@ public class XSLTSchema extends XSLTElementDef
       new XSLTAttributeDef(Constants.S_XSLNAMESPACEURL, "*",
                            XSLTAttributeDef.T_CDATA, false, false,XSLTAttributeDef.WARNING);
                            
-    XSLTElementDef[] templateElements = new XSLTElementDef[23];
-    XSLTElementDef[] templateElementsAndParams = new XSLTElementDef[24];
-    XSLTElementDef[] templateElementsAndSort = new XSLTElementDef[24];
+    XSLTElementDef[] templateElements = new XSLTElementDef[24];
+    XSLTElementDef[] templateElementsAndParams = new XSLTElementDef[25];
+    XSLTElementDef[] templateElementsAndSort = new XSLTElementDef[25];
     //exslt
-    XSLTElementDef[] exsltFunctionElements = new XSLTElementDef[24];
+    XSLTElementDef[] exsltFunctionElements = new XSLTElementDef[25];
     
-    XSLTElementDef[] charTemplateElements = new XSLTElementDef[15];
+    XSLTElementDef[] charTemplateElements = new XSLTElementDef[16];
     XSLTElementDef resultElement = new XSLTElementDef(this, null, "*",
                                      null /*alias */,
                                      templateElements /* elements */,
@@ -445,6 +452,14 @@ public class XSLTSchema extends XSLTElementDef
                                                           spaceAttr }, 
                                                new ProcessorTemplateElem(),
                                   ElemForEach.class /* class object */, true, false, true, 20, true);
+    
+    XSLTElementDef xslForEachGroup = new XSLTElementDef(this,
+                                             Constants.S_XSLNAMESPACEURL, "for-each-group",
+                                             null /*alias */, templateElementsAndSort,
+                                             new XSLTAttributeDef[]{ selectAttrRequired, groupByAttrOpt, spaceAttr }, 
+                                             new ProcessorTemplateElem(),
+                                             ElemForEachGroup.class /* class object */, true, false, true, 20, true);
+    
     XSLTElementDef xslIf = new XSLTElementDef(this,
                                               Constants.S_XSLNAMESPACEURL,
                                               "if", null /*alias */,
@@ -594,6 +609,7 @@ public class XSLTSchema extends XSLTElementDef
     templateElements[i++] = xslCallTemplate;
     templateElements[i++] = xslApplyImports;
     templateElements[i++] = xslForEach;
+    templateElements[i++] = xslForEachGroup;
     templateElements[i++] = xslValueOf;
     templateElements[i++] = xslCopyOf;
     templateElements[i++] = xslNumber;
@@ -631,6 +647,7 @@ public class XSLTSchema extends XSLTElementDef
     charTemplateElements[i++] = xslCallTemplate;
     charTemplateElements[i++] = xslApplyImports;
     charTemplateElements[i++] = xslForEach;
+    charTemplateElements[i++] = xslForEachGroup;
     charTemplateElements[i++] = xslValueOf;
     charTemplateElements[i++] = xslCopyOf;
     charTemplateElements[i++] = xslNumber;
diff --git a/src/org/apache/xalan/templates/Constants.java b/src/org/apache/xalan/templates/Constants.java
index 9bc6442a..8545fe85 100644
--- a/src/org/apache/xalan/templates/Constants.java
+++ b/src/org/apache/xalan/templates/Constants.java
@@ -32,10 +32,7 @@ public class Constants extends org.apache.xml.utils.Constants
    * IDs for XSL element types. These are associated
    * with the string literals in the TransformerImpl class.
    * Don't change the numbers. NOTE THAT THESE ARE NOT IN
-   * ALPHABETICAL ORDER!
-   * (It's a pity Java doesn't have a real Enumerated Mnemonic
-   * datatype... or a C-like preprocessor in lieu thereof which
-   * could be used to generate and maintain synch between these lists.)
+   * ALPHABETICAL ORDER.
    */
   public static final int ELEMNAME_UNDEFINED = -1, ELEMNAME_WITHPARAM = 2,
                           ELEMNAME_ADDATTRIBUTE = 4, ELEMNAME_ANCHOR = 22,
@@ -89,12 +86,14 @@ public class Constants extends org.apache.xml.utils.Constants
   ELEMNAME_LITERALRESULT = 77, ELEMNAME_TEXTLITERALRESULT = 78,
   ELEMNAME_EXTENSIONCALL = 79, ELEMNAME_EXTENSIONDECL = 85,
   ELEMNAME_EXTENSIONSCRIPT = 86, ELEMNAME_OUTPUT = 80,
-  ELEMNAME_COMPONENT = 81, ELEMNAME_SCRIPT = 82;
+  ELEMNAME_COMPONENT = 81, ELEMNAME_SCRIPT = 82,
+  
+  ELEMNAME_FOREACHGROUP = 90;
 
-  // Next free number: 90 (88 and 89 used for EXSLT elements);
+  // Next free number: 91
 
   /**
-   * Literals for XSL element names.  Note that there are more
+   * Literals for XSL element names. Note that there are more
    * names than IDs, because some names map to the same ID.
    */
   public static final String       
@@ -132,6 +131,7 @@ public class Constants extends org.apache.xml.utils.Constants
       ELEMNAME_EXTENSION_STRING = "functions",
       ELEMNAME_FALLBACK_STRING = "fallback",
       ELEMNAME_FOREACH_STRING = "for-each",
+      ELEMNAME_FOREACHGROUP_STRING = "for-each-group",
       ELEMNAME_IF_STRING = "if",
       ELEMNAME_IMPORT_STRING = "import",
       ELEMNAME_INCLUDE_STRING = "include",
diff --git a/src/org/apache/xalan/templates/ElemForEachGroup.java b/src/org/apache/xalan/templates/ElemForEachGroup.java
new file mode 100644
index 00000000..4f578b0e
--- /dev/null
+++ b/src/org/apache/xalan/templates/ElemForEachGroup.java
@@ -0,0 +1,462 @@
+/*
+ * 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.xalan.templates;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.transformer.NodeSorter;
+import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.IntStack;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+
+/**
+ * Implementation of the xsl:for-each-group XSLT 3.0 instruction.
+ * 
+ * <xsl:for-each-group
+              select = expression
+              group-by? = expression
+              group-adjacent? = expression
+              group-starting-with? = pattern
+              group-ending-with? = pattern
+              composite? = boolean
+              collation? = { uri } >
+        <!-- Content: (xsl:sort*, sequence-constructor) -->
+    </xsl:for-each-group>
+    
+    <xsl:sort
+           select? = expression
+           lang? = { language }
+           order? = { "ascending" | "descending" }
+           collation? = { uri }
+           stable? = { boolean }
+           case-order? = { "upper-first" | "lower-first" }
+           data-type? = { "text" | "number" | eqname } >
+        <!-- Content: sequence-constructor -->
+     </xsl:sort>
+     
+     XSLT 3.0 grouping functions,
+     1) fn:current-group()     
+     2) fn:current-grouping-key()
+ * 
+ * (xsl:for-each-group instruction was first introduced in XSLT 2.0 language)
+ * 
+ * @author Mukul Gandhi
+ * 
+ * @xsl.usage advanced
+ */
+
+/*
+  This implementation is WIP
+  
+1) To make this more compliant to XSLT 3.0 spec
+2) We're still using XalanJ's implementation of XPath 1.0 data model
+   for xsl:for-each-group's implementation. 
+*/
+public class ElemForEachGroup extends ElemTemplateElement implements ExpressionOwner
+{
+  
+  private static final long serialVersionUID = -6682554013978812260L;
+  
+  /**
+   * Construct a element representing xsl:for-each-group.
+   */
+  public ElemForEachGroup(){}
+
+  /**
+   * The "select" expression.
+   * @serial
+   */
+  protected Expression m_selectExpression = null;
+  
+  /**
+   * The "group-by" expression.
+   */
+  protected Expression m_GroupByExpression = null; 
+
+  /**
+   * Set the "select" attribute.
+   *
+   * @param xpath The XPath expression for the "select" attribute.
+   */
+  public void setSelect(XPath xpath)
+  {
+      m_selectExpression = xpath.getExpression();  
+  }
+
+  /**
+   * Get the "select" attribute.
+   *
+   * @return The XPath expression for the "select" attribute.
+   */
+  public Expression getSelect()
+  {
+      return m_selectExpression;
+  }
+  
+  public void setGroupBy(XPath xpath)
+  {
+      m_GroupByExpression = xpath.getExpression();   
+  }
+  
+  public Expression getGroupBy()
+  {
+      return m_GroupByExpression;
+  }
+
+  /**
+   * This function is called after everything else has been
+   * recomposed, and allows the template to set remaining
+   * values that may be based on some other property that
+   * depends on recomposition.
+   *
+   * NEEDSDOC @param sroot
+   *
+   * @throws TransformerException
+   */
+  public void compose(StylesheetRoot sroot) throws TransformerException
+  {
+        super.compose(sroot);
+    
+        int length = getSortElemCount();
+    
+        for (int i = 0; i < length; i++)
+        {
+            getSortElem(i).compose(sroot);
+        }
+    
+        java.util.Vector vnames = sroot.getComposeState().getVariableNames();
+    
+        if (m_selectExpression != null) {
+            m_selectExpression.fixupVariables(vnames, sroot.getComposeState().getGlobalsSize());
+        } else {
+            m_selectExpression = getStylesheetRoot().m_selectDefault.getExpression();
+        }
+  }
+  
+  /**
+   * This after the template's children have been composed.
+   */
+  public void endCompose(StylesheetRoot sroot) throws TransformerException
+  {
+        int length = getSortElemCount();
+    
+        for (int i = 0; i < length; i++)
+        {
+            getSortElem(i).endCompose(sroot);
+        }
+        
+        super.endCompose(sroot);
+  }
+
+  /**
+   * Vector containing the xsl:sort elements associated with this element.
+   *  @serial
+   */
+  protected Vector m_sortElems = null;
+
+  /**
+   * Get the count xsl:sort elements associated with this element.
+   * @return The number of xsl:sort elements.
+   */
+  public int getSortElemCount()
+  {
+      return (m_sortElems == null) ? 0 : m_sortElems.size();
+  }
+
+  /**
+   * Get a xsl:sort element associated with this element.
+   *
+   * @param i Index of xsl:sort element to get
+   *
+   * @return xsl:sort element at given index
+   */
+  public ElemSort getSortElem(int i)
+  {
+      return (ElemSort) m_sortElems.elementAt(i);
+  }
+
+  /**
+   * Set a xsl:sort element associated with this element.
+   *
+   * @param sortElem xsl:sort element to set
+   */
+  public void setSortElem(ElemSort sortElem)
+  {
+      if (null == m_sortElems)
+         m_sortElems = new Vector();
+    
+      m_sortElems.addElement(sortElem);
+  }
+
+  /**
+   * Get an int constant identifying the type of element.
+   * @see org.apache.xalan.templates.Constants
+   *
+   * @return The token ID for this element
+   */
+  public int getXSLToken()
+  {
+      return Constants.ELEMNAME_FOREACHGROUP;
+  }
+
+  /**
+   * Return the node name.
+   *
+   * @return The element's name
+   */
+  public String getNodeName()
+  {
+      return Constants.ELEMNAME_FOREACHGROUP_STRING;
+  }
+
+  /**
+   * Execute the xsl:for-each-group transformation
+   *
+   * @param transformer non-null reference to the the current transform-time state.
+   *
+   * @throws TransformerException
+   */
+  public void execute(TransformerImpl transformer) throws TransformerException
+  {
+        transformer.pushCurrentTemplateRuleIsNull(true);    
+        if (transformer.getDebug())
+           transformer.getTraceManager().fireTraceEvent(this);
+    
+        try
+        {
+            transformSelectedNodes(transformer);
+        }
+        finally
+        {
+            if (transformer.getDebug())
+    	       transformer.getTraceManager().fireTraceEndEvent(this); 
+            transformer.popCurrentTemplateRuleIsNull();
+        }
+  }
+
+  /**
+   * Get template element associated with this
+   *
+   *
+   * @return template element associated with this (itself)
+   */
+  protected ElemTemplateElement getTemplateMatch()
+  {
+      return this;
+  }
+
+  /**
+   * Sort given nodes
+   *
+   *
+   * @param xctxt The XPath runtime state for the sort.
+   * @param keys Vector of sort keys
+   * @param sourceNodes Iterator of nodes to sort
+   *
+   * @return iterator of sorted nodes
+   *
+   * @throws TransformerException
+   */
+  public DTMIterator sortNodes(XPathContext xctxt, Vector keys, DTMIterator sourceNodes)
+                                                                     throws TransformerException {
+        NodeSorter sorter = new NodeSorter(xctxt);
+        sourceNodes.setShouldCacheNodes(true);
+        sourceNodes.runTo(-1);
+        xctxt.pushContextNodeList(sourceNodes);
+    
+        try
+        {
+            sorter.sort(sourceNodes, keys, xctxt);
+            sourceNodes.setCurrentPos(0);
+        }
+        finally
+        {
+            xctxt.popContextNodeList();
+        }
+    
+        return sourceNodes;
+  }
+
+  /**
+   * Perform a query if needed, and call transformNode for each child.
+   *
+   * @param transformer non-null reference to the the current transform-time state.
+   *
+   * @throws TransformerException Thrown in a variety of circumstances.
+   * @throws CloneNotSupportedException 
+   * @xsl.usage advanced
+   */
+  public void transformSelectedNodes(TransformerImpl transformer)
+                                              throws TransformerException {
+        final XPathContext xctxt = transformer.getXPathContext();
+        final int sourceNode = xctxt.getCurrentNode();
+        DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
+        
+        // form groups from the 'sourceNodes' iterator
+        
+        // assuming string grouping keys for now.
+        // hashmap's key is the grouping key, and value is a list of dtm integer node handles        
+        Map<String, List<Integer>> groups = new HashMap<String, List<Integer>>();
+        
+        int nextNode;
+        
+        while (DTM.NULL != (nextNode = sourceNodes.nextNode())) {
+            xctxt.pushCurrentNode(nextNode);
+                        
+            XObject xpathEvalResult = m_GroupByExpression.execute(xctxt);
+            
+            String grpByEvalResultStrValue = xpathEvalResult.toString();                            
+            if (groups.get(grpByEvalResultStrValue) != null) {
+                List<Integer> group = groups.get(grpByEvalResultStrValue);
+                group.add(nextNode);
+            } else {
+                List<Integer> group = new ArrayList<Integer>();
+                group.add(nextNode);
+                groups.put(grpByEvalResultStrValue, group);
+            }            
+         }
+        
+         // end, form groups from the 'sourceNodes' iterator
+        
+         try {            
+            xctxt.pushCurrentNode(DTM.NULL);
+            
+            IntStack currentNodes = xctxt.getCurrentNodeStack();
+      
+            xctxt.pushCurrentExpressionNode(DTM.NULL);
+      
+            IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
+      
+            xctxt.pushSAXLocatorNull();
+            xctxt.pushContextNodeList(sourceNodes);
+            transformer.pushElemTemplateElement(null);
+            
+            Set<String> groupingKeys = groups.keySet();
+            
+            // iterate through all the, groups formed by xsl:for-each-group instruction
+            for (Iterator<String> iter = groupingKeys.iterator(); iter.hasNext(); ) {
+               String groupingKey = iter.next();  // this is raw current-grouping-key() value
+               List<Integer> groupNodesDtmHandles = groups.get(groupingKey);  // this is raw dtm current-group() contents
+               
+               for (ElemTemplateElement templateElem = this.m_firstChild; templateElem != null; 
+                                                templateElem = templateElem.m_nextSibling) {
+                   xctxt.setSAXLocator(templateElem);
+                   transformer.setCurrentElement(templateElem);
+                   templateElem.setForEachGroupControlInformation(groupingKey, 
+                                                                 groupNodesDtmHandles);
+                   templateElem.execute(transformer);
+               }
+            }
+        }
+        finally
+        {
+              if (transformer.getDebug())
+                  transformer.getTraceManager().fireSelectedEndEvent(sourceNode, this,
+                        "select", new XPath(m_selectExpression),
+                        new org.apache.xpath.objects.XNodeSet(sourceNodes));
+        
+              xctxt.popSAXLocator();
+              xctxt.popContextNodeList();
+              transformer.popElemTemplateElement();
+              xctxt.popCurrentExpressionNode();
+              xctxt.popCurrentNode();
+              sourceNodes.detach();
+        }
+  }
+
+  /**
+   * Add a child to the child list.
+   * <!ELEMENT xsl:apply-templates (xsl:sort|xsl:with-param)*>
+   * <!ATTLIST xsl:apply-templates
+   *   select %expr; "node()"
+   *   mode %qname; #IMPLIED
+   * >
+   *
+   * @param newChild Child to add to child list
+   *
+   * @return Child just added to child list
+   */
+  public ElemTemplateElement appendChild(ElemTemplateElement newChild)
+  {
+        int type = ((ElemTemplateElement) newChild).getXSLToken();
+    
+        if (type == Constants.ELEMNAME_SORT)
+        {
+            setSortElem((ElemSort) newChild);
+        
+            return newChild;
+        }
+        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/ElemTemplateElement.java b/src/org/apache/xalan/templates/ElemTemplateElement.java
index 807c0b72..0846f512 100644
--- a/src/org/apache/xalan/templates/ElemTemplateElement.java
+++ b/src/org/apache/xalan/templates/ElemTemplateElement.java
@@ -62,6 +62,12 @@ public class ElemTemplateElement extends UnImplNode
                    WhitespaceStrippingElementMatcher, XSLTVisitable
 {
     static final long serialVersionUID = 4440018597841834447L;
+    
+    // xsl:for-each-group grouping key string value
+    private String fGroupingKey;
+    
+    // xsl:for-each-group "current group" contents
+    private List<Integer> fGroupNodesDtmHandles;
 
   /**
    * Construct a template element instance.
@@ -135,6 +141,16 @@ public class ElemTemplateElement extends UnImplNode
   public void execute(
           TransformerImpl transformer)
             throws TransformerException{}
+  
+  /*
+   * Method to support, xsl:for-each-group instruction.
+   */
+  public void setForEachGroupControlInformation(String groupingKey, 
+                                                List<Integer> groupNodesDtmHandles)
+                                                   throws TransformerException {
+      this.fGroupingKey = groupingKey;
+      this.fGroupNodesDtmHandles = groupNodesDtmHandles;
+  }
 
   /**
    * Get the owning "composed" stylesheet.  This looks up the
diff --git a/src/org/apache/xalan/transformer/TransformerImpl.java b/src/org/apache/xalan/transformer/TransformerImpl.java
index bd9baaf7..105543d8 100644
--- a/src/org/apache/xalan/transformer/TransformerImpl.java
+++ b/src/org/apache/xalan/transformer/TransformerImpl.java
@@ -56,6 +56,7 @@ import org.apache.xalan.templates.AVT;
 import org.apache.xalan.templates.Constants;
 import org.apache.xalan.templates.ElemAttributeSet;
 import org.apache.xalan.templates.ElemForEach;
+import org.apache.xalan.templates.ElemForEachGroup;
 import org.apache.xalan.templates.ElemSort;
 import org.apache.xalan.templates.ElemTemplate;
 import org.apache.xalan.templates.ElemTemplateElement;
@@ -2564,6 +2565,91 @@ public class TransformerImpl extends Transformer
 
     return keys;
   }
+  
+  public Vector processSortKeysForEachGroup(ElemForEachGroup foreachgroup, int sourceNodeContext)
+          throws TransformerException
+  {
+
+    Vector keys = null;
+    XPathContext xctxt = m_xcontext;
+    int nElems = foreachgroup.getSortElemCount();
+
+    if (nElems > 0)
+      keys = new Vector();
+
+    // March backwards, collecting the sort keys.
+    for (int i = 0; i < nElems; i++)
+    {
+      ElemSort sort = foreachgroup.getSortElem(i);
+      
+      if (m_debug)
+        getTraceManager().fireTraceEvent(sort);
+     
+      String langString =
+        (null != sort.getLang())
+        ? sort.getLang().evaluate(xctxt, sourceNodeContext, foreachgroup) : null;
+      String dataTypeString = sort.getDataType().evaluate(xctxt,
+                                sourceNodeContext, foreachgroup);
+
+      if (dataTypeString.indexOf(":") >= 0)
+        System.out.println(
+          "TODO: Need to write the hooks for QNAME sort data type");
+      else if (!(dataTypeString.equalsIgnoreCase(Constants.ATTRVAL_DATATYPE_TEXT))
+               &&!(dataTypeString.equalsIgnoreCase(
+                 Constants.ATTRVAL_DATATYPE_NUMBER)))
+        foreachgroup.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
+                      new Object[]{ Constants.ATTRNAME_DATATYPE,
+                                    dataTypeString });
+
+      boolean treatAsNumbers =
+        ((null != dataTypeString) && dataTypeString.equals(
+        Constants.ATTRVAL_DATATYPE_NUMBER)) ? true : false;
+      String orderString = sort.getOrder().evaluate(xctxt, sourceNodeContext,
+                             foreachgroup);
+
+      if (!(orderString.equalsIgnoreCase(Constants.ATTRVAL_ORDER_ASCENDING))
+              &&!(orderString.equalsIgnoreCase(
+                Constants.ATTRVAL_ORDER_DESCENDING)))
+        foreachgroup.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
+                      new Object[]{ Constants.ATTRNAME_ORDER,
+                                    orderString });
+
+      boolean descending =
+        ((null != orderString) && orderString.equals(
+        Constants.ATTRVAL_ORDER_DESCENDING)) ? true : false;
+      AVT caseOrder = sort.getCaseOrder();
+      boolean caseOrderUpper;
+
+      if (null != caseOrder)
+      {
+        String caseOrderString = caseOrder.evaluate(xctxt, sourceNodeContext,
+                                                    foreachgroup);
+
+        if (!(caseOrderString.equalsIgnoreCase(Constants.ATTRVAL_CASEORDER_UPPER))
+                &&!(caseOrderString.equalsIgnoreCase(
+                  Constants.ATTRVAL_CASEORDER_LOWER)))
+          foreachgroup.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
+                        new Object[]{ Constants.ATTRNAME_CASEORDER,
+                                      caseOrderString });
+
+        caseOrderUpper =
+          ((null != caseOrderString) && caseOrderString.equals(
+          Constants.ATTRVAL_CASEORDER_UPPER)) ? true : false;
+      }
+      else
+      {
+        caseOrderUpper = false;
+      }
+
+      keys.addElement(new NodeSortKey(this, sort.getSelect(), treatAsNumbers,
+                                      descending, langString, caseOrderUpper,
+                                      foreachgroup));
+      if (m_debug)
+        getTraceManager().fireTraceEndEvent(sort);
+     }
+
+    return keys;
+  }
 
   //==========================================================
   // SECTION: TransformState implementation


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