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 2025/05/04 09:56:30 UTC

(xalan-java) branch xalan-j_xslt3.0_mvn updated: committing fixes for xsl:for-each-group instruction implementation, for few of w3c xslt 3.0 xsl:for-each-group test cases

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

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


The following commit(s) were added to refs/heads/xalan-j_xslt3.0_mvn by this push:
     new 3b8e534b3 committing fixes for xsl:for-each-group instruction implementation, for few of w3c xslt 3.0 xsl:for-each-group test cases
3b8e534b3 is described below

commit 3b8e534b3514da86b43e70f6d026f353b1fc8610
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sun May 4 15:26:13 2025 +0530

    committing fixes for xsl:for-each-group instruction implementation, for few of w3c xslt 3.0 xsl:for-each-group test cases
---
 .../apache/xalan/processor/XSLTAttributeDef.java   |  7 +-
 .../java/org/apache/xalan/templates/Constants.java |  1 +
 .../apache/xalan/templates/ElemForEachGroup.java   | 82 ++++++++++++++--------
 .../org/apache/xpath/functions/FuncPosition.java   |  5 +-
 .../java/org/apache/xpath/operations/Variable.java | 18 +++--
 5 files changed, 77 insertions(+), 36 deletions(-)

diff --git a/src/main/java/org/apache/xalan/processor/XSLTAttributeDef.java b/src/main/java/org/apache/xalan/processor/XSLTAttributeDef.java
index d4beb3125..dab0ba88c 100644
--- a/src/main/java/org/apache/xalan/processor/XSLTAttributeDef.java
+++ b/src/main/java/org/apache/xalan/processor/XSLTAttributeDef.java
@@ -768,7 +768,8 @@ public class XSLTAttributeDef
       XPath expr = null;
       
       String normalizedStrValue = null;
-      if ((owner instanceof ElemForEachGroup) && (Constants.ATTRNAME_GROUPBY).equals(name)) {
+      if ((owner instanceof ElemForEachGroup) && ((Constants.ATTRNAME_GROUPBY).equals(name) || 
+    		                                      (Constants.ATTRNAME_GROUP_ADJACENT).equals(name))) {
     	 if (value != null) {
     		normalizedStrValue = getForEachGroupAttrNormalizedStrValue(value);    		
     		if (normalizedStrValue != null) {
@@ -1391,13 +1392,13 @@ public class XSLTAttributeDef
   {
 
     // Is this already checked somewhere else?  -sb
-    if (!(value.equals("yes") || value.equals("no")))
+    if (!(value.equals("yes") || value.equals("true") || value.equals("no") || value.equals("false")))
     {
       handleError(handler, XSLTErrorResources.INVALID_BOOLEAN, new Object[] {name,value}, null);
       return null;
    }
  
-     return new Boolean(value.equals("yes") ? true : false);
+     return new Boolean((value.equals("yes") || value.equals("true")) ? true : false);
   }
 
   /**
diff --git a/src/main/java/org/apache/xalan/templates/Constants.java b/src/main/java/org/apache/xalan/templates/Constants.java
index 7cbcb0730..e9aff8e51 100644
--- a/src/main/java/org/apache/xalan/templates/Constants.java
+++ b/src/main/java/org/apache/xalan/templates/Constants.java
@@ -282,6 +282,7 @@ public class Constants extends org.apache.xml.utils.Constants
       ATTRNAME_GROUPINGSEPARATOR = "grouping-separator",
       ATTRNAME_GROUPINGSIZE = "grouping-size",
       ATTRNAME_GROUPBY = "group-by",
+      ATTRNAME_GROUP_ADJACENT = "group-adjacent",
       ATTRNAME_HREF = "href",
       ATTRNAME_ID = "id",
       ATTRNAME_IMPORTANCE = "importance",
diff --git a/src/main/java/org/apache/xalan/templates/ElemForEachGroup.java b/src/main/java/org/apache/xalan/templates/ElemForEachGroup.java
index 1c14a505c..304d1fb72 100644
--- a/src/main/java/org/apache/xalan/templates/ElemForEachGroup.java
+++ b/src/main/java/org/apache/xalan/templates/ElemForEachGroup.java
@@ -47,6 +47,7 @@ import org.apache.xpath.XPathContext;
 import org.apache.xpath.axes.NodeCursor;
 import org.apache.xpath.composite.XPathForExpr;
 import org.apache.xpath.composite.XPathSequenceConstructor;
+import org.apache.xpath.functions.FuncPosition;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XBoolean;
 import org.apache.xpath.objects.XBooleanStatic;
@@ -804,33 +805,41 @@ public class ElemForEachGroup extends ElemTemplateElement
 	  int nextNode;
 	  
 	  SourceLocator srcLocator = xctxt.getSAXLocator();
+	  	  
+	  try {
+		  int pos = 0;
+		  
+		  while (DTM.NULL != (nextNode = sourceNodes.nextNode())) {
+			  FuncPosition.m_forEachGroupGroupByPos = ++pos; 
+			  XObject xpathEvalResult = m_GroupByExpression.execute(xctxt, nextNode, xctxt.getNamespaceContext());
+			  Object groupingKeyValue = getNormalizedGroupingKeyValue(xctxt, xpathEvalResult);
 
-	  while (DTM.NULL != (nextNode = sourceNodes.nextNode())) {
-		  XObject xpathEvalResult = m_GroupByExpression.execute(xctxt, nextNode, xctxt.getNamespaceContext());                
-		  Object groupingKeyValue = getNormalizedGroupingKeyValue(xctxt, xpathEvalResult);
-
-		  if (!m_composite) {
-			  addXdmNodeHandleToGroup(xslForEachGroupByMap, nextNode, groupingKeyValue);
-		  }
-		  else {
-			  // Processing for xsl:for-each-group's composite grouping key
-			  if (groupingKeyValue instanceof ForEachGroupCompositeGroupingKey) {
-				  ForEachGroupCompositeGroupingKey groupingKeyObj = (ForEachGroupCompositeGroupingKey)groupingKeyValue;
-				  ResultSequence groupingKeySeq = groupingKeyObj.getValue();
-				  if (groupingKeySeq.size() >= 1) {
-					  addXdmNodeHandleToGroup(xslForEachGroupByMap, nextNode, groupingKeyValue);
+			  if (!m_composite) {
+				  addXdmNodeHandleToGroup(xslForEachGroupByMap, nextNode, groupingKeyValue);
+			  }
+			  else {
+				  // Processing for xsl:for-each-group's composite grouping key
+				  if (groupingKeyValue instanceof ForEachGroupCompositeGroupingKey) {
+					  ForEachGroupCompositeGroupingKey groupingKeyObj = (ForEachGroupCompositeGroupingKey)groupingKeyValue;
+					  ResultSequence groupingKeySeq = groupingKeyObj.getValue();
+					  if (groupingKeySeq.size() >= 1) {
+						  addXdmNodeHandleToGroup(xslForEachGroupByMap, nextNode, groupingKeyValue);
+					  }
+					  else {
+						  throw new TransformerException("XTSE1080 : An xsl:for-each-group instruction with attribute "
+																										  + "'composite=\"yes\"', resulted in a grouping key "
+																										  + "sequence that is empty.", srcLocator);
+					  }
 				  }
 				  else {
-					  throw new TransformerException("XTSE1080 : An xsl:for-each-group instruction with attribute "
-							  		                             + "value 'composite=\"yes\"', resulted in a grouping key "
-							  		                             + "sequence that is empty.", srcLocator);
+					  addXdmNodeHandleToGroup(xslForEachGroupByMap, nextNode, groupingKeyValue); 
 				  }
 			  }
-			  else {
-				  addXdmNodeHandleToGroup(xslForEachGroupByMap, nextNode, groupingKeyValue); 
-			  }
 		  }
 	  }
+	  finally {	  
+	     FuncPosition.m_forEachGroupGroupByPos = 0;
+	  }
   }
 
   /**
@@ -1008,14 +1017,31 @@ public class ElemForEachGroup extends ElemTemplateElement
    */
   private void constructGroupsForGroupAdjacent(XPathContext xctxt, DTMCursorIterator sourceNodes,
 		                                       List<GroupingKeyAndGroupPair> xslForEachGroupAdjacentList) throws TransformerException {
-	 Object prevValue = null;
+	  
 	 int idx = 0;
 	 int nextNode;
 	 
+	 Object prevGroupingKeyValue = null;
+	 
+	 SourceLocator srcLocator = xctxt.getSAXLocator(); 
+	 
 	 while (DTM.NULL != (nextNode = sourceNodes.nextNode())) {	     
 	     XObject xpathEvalResult = m_GroupAdjacentExpression.execute(xctxt, nextNode, xctxt.getNamespaceContext());                 
-	     Object groupingKeyValue = getNormalizedGroupingKeyValue(xctxt, xpathEvalResult);                 
-	     Object currValue = groupingKeyValue;
+	     Object groupingKeyValue = getNormalizedGroupingKeyValue(xctxt, xpathEvalResult);
+	     
+	     if (m_composite) {
+	    	 if (groupingKeyValue instanceof ForEachGroupCompositeGroupingKey) {
+				  ForEachGroupCompositeGroupingKey groupingKeyObj = (ForEachGroupCompositeGroupingKey)groupingKeyValue;
+				  ResultSequence groupingKeySeq = groupingKeyObj.getValue();
+				  if (groupingKeySeq.size() == 0) {
+					  throw new TransformerException("XTSE1080 : An xsl:for-each-group instruction with attribute "
+																	                             + "'composite=\"yes\"', resulted in a grouping key "
+																	                             + "sequence that is empty.", srcLocator);
+				  }
+			  } 
+	     }
+	     
+	     Object currGroupingKeyValue = groupingKeyValue;
 	     
 	     List<Integer> group = null;
 	     
@@ -1023,12 +1049,12 @@ public class ElemForEachGroup extends ElemTemplateElement
 	         // This is the first XDM node being iterated, within this loop
 	         group = new ArrayList<Integer>();
 	         group.add(nextNode);
-	         GroupingKeyAndGroupPair groupingKeyAndGroupPair = new GroupingKeyAndGroupPair(currValue, group);
+	         GroupingKeyAndGroupPair groupingKeyAndGroupPair = new GroupingKeyAndGroupPair(currGroupingKeyValue, group);
 	         xslForEachGroupAdjacentList.add(groupingKeyAndGroupPair);
-	         prevValue = currValue; 
+	         prevGroupingKeyValue = currGroupingKeyValue; 
 	     }
 	     else {
-	        if (currValue.equals(prevValue)) {
+	        if (currGroupingKeyValue.equals(prevGroupingKeyValue)) {
 	        	int currResultSize = xslForEachGroupAdjacentList.size();
 	        	GroupingKeyAndGroupPair groupingKeyAndGroupPair = xslForEachGroupAdjacentList.get(currResultSize - 1);
 	        	group = groupingKeyAndGroupPair.getGroupNodesDtmHandles(); 
@@ -1037,11 +1063,11 @@ public class ElemForEachGroup extends ElemTemplateElement
 	        else {
 	            group = new ArrayList<Integer>();
 	            group.add(nextNode);
-	            GroupingKeyAndGroupPair groupingKeyAndGroupPair = new GroupingKeyAndGroupPair(currValue, group);
+	            GroupingKeyAndGroupPair groupingKeyAndGroupPair = new GroupingKeyAndGroupPair(currGroupingKeyValue, group);
 	            xslForEachGroupAdjacentList.add(groupingKeyAndGroupPair);
 	        }
 	        
-	        prevValue = currValue;
+	        prevGroupingKeyValue = currGroupingKeyValue;
 	     }
 	     
 	     idx++;
diff --git a/src/main/java/org/apache/xpath/functions/FuncPosition.java b/src/main/java/org/apache/xpath/functions/FuncPosition.java
index f804b935c..7269a4618 100644
--- a/src/main/java/org/apache/xpath/functions/FuncPosition.java
+++ b/src/main/java/org/apache/xpath/functions/FuncPosition.java
@@ -38,6 +38,8 @@ public class FuncPosition extends Function
   
   private boolean m_isTopLevel;
   
+  public static int m_forEachGroupGroupByPos = 0;
+  
   /**
    * Figure out if we're executing a toplevel expression.
    * If so, we can't be inside of a predicate. 
@@ -127,7 +129,8 @@ public class FuncPosition extends Function
    */
   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
   {    	  
-	  double pos = (xctxt.getGroupPosition() > 0) ? xctxt.getGroupPosition() : ((double) getPositionInContextNodeList(xctxt));  
+	  double pos = (xctxt.getGroupPosition() > 0) ? xctxt.getGroupPosition() : ((double) getPositionInContextNodeList(xctxt));
+	  pos = (pos > 0) ? pos : m_forEachGroupGroupByPos;
     
       return new XNumber(pos);
   }
diff --git a/src/main/java/org/apache/xpath/operations/Variable.java b/src/main/java/org/apache/xpath/operations/Variable.java
index e389505de..c5cfe8271 100644
--- a/src/main/java/org/apache/xpath/operations/Variable.java
+++ b/src/main/java/org/apache/xpath/operations/Variable.java
@@ -267,7 +267,7 @@ public class Variable extends Expression implements PathComponent
               }
            } 
            else {  
-              result = xctxt.getVarStack().getVariableOrParam(xctxt,m_qname);
+              result = xctxt.getVarStack().getVariableOrParam(xctxt, m_qname);
            }
         }
         catch (javax.xml.transform.TransformerException ex) {
@@ -281,10 +281,20 @@ public class Variable extends Expression implements PathComponent
         	   result = xpath.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
         	   
         	   XslTransformSharedDatastore.xpathNodeCombiningExprRhsStrBuff = null;
-           }
+           }           
            else {
-               throw new javax.xml.transform.TransformerException("Variable $" + m_qname.toString() + " "
-                                                                                               + "accessed before it is bound!."); 
+        	  try {
+        		  if (m_isGlobal) {
+        			  result = xctxt.getVarStack().getGlobalVariable(xctxt, m_index, destructiveOK);
+        		  }
+        		  else {
+        			  result = xctxt.getVarStack().getLocalVariable(xctxt, m_index, destructiveOK);
+        		  }
+        	  }
+        	  catch (TransformerException ex1) {
+                  throw new javax.xml.transform.TransformerException("Variable $" + m_qname.toString() + " "
+                                                                                                  			+ "accessed before it is bound!.");
+        	  }
            }
         }
       


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