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/07 11:47:15 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 'if' conditional expression, and few related new working 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 1d55a98f committing implementation of xpath 3.1 'if' conditional expression, and few related new working test cases
     new f8483e13 Merge pull request #21 from mukulga/xalan-j_xslt3.0_mukul
1d55a98f is described below

commit 1d55a98f4daad55e8053de710ec481552dd8ffd2
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Jul 7 17:10:12 2023 +0530

    committing implementation of xpath 3.1 'if' conditional expression, and few related new working test cases
---
 src/org/apache/xpath/compiler/Compiler.java    |   7 ++
 src/org/apache/xpath/compiler/OpCodes.java     |   4 +-
 src/org/apache/xpath/compiler/XPathParser.java | 105 +++++++++++++++---
 src/org/apache/xpath/composite/IfExpr.java     | 142 +++++++++++++++++++++++++
 tests/if_expr/gold/test1.out                   |   1 +
 tests/if_expr/gold/test2.out                   |   1 +
 tests/if_expr/gold/test3.out                   |  10 ++
 tests/if_expr/gold/test4.out                   |  26 +++++
 tests/if_expr/gold/test5.out                   |   6 ++
 tests/if_expr/gold/test6.out                   |  14 +++
 tests/if_expr/test1.xsl                        |  37 +++++++
 tests/if_expr/test1_a.xml                      |   5 +
 tests/if_expr/test1_b.xml                      |   5 +
 tests/if_expr/test1_c.xml                      |  23 ++++
 tests/if_expr/test1_d.xml                      |  11 ++
 tests/if_expr/test1_e.xml                      |  21 ++++
 tests/if_expr/test2.xsl                        |  38 +++++++
 tests/if_expr/test3.xsl                        |  49 +++++++++
 tests/if_expr/test4.xsl                        |  46 ++++++++
 tests/if_expr/test5.xsl                        |  56 ++++++++++
 tests/org/apache/xalan/xpath3/IfExprTests.java | 110 +++++++++++++++++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java |   3 +-
 22 files changed, 706 insertions(+), 14 deletions(-)

diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index 1ee1b6d0..b67d3c51 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -129,6 +129,8 @@ public class Compiler extends OpMap
     {
     case OpCodes.OP_XPATH :
       expr = compile(opPos + 2); break;
+    case OpCodes.OP_IF_EXPR :
+      expr = ifExpr(opPos); break;
     case OpCodes.OP_OR :
       expr = or(opPos); break;
     case OpCodes.OP_AND :
@@ -1170,6 +1172,11 @@ private static final boolean DEBUG = false;
   {
       return XPathParser.fDynamicFunctionCall;
   }
+  
+  Expression ifExpr(int opPos) throws TransformerException
+  {
+      return XPathParser.fIfExpr;
+  }
 
   // The current id for extension functions.
   private static long s_nextMethodId = 0;
diff --git a/src/org/apache/xpath/compiler/OpCodes.java b/src/org/apache/xpath/compiler/OpCodes.java
index bdf4a5db..92fb38f5 100644
--- a/src/org/apache/xpath/compiler/OpCodes.java
+++ b/src/org/apache/xpath/compiler/OpCodes.java
@@ -679,8 +679,10 @@ public class OpCodes
   public static final int OP_INLINE_FUNCTION = 61;
   
   public static final int OP_DYNAMIC_FUNCTION_CALL = 62;
+  
+  public static final int OP_IF_EXPR = 63;
 
   /** The next free ID. Please keep this up to date. */
-  private static final int NEXT_FREE_ID = 63;
+  private static final int NEXT_FREE_ID = 64;
   
 }
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index a833379f..c5493cf6 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -30,6 +30,7 @@ import javax.xml.transform.TransformerException;
 import org.apache.xalan.res.XSLMessages;
 import org.apache.xml.utils.PrefixResolver;
 import org.apache.xpath.XPathProcessorException;
+import org.apache.xpath.composite.IfExpr;
 import org.apache.xpath.domapi.XPathStylesheetDOM3Exception;
 import org.apache.xpath.functions.DynamicFunctionCall;
 import org.apache.xpath.objects.InlineFunction;
@@ -79,19 +80,23 @@ public class XPathParser
   protected final static int FILTER_MATCH_PREDICATES = 2;
   
   /*
-   * While parsing XPath 3.1 "function item" inline function expressions and, 
-   * dynamic function calls, we use this constant string array to make parse 
-   * decisions. The elements of this array are certain XPath operator names 
-   * that need this support.
+   * While parsing certain XPath 3.1 expressions, we use this constant string 
+   * array to make parse decisions. The elements of this array are certain 
+   * XPath 'operator names' and 'key words' that need this support.
    */
   private static final String[] XPATH_OP_ARR = new String[] {"div", "or", "and", "mod", "to", 
-                                                                "eq", "ne", "lt", "gt", "le", "ge"};
+                                                              "eq", "ne", "lt", "gt", "le", "ge", 
+                                                              "if", "then", "else"};
   
   private List<String> fXpathOpArrTokensList = null;
   
   static InlineFunction fInlineFunction = null;
   
   static DynamicFunctionCall fDynamicFunctionCall = null;
+  
+  static IfExpr fIfExpr = null;
+  
+  private boolean fIsXpathPredicateParsingActive = false;
 
   /**
    * The parser constructor.
@@ -599,7 +604,8 @@ public class XPathParser
           
           if ("$".equals(funcBodyXPathExprStrPartsArr[idx]) && (idx < 
                                                                   (funcBodyXPathExprStrPartsArr.length - 1))) {
-              // this handles, variable references within XPath expression inline function's body
+              // this handles, variable references within XPath expression string
+              // that's been formed within this method.
               xpathExprStrPart = "$" + funcBodyXPathExprStrPartsArr[idx + 1];
               idx += 1;
           }
@@ -831,14 +837,86 @@ public class XPathParser
   /**
    *
    *
-   * Expr  ::=  OrExpr
-   *
+   * Expr  ::=  IfExpr 
+   *   | OrExpr
    *
    * @throws javax.xml.transform.TransformerException
    */
   protected void Expr() throws javax.xml.transform.TransformerException
   {
-    OrExpr();
+      if (tokenIs("if")) {         
+         fIfExpr = IfExpr();
+      }
+      else {
+         OrExpr();
+      }
+  }
+  
+  protected IfExpr IfExpr() throws javax.xml.transform.TransformerException
+  {
+      int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH);
+      
+      nextToken();
+      
+      insertOp(opPos, 2, OpCodes.OP_IF_EXPR);
+      
+      IfExpr ifExpr = new IfExpr();            
+      
+      consumeExpected('(');
+      
+      List<String> conditionalExprXPathStrPartsList = new ArrayList<String>();
+      
+      while (!tokenIs("then") && m_token != null)
+      {
+          conditionalExprXPathStrPartsList.add(m_token);
+          nextToken();
+      }
+      
+      consumeExpected("then");
+      
+      conditionalExprXPathStrPartsList = conditionalExprXPathStrPartsList.subList(0, 
+                                                             conditionalExprXPathStrPartsList.size() - 1);
+      
+      String conditionalXPathExprStr = getXPathStrFromComponentParts(conditionalExprXPathStrPartsList);
+      
+      List<String> thenExprXPathStrPartsList = new ArrayList<String>();
+      
+      while (!tokenIs("else") && m_token != null)
+      {
+          thenExprXPathStrPartsList.add(m_token);
+          nextToken();
+      }
+      
+      consumeExpected("else");
+      
+      String thenXPathExprStr = getXPathStrFromComponentParts(thenExprXPathStrPartsList);            
+      
+      List<String> elseExprXPathStrPartsList = new ArrayList<String>();
+      
+      while (m_token != null)
+      {
+          if (fIsXpathPredicateParsingActive && lookahead(']', 1)) {
+             elseExprXPathStrPartsList.add(m_token);
+             elseExprXPathStrPartsList.subList(0, elseExprXPathStrPartsList.size() - 1);
+             nextToken();
+             break;
+          }
+          else {
+             elseExprXPathStrPartsList.add(m_token);
+             nextToken();
+          }          
+      }
+      
+      String elseXPathExprStr = getXPathStrFromComponentParts(elseExprXPathStrPartsList);
+      
+      ifExpr.setConditionalExprXPathStr(conditionalXPathExprStr);
+      ifExpr.setThenExprXPathStr(thenXPathExprStr);
+      ifExpr.setElseExprXPathStr(elseXPathExprStr);
+      
+      m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH,
+                                    m_ops.getOp(OpMap.MAPINDEX_LENGTH) - opPos);
+      
+      return ifExpr;      
   }
 
   /**
@@ -1548,7 +1626,7 @@ public class XPathParser
    * | FunctionCall
    * | FunctionItemExpr
    * 
-   * The XPath grammar option 'VarRef ArgumentList' shown above
+   * The XPath grammar option 'VarRef ArgumentList' mentioned above
    * denotes, dynamic function call.
    *
    * @return true if this method successfully matched a PrimaryExpr
@@ -2239,9 +2317,12 @@ public class XPathParser
 
     if (tokenIs('['))
     {
+      fIsXpathPredicateParsingActive = true;
+      
       nextToken();
-      PredicateExpr();
-      consumeExpected(']');
+      PredicateExpr();      
+      fIsXpathPredicateParsingActive = false;      
+      consumeExpected(']');                  
     }
   }
 
diff --git a/src/org/apache/xpath/composite/IfExpr.java b/src/org/apache/xpath/composite/IfExpr.java
new file mode 100644
index 00000000..e5364d94
--- /dev/null
+++ b/src/org/apache/xpath/composite/IfExpr.java
@@ -0,0 +1,142 @@
+/*
+ * 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.xpath.composite;
+
+import java.util.Vector;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.XObject;
+
+/*
+ * The XalanJ xpath parser, creates and populates an object of this class, 
+ * as a representation of XPath 3.1 "if" conditional expressions.
+ * 
+ * XPath 3.1 spec, provides following definitions of conditional expressions.
+ * 
+ * Grammar fragment,
+ * IfExpr   ::=   "if" "(" Expr ")" "then" ExprSingle "else" ExprSingle
+ * 
+ * The expression following the if keyword is called the test expression, and 
+ * the expressions following the then and else keywords are called the 
+ * then-expression and else-expression, respectively.
+ * 
+ * The first step in processing a conditional expression is to find the 
+ * effective boolean value of the test expression.
+ * 
+ * The value of a conditional expression is defined as follows: If the 
+ * effective boolean value of the test expression is true, the value of 
+ * the then-expression is returned. If the effective boolean value of the 
+ * test expression is false, the value of the else-expression is returned.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class IfExpr extends Expression {
+    
+    private static final long serialVersionUID = 4057572946055830336L;
+
+    private String conditionalExprXPathStr;
+    
+    private String thenExprXPathStr;
+    
+    private String elseExprXPathStr;
+    
+    // the following two fields of this class, are used during 
+    // XPath.fixupVariables(..) action as performed within object of 
+    // this class.    
+    private Vector fVars;    
+    private int fGlobalsSize;
+
+    public String getConditionalExprXPathStr() {
+        return conditionalExprXPathStr;
+    }
+
+    public void setConditionalExprXPathStr(String conditionalExprXPathStr) {
+        this.conditionalExprXPathStr = conditionalExprXPathStr;
+    }
+
+    public String getThenExprXPathStr() {
+        return thenExprXPathStr;
+    }
+
+    public void setThenExprXPathStr(String thenExprXPathStr) {
+        this.thenExprXPathStr = thenExprXPathStr;
+    }
+
+    public String getElseExprXPathStr() {
+        return elseExprXPathStr;
+    }
+
+    public void setElseExprXPathStr(String elseExprXPathStr) {
+        this.elseExprXPathStr = elseExprXPathStr;
+    }
+
+    @Override
+    public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) {
+       // no op       
+    }
+
+    @Override
+    public XObject execute(XPathContext xctxt) throws TransformerException {
+       XObject evalResult = null;
+       
+       SourceLocator srcLocator = xctxt.getSAXLocator();
+       
+       int contextNode = xctxt.getContextNode();
+       
+       XPath conditionlExprXpath = new XPath(conditionalExprXPathStr, srcLocator, null, 
+                                                                            XPath.SELECT, null);
+       conditionlExprXpath.fixupVariables(fVars, fGlobalsSize);
+       
+       XObject conditionalXpathExprResult = conditionlExprXpath.execute(xctxt, contextNode, null);
+       
+       if (conditionalXpathExprResult.bool()) {
+           XPath thenExprXpath = new XPath(thenExprXPathStr, srcLocator, null, XPath.SELECT, null);
+           thenExprXpath.fixupVariables(fVars, fGlobalsSize);
+           
+           evalResult = thenExprXpath.execute(xctxt, contextNode, null);
+       }
+       else {
+           XPath elseExprXpath = new XPath(elseExprXPathStr, srcLocator, null, XPath.SELECT, null);
+           elseExprXpath.fixupVariables(fVars, fGlobalsSize);
+           
+           evalResult = elseExprXpath.execute(xctxt, contextNode, null);
+       }
+       
+       return evalResult;
+    }
+
+    @Override
+    public void fixupVariables(Vector vars, int globalsSize) {
+        fVars = (Vector)(vars.clone());
+        fGlobalsSize = globalsSize; 
+    }
+
+    @Override
+    public boolean deepEquals(Expression expr) {
+       return false;
+    }
+
+}
diff --git a/tests/if_expr/gold/test1.out b/tests/if_expr/gold/test1.out
new file mode 100644
index 00000000..c46008d2
--- /dev/null
+++ b/tests/if_expr/gold/test1.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>x is less than y</result>
diff --git a/tests/if_expr/gold/test2.out b/tests/if_expr/gold/test2.out
new file mode 100644
index 00000000..9229ad61
--- /dev/null
+++ b/tests/if_expr/gold/test2.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>x is greater or equal to y</result>
diff --git a/tests/if_expr/gold/test3.out b/tests/if_expr/gold/test3.out
new file mode 100644
index 00000000..45d82e28
--- /dev/null
+++ b/tests/if_expr/gold/test3.out
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <item>
+    <a>7</a>
+    <b>2</b>
+  </item>
+  <item>
+    <a>8</a>
+    <b>2</b>
+  </item>
+</result>
diff --git a/tests/if_expr/gold/test4.out b/tests/if_expr/gold/test4.out
new file mode 100644
index 00000000..ebc30932
--- /dev/null
+++ b/tests/if_expr/gold/test4.out
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <lessOrEqual count="3">
+    <item>
+    <a>1</a>
+    <b>3</b>
+  </item>
+    <item>
+    <a>2</a>
+    <b>5</b>
+  </item>
+    <item>
+    <a>4</a>
+    <b>12</b>
+  </item>
+  </lessOrEqual>
+  <greater count="2">
+    <item>
+    <a>7</a>
+    <b>2</b>
+  </item>
+    <item>
+    <a>8</a>
+    <b>2</b>
+  </item>
+  </greater>
+</result>
diff --git a/tests/if_expr/gold/test5.out b/tests/if_expr/gold/test5.out
new file mode 100644
index 00000000..6af91649
--- /dev/null
+++ b/tests/if_expr/gold/test5.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <widget>
+      <name>abc</name>
+      <unit-cost>7</unit-cost>
+   </widget>
+</result>
diff --git a/tests/if_expr/gold/test6.out b/tests/if_expr/gold/test6.out
new file mode 100644
index 00000000..b8a33306
--- /dev/null
+++ b/tests/if_expr/gold/test6.out
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <part>
+    <name>part1</name>
+    <wholesale>
+       <price>5</price>
+    </wholesale>
+  </part>
+  <part>
+    <name>part2</name>
+    <retail>
+       <price>15</price>       
+    </retail>
+  </part>
+</result>
diff --git a/tests/if_expr/test1.xsl b/tests/if_expr/test1.xsl
new file mode 100644
index 00000000..7e6941e8
--- /dev/null
+++ b/tests/if_expr/test1.xsl
@@ -0,0 +1,37 @@
+<?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, test1_b.xml -->
+   
+   <!-- An XSLT stylesheet, to test "if" conditional expression. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <result>
+         <xsl:value-of select="if (x lt y) then ('x is less than y') else ('x is greater or equal to y')"/>   
+      </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/if_expr/test1_a.xml b/tests/if_expr/test1_a.xml
new file mode 100644
index 00000000..c67c2ed4
--- /dev/null
+++ b/tests/if_expr/test1_a.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+  <x>3</x>
+  <y>7</y>
+</elem>
\ No newline at end of file
diff --git a/tests/if_expr/test1_b.xml b/tests/if_expr/test1_b.xml
new file mode 100644
index 00000000..64985618
--- /dev/null
+++ b/tests/if_expr/test1_b.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+  <x>7</x>
+  <y>3</y>
+</elem>
\ No newline at end of file
diff --git a/tests/if_expr/test1_c.xml b/tests/if_expr/test1_c.xml
new file mode 100644
index 00000000..c6e81550
--- /dev/null
+++ b/tests/if_expr/test1_c.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+  <item>
+    <a>1</a>
+    <b>3</b>
+  </item>
+  <item>
+    <a>2</a>
+    <b>5</b>
+  </item>
+  <item>
+    <a>7</a>
+    <b>2</b>
+  </item>
+  <item>
+    <a>8</a>
+    <b>2</b>
+  </item>
+  <item>
+    <a>4</a>
+    <b>12</b>
+  </item>
+</elem>
\ No newline at end of file
diff --git a/tests/if_expr/test1_d.xml b/tests/if_expr/test1_d.xml
new file mode 100644
index 00000000..cec0a65b
--- /dev/null
+++ b/tests/if_expr/test1_d.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widgets>
+   <widget>
+      <name>abc</name>
+      <unit-cost>7</unit-cost>
+   </widget>
+   <widget>
+      <name>pqr</name>
+      <unit-cost>10</unit-cost>
+   </widget>
+</widgets>
\ No newline at end of file
diff --git a/tests/if_expr/test1_e.xml b/tests/if_expr/test1_e.xml
new file mode 100644
index 00000000..ee9110e6
--- /dev/null
+++ b/tests/if_expr/test1_e.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<parts>
+  <part discounted="part_is_discounted">
+    <name>part1</name>
+    <wholesale>
+       <price>5</price>
+    </wholesale>
+    <retail>
+       <price>7</price>  
+    </retail>
+  </part>
+  <part>
+    <name>part2</name>
+    <wholesale>
+       <price>12</price>    
+    </wholesale>
+    <retail>
+       <price>15</price>       
+    </retail>
+  </part>
+</parts>
\ No newline at end of file
diff --git a/tests/if_expr/test2.xsl b/tests/if_expr/test2.xsl
new file mode 100644
index 00000000..0fd90efa
--- /dev/null
+++ b/tests/if_expr/test2.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_c.xml -->
+   
+   <!-- An XSLT stylesheet, to test "if" conditional expression
+        that exists within an XPath predicate. -->                 
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/elem">
+      <result>
+         <xsl:copy-of select="item[if (number(a) gt number(b)) then true() else false()]"/>
+      </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/if_expr/test3.xsl b/tests/if_expr/test3.xsl
new file mode 100644
index 00000000..ec49a577
--- /dev/null
+++ b/tests/if_expr/test3.xsl
@@ -0,0 +1,49 @@
+<?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_c.xml -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 "if" conditional 
+        expression, when used within xsl:for-each-group to transform
+        the current-grouping-key() value. -->                 
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="gThan" select="function($x, $y) { $x gt $y }"/>
+
+   <xsl:template match="/elem">
+      <result>
+        <xsl:for-each-group select="item" group-by="$gThan(a, b)">
+           <xsl:variable name="grtOrLess" select="if (string(current-grouping-key()) eq 'true') 
+                                                                  then 'greater' 
+                                                                  else 'lessOrEqual'"/>
+           <xsl:element name="{normalize-space($grtOrLess)}">
+              <xsl:attribute name="count" select="count(current-group())"/>
+              <xsl:copy-of select="current-group()"/>
+           </xsl:element>
+        </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/if_expr/test4.xsl b/tests/if_expr/test4.xsl
new file mode 100644
index 00000000..9218bffc
--- /dev/null
+++ b/tests/if_expr/test4.xsl
@@ -0,0 +1,46 @@
+<?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_d.xml -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 "if" conditional 
+        expression. The XPath "if" conditional expression example 
+        illustrated within this stylesheet test, is borrowed from 
+        XPath 3.1 spec, with minor modifications. This stylesheet
+        example uses the fn:number function, but XPath 3.1 spec 
+        doesn't. -->                 
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/widgets">
+      <result>
+        <xsl:variable name="widget1" select="widget[1]"/>
+        <xsl:variable name="widget2" select="widget[2]"/>
+        <xsl:copy-of select="if (number($widget1/unit-cost) &lt; number($widget2/unit-cost)) 
+                                     then $widget1 
+                                     else $widget2"/>
+      </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/if_expr/test5.xsl b/tests/if_expr/test5.xsl
new file mode 100644
index 00000000..4954d9f6
--- /dev/null
+++ b/tests/if_expr/test5.xsl
@@ -0,0 +1,56 @@
+<?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_e.xml -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 "if" conditional 
+        expression. The XPath "if" conditional expression example 
+        illustrated within this stylesheet test, is borrowed from 
+        XPath 3.1 spec. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/parts">
+      <result>
+         <xsl:call-template name="analyzePart">
+            <xsl:with-param name="part" select="part[1]"/>
+         </xsl:call-template>
+         <xsl:call-template name="analyzePart">
+	        <xsl:with-param name="part" select="part[2]"/>
+         </xsl:call-template>
+      </result>
+   </xsl:template>
+   
+   <xsl:template name="analyzePart">
+      <xsl:param name="part"/>
+      
+      <part>
+         <xsl:copy-of select="$part/name"/>
+         <xsl:copy-of select="if ($part/@discounted)
+                                    then $part/wholesale
+                                    else $part/retail"/>
+      </part>
+   </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/IfExprTests.java b/tests/org/apache/xalan/xpath3/IfExprTests.java
new file mode 100644
index 00000000..4e422b93
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/IfExprTests.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+/**
+ * XPath 3.1 test cases, for "if" conditional expressions.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class IfExprTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "if_expr/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "if_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 xslIfExprTest1() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslIfExprTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslIfExprTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_c.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslIfExprTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_c.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslIfExprTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_d.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslIfExprTest6() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_e.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test6.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 0aae607c..e5176c6b 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -24,6 +24,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.IfExprTests;
 import org.apache.xalan.xpath3.InlineFunctionItemExprTests;
 import org.apache.xalan.xpath3.RangeExprTests;
 import org.apache.xalan.xpath3.SequenceTests;
@@ -54,7 +55,7 @@ import org.junit.runners.Suite.SuiteClasses;
                 FnIndexOfTests.class, SequenceTests.class, RangeExprTests.class, 
                 W3c_xslt30_IterateTests.class, W3c_xslt30_AxesTests.class, XslIterateTests.class,
                 ValueComparisonTests.class, InlineFunctionItemExprTests.class, FnForEachTests.class, 
-                FnFilterTests.class, DynamicFunctionCallTests.class })
+                FnFilterTests.class, DynamicFunctionCallTests.class, IfExprTests.class })
 public class AllXsl3Tests {
 
 }


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