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/07/02 10:47:09 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing improvements to xpath 3.1 function item inline function expressions processing. improvements to, xsl:copy-of instruction to handle processing of xpath 3.1 sequences. improvements to xpath function fn:count to handle range to expression as an argument. adding a related working xslt 3.0 test case as well.

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 76dfa805 committing improvements to xpath 3.1 function item inline function expressions processing. improvements to, xsl:copy-of instruction to handle processing of xpath 3.1 sequences. improvements to xpath function fn:count to handle range to expression as an argument. adding a related working xslt 3.0 test case as well.
     new af5aec06 Merge pull request #16 from mukulga/xalan-j_xslt3.0_mukul
76dfa805 is described below

commit 76dfa805c35c7c32dee36b3b10ed7e29a1971d96
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sun Jul 2 16:07:31 2023 +0530

    committing improvements to xpath 3.1 function item inline function expressions processing. improvements to, xsl:copy-of instruction to handle processing of xpath 3.1 sequences. improvements to xpath function fn:count to handle range to expression as an argument. adding a related working xslt 3.0 test case as well.
---
 src/org/apache/xalan/templates/ElemCopyOf.java   | 61 ++++++++++++------------
 src/org/apache/xpath/compiler/XPathParser.java   | 37 ++++++++++++--
 src/org/apache/xpath/functions/FuncCount.java    | 13 +++--
 src/org/apache/xpath/functions/FuncFilter.java   |  2 +-
 tests/fn_filter/gold/test7.out                   |  4 ++
 tests/fn_filter/test7.xsl                        | 38 +++++++++++++++
 tests/org/apache/xalan/xpath3/FnFilterTests.java | 10 ++++
 7 files changed, 126 insertions(+), 39 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemCopyOf.java b/src/org/apache/xalan/templates/ElemCopyOf.java
index d0889369..0c9876f3 100644
--- a/src/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/org/apache/xalan/templates/ElemCopyOf.java
@@ -38,7 +38,8 @@ import org.apache.xpath.objects.XObject;
 /*
  * Implementation of XSLT xsl:copy-of instruction.
  * 
- * XSLT 3.0 xsl:copy-of instruction definition,
+ * XSLT 3.0 spec, provides following definition of xsl:copy-of
+ * instruction,
  *  
  * <xsl:copy-of
           select = expression
@@ -51,7 +52,7 @@ import org.apache.xpath.objects.XObject;
  */
 public class ElemCopyOf extends ElemTemplateElement
 {
-    static final long serialVersionUID = -7433828829497411127L;
+   static final long serialVersionUID = -7433828829497411127L;
 
   /**
    * The required select attribute contains an expression.
@@ -119,8 +120,7 @@ public class ElemCopyOf extends ElemTemplateElement
   /**
    * The xsl:copy-of element can be used to insert a result tree
    * fragment into the result tree, without first converting it to
-   * a string as xsl:value-of does (see [7.6.1 Generating Text with
-   * xsl:value-of]).
+   * a string as xsl:value-of does.
    *
    * @param transformer non-null reference to the the current transform-time state.
    *
@@ -145,8 +145,7 @@ public class ElemCopyOf extends ElemTemplateElement
 
       SerializationHandler handler = transformer.getSerializationHandler();
 
-      if (null != value)
-                        {
+      if (value != null) {
         int type = value.getType();
         String s;
 
@@ -199,45 +198,47 @@ public class ElemCopyOf extends ElemTemplateElement
             handler, value, transformer.getXPathContext());
           break;
         case XObject.CLASS_RESULT_SEQUENCE :
-          // added for XSLT 3.0
+          // added for XSLT 3.0          
           ResultSequence resultSequence = (ResultSequence)value;
           char[] spaceCharArr = new char[1];
           spaceCharArr[0] = ' ';
-          for (int idx = 0; idx < resultSequence.size(); idx++) {
+          
+          for (int idx = 0; idx < resultSequence.size(); idx++) {             
              XObject sequenceItem = resultSequence.item(idx);
              
              if (sequenceItem.getType() == XObject.CLASS_STRING) {
                  String str = sequenceItem.str();
                  handler.characters(str.toCharArray(), 0, str.length());
                  if (idx < (resultSequence.size() - 1)) {                     
-                     handler.characters(spaceCharArr, 0, 1);
+                    handler.characters(spaceCharArr, 0, 1);
                  }
-                 continue;
              }
-             
-             DTMIterator dtmIter = sequenceItem.iter();
-
-             DTMTreeWalker dtmTreeWalker = new TreeWalker2Result(transformer, handler);
-             int nodePos;
+             else if (sequenceItem.getType() == XObject.CLASS_NODESET) {
+                 DTMIterator nl1 = sequenceItem.iter();
 
-             while (DTM.NULL != (nodePos = dtmIter.nextNode())) {
-               DTM dtm = xctxt.getDTMManager().getDTM(nodePos);
-               short t = dtm.getNodeType(nodePos);
+                 DTMTreeWalker tw1 = new TreeWalker2Result(transformer, handler);
+                 int pos1;
 
-               if (t == DTM.DOCUMENT_NODE) {
-                 for (int child = dtm.getFirstChild(nodePos); child != DTM.NULL; 
-                                                                 child = dtm.getNextSibling(child)) {
-                   dtmTreeWalker.traverse(child);
-                 }
-               }
-               else if (t == DTM.ATTRIBUTE_NODE) {
-                 SerializerUtils.addAttribute(handler, nodePos);
-               }
-               else {
-                 dtmTreeWalker.traverse(nodePos);
-               }
+                 while (DTM.NULL != (pos1 = nl1.nextNode())) {
+                     DTM dtm = xctxt.getDTMManager().getDTM(pos1);
+                     short t = dtm.getNodeType(pos1);
+                   
+                     if (t == DTM.DOCUMENT_NODE) {
+                        for (int child = dtm.getFirstChild(pos1); child != DTM.NULL; 
+                                                                     child = dtm.getNextSibling(child)) {
+                            tw1.traverse(child);
+                        }
+                     }
+                     else if (t == DTM.ATTRIBUTE_NODE) {
+                         SerializerUtils.addAttribute(handler, pos1);
+                     }
+                     else {
+                         tw1.traverse(pos1);
+                     }
+                 }    
              }
           }
+          
           break;
         default :
           
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index 3b49f83a..1aea175c 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -21,6 +21,7 @@
 package org.apache.xpath.compiler;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.xml.transform.ErrorListener;
@@ -76,6 +77,16 @@ public class XPathParser
   protected final static int FILTER_MATCH_PRIMARY    = 1;
   protected final static int FILTER_MATCH_PREDICATES = 2;
   
+  /*
+   * While parsing XPath 3.1 "function item" inline function expressions, we use this 
+   * constant string array to make parse decisions. The elements of this array are certain 
+   * XPath operator names that need this support.
+   */
+  static final String[] XPATH_INLINE_FN_OP_ARR = new String[] {"div", "or", "and", "mod", "to", 
+                                                                   "eq", "ne", "lt", "gt", "le", "ge"};
+  
+  List<String> fXpathInlineFunctionOpTokensList = null;
+  
   static InlineFunction fInlineFunction = null;
 
   /**
@@ -85,6 +96,7 @@ public class XPathParser
   {
     m_errorListener = errorListener;
     m_sourceLocator = sourceLocator;
+    fXpathInlineFunctionOpTokensList = Arrays.asList(XPATH_INLINE_FN_OP_ARR);
   }
 
   /**
@@ -1626,6 +1638,15 @@ public class XPathParser
       
       consumeExpected('{');
       
+      // While parsing the XPath expression string that forms body of inline
+      // function expression, we only get this XPath expression's string value,
+      // as determined below and store that within an object of class 
+      // 'InlineFunction', which is later used during evaluation of XPath 3.1
+      // higher-order functions like fn:for-each, fn:filter.
+      // This seems to be unlike all other XPath expression parsing (i.e, not involving
+      // the function item inline function expressions) implemented by XalanJ's XPath 1.0
+      // processor that uses this XPathParser class.
+      
       List<String> funcBodyXPathExprStrPartsList = new ArrayList<String>();
       
       if (tokenIs('}')) {
@@ -1647,22 +1668,28 @@ public class XPathParser
       for (int idx = 0; idx < funcBodyXPathExprStrPartsArr.length; idx++) {
           String xpathExprStrPart = null;
           
+          boolean isXpathInlineFunctionOpToken = false;
+          
           if ("$".equals(funcBodyXPathExprStrPartsArr[idx]) && (idx < 
                                                                   (funcBodyXPathExprStrPartsArr.length - 1))) {
+              // this handles, variable references within XPath expression inline function's body
               xpathExprStrPart = "$" + funcBodyXPathExprStrPartsArr[idx + 1];
               idx += 1;
           }
-          else {
-              xpathExprStrPart = (String)funcBodyXPathExprStrPartsArr[idx]; 
+          else {              
+              xpathExprStrPart = (String)funcBodyXPathExprStrPartsArr[idx];
+              if (fXpathInlineFunctionOpTokensList.contains(xpathExprStrPart)) {
+                 isXpathInlineFunctionOpToken = true;   
+              }
           }
           
-          funcBodyXPathExprStrBuff.append(xpathExprStrPart + " ");
+          funcBodyXPathExprStrBuff.append(isXpathInlineFunctionOpToken ? " " + xpathExprStrPart + 
+                                                                                           " " : xpathExprStrPart);
       }
       
-      funcBodyXPathExprStr = funcBodyXPathExprStrBuff.toString();
+      funcBodyXPathExprStr = (funcBodyXPathExprStrBuff.toString()).trim();
       
       if (funcBodyXPathExprStr.length() > 0) {
-         funcBodyXPathExprStr = funcBodyXPathExprStr.substring(0, funcBodyXPathExprStr.length() - 1); 
          inlineFunction.setFuncBodyXPathExprStr(funcBodyXPathExprStr);
       }
       
diff --git a/src/org/apache/xpath/functions/FuncCount.java b/src/org/apache/xpath/functions/FuncCount.java
index 3ca8f438..074c33d0 100644
--- a/src/org/apache/xpath/functions/FuncCount.java
+++ b/src/org/apache/xpath/functions/FuncCount.java
@@ -27,6 +27,7 @@ import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XNodeSet;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.Range;
 import org.apache.xpath.operations.Variable;
 
 /**
@@ -69,9 +70,15 @@ public class FuncCount extends FunctionOneArg
            }
         }
         else if (m_arg0 instanceof Expression) {
-            DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
-            count = nl.getLength();	
-            nl.detach();
+            if (m_arg0 instanceof Range) {
+                ResultSequence resultSeq = (ResultSequence)(((Range)m_arg0).execute(xctxt));
+                count = resultSeq.size();
+            }
+            else {
+               DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
+               count = nl.getLength();	
+               nl.detach();
+            }
         }
     
         return new XNumber((double)count);    
diff --git a/src/org/apache/xpath/functions/FuncFilter.java b/src/org/apache/xpath/functions/FuncFilter.java
index 933ce64e..995f47ed 100644
--- a/src/org/apache/xpath/functions/FuncFilter.java
+++ b/src/org/apache/xpath/functions/FuncFilter.java
@@ -220,7 +220,7 @@ public class FuncFilter extends Function2Args {
            
            int dtmNodeHandle;
            
-           while (DTM.NULL != (dtmNodeHandle = arg0DtmIterator.nextNode())) {
+           while (DTM.NULL != (dtmNodeHandle = arg0DtmIterator.nextNode())) {               
                XNodeSet inpSeqItem = new XNodeSet(dtmNodeHandle, xctxt.getDTMManager());
                if (varQname != null) {
                   inlineFunctionVarMap.put(varQname, inpSeqItem);
diff --git a/tests/fn_filter/gold/test7.out b/tests/fn_filter/gold/test7.out
new file mode 100644
index 00000000..a0d9cd9f
--- /dev/null
+++ b/tests/fn_filter/gold/test7.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <a>5</a>
+  <a>6</a>
+</result>
diff --git a/tests/fn_filter/test7.xsl b/tests/fn_filter/test7.xsl
new file mode 100644
index 00000000..21b33eaf
--- /dev/null
+++ b/tests/fn_filter/test7.xsl
@@ -0,0 +1,38 @@
+<?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 -->
+   
+   <!-- Test for the XPath 3.1 fn:filter() function -->                
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <result>
+	     <xsl:variable name="func1" select="function($x) { count(3 to $x) lt 5 }"/>	 
+	     <xsl:copy-of select="filter(a, $func1)"/>
+      </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/org/apache/xalan/xpath3/FnFilterTests.java b/tests/org/apache/xalan/xpath3/FnFilterTests.java
index 67b9e53e..c322935f 100644
--- a/tests/org/apache/xalan/xpath3/FnFilterTests.java
+++ b/tests/org/apache/xalan/xpath3/FnFilterTests.java
@@ -109,5 +109,15 @@ public class FnFilterTests extends XslTransformTestsUtil {
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, 
                                                             new XslTestsErrorHandler());
     }
+    
+    @Test
+    public void xslFnFilterTest7() {
+        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);
+    }
 
 }


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