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/18 14:26:44 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: implementation of xpath 3.1 function fn:distinct-values. improvements to xpath 3.1 function implementations for fn:index-of, fn:string-join, fn:tokenize. implementation of XML Schema data types xs:untyped, xs:untypedAtomic for xslt 3.0 processing. minor improvement to xpath expression lexer, to recognize the characters '{', '}' as valid xpath 3.1 language tokens. committing few related new working test cases as well. minor improvements to few other parts of, xalanj xslt 3.0 processor codebase.

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 e6824e6f implementation of xpath 3.1 function fn:distinct-values. improvements to xpath 3.1 function implementations for fn:index-of, fn:string-join, fn:tokenize. implementation of XML Schema data types xs:untyped, xs:untypedAtomic for xslt 3.0 processing. minor improvement to xpath expression lexer, to recognize the characters '{', '}' as valid xpath 3.1 language tokens. committing few related new working test cases as well. minor improvements to few other parts of, xalanj xslt  [...]
     new c341c7c9 Merge pull request #31 from mukulga/xalan-j_xslt3.0_mukul
e6824e6f is described below

commit e6824e6f6552cf730a950423913101f3153f9427
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Tue Jul 18 19:46:17 2023 +0530

    implementation of xpath 3.1 function fn:distinct-values. improvements to xpath 3.1 function implementations for fn:index-of, fn:string-join, fn:tokenize. implementation of XML Schema data types xs:untyped, xs:untypedAtomic for xslt 3.0 processing. minor improvement to xpath expression lexer, to recognize the characters '{', '}' as valid xpath 3.1 language tokens. committing few related new working test cases as well. minor improvements to few other parts of, xalanj xslt 3.0 processor  [...]
---
 src/org/apache/xalan/templates/ElemCopyOf.java     |  16 ++
 src/org/apache/xpath/compiler/FunctionTable.java   |   9 +-
 src/org/apache/xpath/compiler/Keywords.java        |   3 +
 src/org/apache/xpath/compiler/Lexer.java           |   8 +-
 .../apache/xpath/functions/FuncDistinctValues.java | 237 +++++++++++++++++++++
 src/org/apache/xpath/functions/FuncIndexOf.java    | 124 ++++++++++-
 src/org/apache/xpath/functions/FuncStringJoin.java |  87 ++++++--
 src/org/apache/xpath/functions/FuncTokenize.java   |   7 +-
 src/org/apache/xpath/xs/types/XSUntyped.java       |  78 +++++++
 src/org/apache/xpath/xs/types/XSUntypedAtomic.java |  95 +++++++++
 tests/fn_distinct_values/gold/test1.out            |   6 +
 tests/fn_distinct_values/gold/test2.out            |   1 +
 tests/fn_distinct_values/gold/test3.out            |   5 +
 tests/fn_distinct_values/gold/test4.out            |   6 +
 tests/fn_distinct_values/gold/test5.out            |   7 +
 .../test1.xsl                                      |  18 +-
 tests/fn_distinct_values/test1_a.xml               |  12 ++
 tests/fn_distinct_values/test1_b.xml               |  12 ++
 tests/fn_distinct_values/test1_c.xml               |  12 ++
 tests/fn_distinct_values/test1_d.xml               |  12 ++
 tests/fn_distinct_values/test1_e.xml               |  12 ++
 .../test1.xsl => fn_distinct_values/test2.xsl}     |  15 +-
 .../test1.xsl => fn_distinct_values/test3.xsl}     |  18 +-
 .../test1.xsl => fn_distinct_values/test4.xsl}     |  15 +-
 .../test1.xsl => fn_distinct_values/test5.xsl}     |  18 +-
 .../test1.xsl => fn_distinct_values/test6.xsl}     |  18 +-
 .../test1.xsl => fn_distinct_values/test7.xsl}     |  19 +-
 tests/fn_indexof/gold/test1.out                    |   4 +-
 tests/fn_indexof/gold/test2.out                    |   1 +
 tests/fn_indexof/gold/test3.out                    |   5 +
 tests/fn_indexof/test1.xsl                         |   4 +-
 tests/fn_indexof/test1_a.xml                       |  12 ++
 tests/fn_indexof/test1_b.xml                       |  12 ++
 .../test1.xsl => fn_indexof/test2.xsl}             |  15 +-
 .../test1.xsl => fn_indexof/test3.xsl}             |  15 +-
 .../test1.xsl => fn_indexof/test4.xsl}             |  16 +-
 tests/fn_indexof/{test1.xsl => test5.xsl}          |  17 +-
 tests/fn_indexof/{test1.xsl => test6.xsl}          |  17 +-
 .../test1.out => fn_string_join/gold/test2.out}    |   4 +-
 tests/fn_string_join/gold/test3.out                |   4 +
 tests/fn_string_join/gold/test4.out                |   4 +
 tests/fn_string_join/test1.xsl                     |   2 +
 tests/fn_string_join/test1_a.xml                   |  12 ++
 tests/fn_string_join/test1_b.xml                   |  13 ++
 tests/fn_string_join/{test1.xsl => test2.xsl}      |  12 +-
 tests/fn_string_join/{test1.xsl => test3.xsl}      |  16 +-
 tests/fn_string_join/{test1.xsl => test4.xsl}      |  16 +-
 .../test1.xsl => fn_string_join/test5.xsl}         |  15 +-
 tests/inline_function_expr/gold/test5.out          |   1 +
 .../test1.xsl => inline_function_expr/test5.xsl}   |  12 +-
 tests/let_expr/test2.xsl                           |   8 +-
 ...emExprTests.java => FnDistinctValuesTests.java} |  67 ++++--
 tests/org/apache/xalan/xpath3/FnIndexOfTests.java  |  50 +++++
 .../org/apache/xalan/xpath3/FnStringJoinTests.java |  40 ++++
 .../xalan/xpath3/InlineFunctionItemExprTests.java  |  10 +
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   3 +-
 56 files changed, 1114 insertions(+), 163 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemCopyOf.java b/src/org/apache/xalan/templates/ElemCopyOf.java
index d1dd523f..54242ddb 100644
--- a/src/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/org/apache/xalan/templates/ElemCopyOf.java
@@ -35,6 +35,8 @@ import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
 
 /*
  * Implementation of XSLT xsl:copy-of instruction.
@@ -221,6 +223,20 @@ public class ElemCopyOf extends ElemTemplateElement
                     handler.characters(spaceCharArr, 0, 1);
                  }
              }
+             else if (sequenceItem instanceof XSUntyped) {
+                 String str = ((XSUntyped)sequenceItem).stringValue();
+                 handler.characters(str.toCharArray(), 0, str.length());
+                 if (idx < (resultSequence.size() - 1)) {                     
+                    handler.characters(spaceCharArr, 0, 1);
+                 }
+             }
+             else if (sequenceItem instanceof XSUntypedAtomic) {
+                 String str = ((XSUntypedAtomic)sequenceItem).stringValue();
+                 handler.characters(str.toCharArray(), 0, str.length());
+                 if (idx < (resultSequence.size() - 1)) {                     
+                    handler.characters(spaceCharArr, 0, 1);
+                 } 
+             }
              else if (sequenceItem.getType() == XObject.CLASS_NODESET) {
                  DTMIterator nl1 = sequenceItem.iter();
 
diff --git a/src/org/apache/xpath/compiler/FunctionTable.java b/src/org/apache/xpath/compiler/FunctionTable.java
index e9251ee6..1ddedf23 100644
--- a/src/org/apache/xpath/compiler/FunctionTable.java
+++ b/src/org/apache/xpath/compiler/FunctionTable.java
@@ -185,6 +185,9 @@ public class FunctionTable
   
   /** The 'filter()' id. */
   public static final int FUNC_FILTER = 54;
+  
+  /** The 'distinct-values()' id. */
+  public static final int FUNC_DISTINCT_VALUES = 55;
 
   // Proprietary
 
@@ -213,7 +216,7 @@ public class FunctionTable
    * Number of built in functions. Be sure to update this as
    * built-in functions are added.
    */
-  private static final int NUM_BUILT_IN_FUNCS = 55;
+  private static final int NUM_BUILT_IN_FUNCS = 56;
 
   /**
    * Number of built-in functions that may be added.
@@ -315,6 +318,8 @@ public class FunctionTable
       org.apache.xpath.functions.FuncForEach.class;
     m_functions[FUNC_FILTER] = 
       org.apache.xpath.functions.FuncFilter.class;
+    m_functions[FUNC_DISTINCT_VALUES] = 
+      org.apache.xpath.functions.FuncDistinctValues.class;
   }
 
   static{
@@ -424,6 +429,8 @@ public class FunctionTable
                           new Integer(FunctionTable.FUNC_FOR_EACH));
           m_functionID.put(Keywords.FUNC_FILTER,
                           new Integer(FunctionTable.FUNC_FILTER));
+          m_functionID.put(Keywords.FUNC_DISTINCT_VALUES,
+                          new Integer(FunctionTable.FUNC_DISTINCT_VALUES));
   }
   
   public FunctionTable(){
diff --git a/src/org/apache/xpath/compiler/Keywords.java b/src/org/apache/xpath/compiler/Keywords.java
index 9e66c05c..04e76e38 100644
--- a/src/org/apache/xpath/compiler/Keywords.java
+++ b/src/org/apache/xpath/compiler/Keywords.java
@@ -265,6 +265,9 @@ public class Keywords
   
   /** filter function string. */
   public static final String FUNC_FILTER = "filter";
+  
+  /** distinct-values function string. */
+  public static final String FUNC_DISTINCT_VALUES = "distinct-values";
 
   // Proprietary, built in functions
 
diff --git a/src/org/apache/xpath/compiler/Lexer.java b/src/org/apache/xpath/compiler/Lexer.java
index 80c9c7ad..f48b8e61 100644
--- a/src/org/apache/xpath/compiler/Lexer.java
+++ b/src/org/apache/xpath/compiler/Lexer.java
@@ -251,15 +251,17 @@ class Lexer
       case '[' :
       case ')' :
       case ']' :
+      case '{' :   // added for XPath 3.1
+      case '}' :   // added for XPath 3.1    
       case '|' :
       case '/' :
       case '*' :
       case '+' :
       case '=' :
-      case ',' :
+      case ',' :      
       case '\\' :  // Unused at the moment
-      case '^' :  // Unused at the moment
-      case '!' :  // Unused at the moment
+      case '^' :   // Unused at the moment
+      case '!' :   // Unused at the moment
       case '$' :
       case '<' :
       case '>' :
diff --git a/src/org/apache/xpath/functions/FuncDistinctValues.java b/src/org/apache/xpath/functions/FuncDistinctValues.java
new file mode 100644
index 00000000..57147aec
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncDistinctValues.java
@@ -0,0 +1,237 @@
+/*
+ * 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.functions;
+
+import javax.xml.transform.SourceLocator;
+
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XString;
+import org.apache.xpath.res.XPATHErrorResources;
+import org.apache.xpath.xs.types.XSAnyType;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
+
+/**
+ * Execute the distinct-values() function.
+ * 
+ * XPath 3.1 F&O spec, defines the function fn:distinct-values as follows,
+ *  
+ * This function returns the values that appear in a sequence, with 
+ * duplicates eliminated.
+ * 
+ * Function signatures :
+ *      1) fn:distinct-values($arg as xs:anyAtomicType*) as xs:anyAtomicType*
+
+        2) fn:distinct-values($arg as xs:anyAtomicType*, $collation as xs:string) 
+                                                                            as xs:anyAtomicType*
+                                                                                                                                                        
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FuncDistinctValues extends Function2Args {
+    
+   private static final long serialVersionUID = -1637800188441824456L;
+    
+   private static final String FUNCTION_NAME = "distinct-values()"; 
+
+  /**
+   * Execute the function. The function must return a valid object.
+   * 
+   * @param xctxt The current execution context.
+   * 
+   * @return A valid XObject.
+   *
+   * @throws javax.xml.transform.TransformerException
+   */
+  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+  {      
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        ResultSequence resultSeq = new ResultSequence();
+        
+        Expression arg0 = getArg0();        
+        Expression arg1 = getArg1();   // the second argument of this function, is unused for now
+        
+        XObject arg0Obj = arg0.execute(xctxt);
+        
+        if (arg0Obj instanceof XNodeSet) {
+           DTMManager dtmMgr = (DTMManager)xctxt;
+           
+           int currentNode = xctxt.getCurrentNode();
+           DTMIterator sourceNodes = arg0.asIterator(xctxt, currentNode);
+           
+           int nextNodeDtmHandle;
+           
+           while ((nextNodeDtmHandle = sourceNodes.nextNode()) != DTM.NULL) {
+              XNodeSet xNodeSet = new XNodeSet(nextNodeDtmHandle, xctxt);
+              String nodeStrValue = xNodeSet.str();
+              
+              DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
+              
+              if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
+                 XSUntyped xsUntyped = new XSUntyped(nodeStrValue);                 
+                 addItemToResultSequence(resultSeq, xsUntyped, true);
+              }
+              else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
+                 XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                 addItemToResultSequence(resultSeq, xsUntypedAtomic, true);
+              }
+              else {
+                 XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                 addItemToResultSequence(resultSeq, xsUntypedAtomic, true);
+              }
+           }
+        }
+        else if (arg0Obj instanceof ResultSequence) {
+           ResultSequence inpResultSeq = (ResultSequence)arg0Obj; 
+           for (int idx = 0; idx < inpResultSeq.size(); idx++) {
+              XObject xObj = inpResultSeq.item(idx);
+              if (xObj instanceof XSAnyType) {
+                 XSAnyType xsAnyType = (XSAnyType)xObj;
+                 addItemToResultSequence(resultSeq, xsAnyType, true);
+              }
+              else {
+                 addItemToResultSequence(resultSeq, xObj, true);
+              }
+           }
+        }
+        else {
+           // we're assuming here that, an input value is an 
+           // singleton xdm item.            
+           if (arg0Obj instanceof XSAnyType) {
+              XSAnyType xsAnyType = (XSAnyType)arg0Obj;
+              addItemToResultSequence(resultSeq, xsAnyType, false);
+           }
+           else {
+              String seqItemStrValue = arg0Obj.str();
+              addItemToResultSequence(resultSeq, new XString(seqItemStrValue),
+                                                                         false);
+           }
+        }
+            
+        return resultSeq;
+  }
+
+/**
+   * Check that the number of arguments passed to this function is correct.
+   *
+   * @param argNum The number of arguments that is being passed to the function.
+   *
+   * @throws WrongNumberArgsException
+   */
+  public void checkNumberArgs(int argNum) throws WrongNumberArgsException
+  {
+     if (!(argNum == 1 || argNum == 2)) {
+        reportWrongNumberArgs();
+     }
+  }
+
+  /**
+   * Constructs and throws a WrongNumberArgException with the appropriate
+   * message for this function object.
+   *
+   * @throws WrongNumberArgsException
+   */
+  protected void reportWrongNumberArgs() throws WrongNumberArgsException {
+      throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
+                                              XPATHErrorResources.ER_ONE_OR_TWO, null)); //"1 or 2"
+  }
+  
+  /**
+   * Add an xdm input item to result sequence, if that already doesn't exist within
+   * the result sequence. 
+   */
+  private void addItemToResultSequence(ResultSequence resultSeq, XObject inpItem, 
+                                                                     boolean cardinalityCheck) {
+      if (cardinalityCheck) {
+          if (resultSeq.size() == 0) {                     
+              resultSeq.add(inpItem);    
+          }
+          else if (!contains(resultSeq, inpItem)) {
+              resultSeq.add(inpItem);
+          }   
+      }
+      else {
+          resultSeq.add(inpItem);   
+      }
+  }
+  
+  /**
+   * Check whether a 'ResultSequence' object, contains a specific xdm item.
+   */
+  private boolean contains(ResultSequence resultSeq, XObject srch) {
+     
+     boolean isSeqContains = false;
+     
+     for (int idx = 0; idx < resultSeq.size(); idx++) {
+        XObject existingItemWithinResultSeq = resultSeq.item(idx);
+        if ((existingItemWithinResultSeq instanceof XSUntyped) && 
+                                                          (srch instanceof XSUntyped)) {
+           if (((XSUntyped)existingItemWithinResultSeq).equals((XSUntyped)srch)) {
+               isSeqContains = true;
+               break;    
+           }
+        }
+        else if ((existingItemWithinResultSeq instanceof XSUntypedAtomic) && 
+                                                                (srch instanceof XSUntypedAtomic)) {
+            if (((XSUntypedAtomic)existingItemWithinResultSeq).equals((XSUntypedAtomic)srch)) {
+               isSeqContains = true;
+               break;    
+            } 
+        }
+        else if ((existingItemWithinResultSeq instanceof XSUntyped) && 
+                                                              (srch instanceof XSUntypedAtomic)) {
+            if (((XSUntyped)existingItemWithinResultSeq).equals((XSUntypedAtomic)srch)) {
+               isSeqContains = true;
+               break;    
+            } 
+        }
+        else if ((existingItemWithinResultSeq instanceof XSUntypedAtomic) && 
+                                                              (srch instanceof XSUntyped)) {
+            if (((XSUntypedAtomic)existingItemWithinResultSeq).equals((XSUntyped)srch)) {
+               isSeqContains = true;
+               break;    
+            }
+        }
+        else if ((existingItemWithinResultSeq instanceof XSAnyType) && 
+                                                               (srch instanceof XSAnyType)) {
+            if (((XSAnyType)existingItemWithinResultSeq).equals((XSAnyType)srch)) {
+                isSeqContains = true;
+                break;    
+            }   
+        }
+        else if (existingItemWithinResultSeq.equals(srch)) {
+            isSeqContains = true;
+            break;    
+        }
+     }
+     
+     return isSeqContains;
+     
+  }
+
+}
diff --git a/src/org/apache/xpath/functions/FuncIndexOf.java b/src/org/apache/xpath/functions/FuncIndexOf.java
index 67a5cbba..c9fa3bf5 100644
--- a/src/org/apache/xpath/functions/FuncIndexOf.java
+++ b/src/org/apache/xpath/functions/FuncIndexOf.java
@@ -22,12 +22,20 @@ import java.math.BigInteger;
 import javax.xml.transform.SourceLocator;
 
 import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
 import org.apache.xpath.Expression;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.LocPathIterator;
 import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XNodeSet;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.res.XPATHErrorResources;
+import org.apache.xpath.xs.types.XSAnyType;
 import org.apache.xpath.xs.types.XSInteger;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
 
 /**
  * Execute the index-of() function.
@@ -69,22 +77,87 @@ public class FuncIndexOf extends Function3Args {
         
         ResultSequence resultSeq = new ResultSequence();
         
+        ResultSequence arg0ResultSeq = null;
+        
+        final int contextNode = xctxt.getCurrentNode();
+        
         Expression arg0 = getArg0();
         Expression arg1 = getArg1();
         
-        XObject arg0Obj = arg0.execute(xctxt);
+        DTMManager dtmMgr = (DTMManager)xctxt;
+        
+        if (arg0 instanceof LocPathIterator) {
+            arg0ResultSeq = new ResultSequence();
+                                
+            DTMIterator arg0DtmIterator = m_arg0.asIterator(xctxt, contextNode);        
+            
+            int nextNodeDtmHandle;
+            
+            while ((nextNodeDtmHandle = arg0DtmIterator.nextNode()) != DTM.NULL) {
+                XNodeSet xNodeSet = new XNodeSet(nextNodeDtmHandle, xctxt.getDTMManager());
+                
+                String nodeStrValue = xNodeSet.str();
+                
+                DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
+                
+                if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
+                   XSUntyped xsUntyped = new XSUntyped(nodeStrValue);
+                   arg0ResultSeq.add(xsUntyped);
+                }
+                else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
+                   XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                   arg0ResultSeq.add(xsUntypedAtomic);
+                }
+                else {
+                   XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                   arg0ResultSeq.add(xsUntypedAtomic);
+                }                        
+            } 
+        }
+        else {
+            XObject arg0Obj = arg0.execute(xctxt);
+            if (arg0Obj instanceof ResultSequence) {
+               arg0ResultSeq = (ResultSequence)arg0Obj;     
+            }
+        }
 
-        if (!(arg0Obj instanceof ResultSequence)) {
-           throw new javax.xml.transform.TransformerException("The first argument of fn:index-of is "
-                                                                      + "not a sequence.", srcLocator);     
+        if (arg0ResultSeq == null) {
+           throw new javax.xml.transform.TransformerException("XPTY0004 : The first argument of fn:index-of didn't "
+                                                                                        + "evaluate to a sequence.", srcLocator);     
         }
         
         XObject arg1Obj = arg1.execute(xctxt);
         
-        ResultSequence arg0ResultSeq = (ResultSequence)arg0Obj;
+        if (arg1Obj instanceof XNodeSet) {
+           XNodeSet xNodeSet = (XNodeSet)arg1Obj;           
+           
+           if (xNodeSet.getLength() == 1) {
+              String nodeStrValue = xNodeSet.str();
+               
+              DTMIterator sourceNodes = arg0.asIterator(xctxt, contextNode);
+              int dtmNodeHandle = sourceNodes.nextNode();
+              
+              DTM dtm = dtmMgr.getDTM(dtmNodeHandle);
+               
+              if (dtm.getNodeType(dtmNodeHandle) == DTM.ELEMENT_NODE) {
+                 arg1Obj = new XSUntyped(nodeStrValue);
+              }
+              else if (dtm.getNodeType(dtmNodeHandle) == DTM.ATTRIBUTE_NODE) {
+                 arg1Obj = new XSUntypedAtomic(nodeStrValue);
+              }
+              else {
+                 arg1Obj = new XSUntypedAtomic(nodeStrValue);
+              }    
+           }
+           else {                            
+              throw new javax.xml.transform.TransformerException("XPTY0004 : the second argument of "
+                                                                                   + "fn:index-of needs to be a sequence of size one.", 
+                                                                                            srcLocator); 
+           }
+        }
         
         for (int idx = 0; idx < arg0ResultSeq.size(); idx++) {
-           if ((arg0ResultSeq.item(idx)).equals(arg1Obj)) {
+           if (equals(arg0ResultSeq.item(idx), arg1Obj)) {
               resultSeq.add(new XSInteger(BigInteger.valueOf(idx + 1)));    
            }
         }
@@ -116,5 +189,44 @@ public class FuncIndexOf extends Function3Args {
       throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
                                               XPATHErrorResources.ER_TWO_OR_THREE, null)); //"2 or 3"
   }
+  
+  /**
+   * Check equality of two xdm items.
+   */
+  private boolean equals(XObject obj1, XObject obj2) {
+      
+      boolean isEquals = false;
+      
+      if ((obj1 instanceof XSUntyped) && (obj2 instanceof XSUntyped)) {
+         if (((XSUntyped)obj1).equals((XSUntyped)obj2)) {
+            isEquals = true;   
+         }
+      }
+      else if ((obj1 instanceof XSUntypedAtomic) && (obj2 instanceof XSUntypedAtomic)) {
+         if (((XSUntypedAtomic)obj1).equals((XSUntypedAtomic)obj2)) {
+            isEquals = true;   
+         }
+      }
+      else if ((obj1 instanceof XSUntyped) && (obj2 instanceof XSUntypedAtomic)) {
+         if (((XSUntyped)obj1).equals((XSUntypedAtomic)obj2)) {
+            isEquals = true;   
+         } 
+      }
+      else if ((obj1 instanceof XSUntypedAtomic) && (obj2 instanceof XSUntyped)) {
+         if (((XSUntypedAtomic)obj1).equals((XSUntyped)obj2)) {
+            isEquals = true; 
+         }
+      }
+      else if ((obj1 instanceof XSAnyType) && (obj2 instanceof XSAnyType)) {
+         if (((XSAnyType)obj1).equals((XSAnyType)obj2)) {
+            isEquals = true;  
+         }   
+      }
+      else if (obj1.equals(obj2)) {
+          isEquals = true;   
+      }
+      
+      return isEquals; 
+  }
 
 }
diff --git a/src/org/apache/xpath/functions/FuncStringJoin.java b/src/org/apache/xpath/functions/FuncStringJoin.java
index e028c816..55e32c9f 100644
--- a/src/org/apache/xpath/functions/FuncStringJoin.java
+++ b/src/org/apache/xpath/functions/FuncStringJoin.java
@@ -23,12 +23,21 @@ package org.apache.xpath.functions;
 import javax.xml.transform.SourceLocator;
 
 import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.LocPathIterator;
 import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XNodeSet;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.objects.XString;
+import org.apache.xpath.operations.Range;
 import org.apache.xpath.operations.Variable;
 import org.apache.xpath.res.XPATHErrorResources;
+import org.apache.xpath.xs.types.XSAnyType;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
 
 /**
  * Execute the string-join() function.
@@ -61,19 +70,53 @@ public class FuncStringJoin extends Function2Args {
     
     ResultSequence arg0ResultSeq = null;
     
+    final int contextNode = xctxt.getCurrentNode();
+    
     if (m_arg0 instanceof Function) {
-        // evaluate an xslt/xpath function reference.
         XObject evalResult = ((Function)m_arg0).execute(xctxt);
         if (evalResult instanceof ResultSequence) {
-            arg0ResultSeq = (ResultSequence)evalResult;   
+           arg0ResultSeq = (ResultSequence)evalResult;   
         }                
-    }
-    
-    if (m_arg0 instanceof Variable) {
-        // evaluate an xslt variable reference.
+    }    
+    else if (m_arg0 instanceof Variable) {
         XObject evalResult = ((Variable)m_arg0).execute(xctxt);
         if (evalResult instanceof ResultSequence) {
-            arg0ResultSeq = (ResultSequence)evalResult;    
+           arg0ResultSeq = (ResultSequence)evalResult;    
+        }
+    }
+    else if (m_arg0 instanceof Range) {
+        XObject evalResult = ((Range)m_arg0).execute(xctxt);
+        if (evalResult instanceof ResultSequence) {
+           arg0ResultSeq = (ResultSequence)evalResult;    
+        }
+    }
+    else if (m_arg0 instanceof LocPathIterator) {
+        arg0ResultSeq = new ResultSequence();
+        
+        DTMManager dtmMgr = (DTMManager)xctxt;        
+        DTMIterator arg0DtmIterator = m_arg0.asIterator(xctxt, contextNode);        
+        
+        int nextNodeDtmHandle;
+        
+        while ((nextNodeDtmHandle = arg0DtmIterator.nextNode()) != DTM.NULL) {
+            XNodeSet xNodeSet = new XNodeSet(nextNodeDtmHandle, xctxt.getDTMManager());
+            
+            String nodeStrValue = xNodeSet.str();
+            
+            DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
+            
+            if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
+               XSUntyped xsUntyped = new XSUntyped(nodeStrValue);
+               arg0ResultSeq.add(xsUntyped);
+            }
+            else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
+               XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+               arg0ResultSeq.add(xsUntypedAtomic);
+            }
+            else {
+               XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+               arg0ResultSeq.add(xsUntypedAtomic);
+            }                        
         }
     }
     
@@ -83,13 +126,13 @@ public class FuncStringJoin extends Function2Args {
                                                                              srcLocator);    
     }
     
-    String separator = null;
+    String strJoinSeparator = null;
     
     if (m_arg1 == null) {
-       separator = "";   
+       strJoinSeparator = "";   
     }    
     else if (m_arg1 instanceof XString) {
-       separator = ((XString)m_arg1).str();
+       strJoinSeparator = ((XString)m_arg1).str();
     }
     else {
        throw new javax.xml.transform.TransformerException("The second argument of fn:string-join must "
@@ -97,18 +140,34 @@ public class FuncStringJoin extends Function2Args {
                                                                                      srcLocator);
     }
     
-    StringBuffer sb = new StringBuffer();
+    StringBuffer strBuffer = new StringBuffer();
     
     for (int idx = 0; idx < arg0ResultSeq.size(); idx++) {
+       String strValue = null;
+       
+       XObject xObject = arg0ResultSeq.item(idx);
+       if (xObject instanceof XSUntyped) {
+          strValue = ((XSUntyped)xObject).stringValue();     
+       }
+       else if (xObject instanceof XSUntypedAtomic) {
+          strValue = ((XSUntypedAtomic)xObject).stringValue();  
+       }
+       else if (xObject instanceof XSAnyType) {
+          strValue = ((XSAnyType)xObject).stringValue(); 
+       }
+       else {
+          strValue = xObject.str(); 
+       }
+       
        if (idx < (arg0ResultSeq.size() - 1)) {
-          sb.append(((arg0ResultSeq.item(idx)).str()) + separator);    
+          strBuffer.append(strValue + strJoinSeparator);    
        }
        else {
-          sb.append((arg0ResultSeq.item(idx)).str());    
+          strBuffer.append(strValue);    
        }
     }        
 
-    return new XString(sb.toString());
+    return new XString(strBuffer.toString());
   }
 
   /**
diff --git a/src/org/apache/xpath/functions/FuncTokenize.java b/src/org/apache/xpath/functions/FuncTokenize.java
index dfafb177..08040996 100644
--- a/src/org/apache/xpath/functions/FuncTokenize.java
+++ b/src/org/apache/xpath/functions/FuncTokenize.java
@@ -65,6 +65,9 @@ public class FuncTokenize extends Function3Args {
    */
   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
   {      
+        
+        ResultSequence resultSeq = new ResultSequence();
+      
         SourceLocator srcLocator = xctxt.getSAXLocator();
         
         XMLString inputStr = m_arg0.execute(xctxt).xstr();
@@ -93,7 +96,6 @@ public class FuncTokenize extends Function3Args {
                 throw new javax.xml.transform.TransformerException(ex.getMessage(), srcLocator); 
             }
             
-            ResultSequence resultSeq = new ResultSequence();
             for (int idx = 0; idx < tokenList.size(); idx++) {
                 resultSeq.add(new XString(tokenList.get(idx)));    
             }
@@ -132,8 +134,7 @@ public class FuncTokenize extends Function3Args {
         catch (Exception ex) {
            throw new javax.xml.transform.TransformerException(ex.getMessage(), srcLocator);   
         }
-    
-        ResultSequence resultSeq = new ResultSequence();
+            
         for (int idx = 0; idx < tokenList.size(); idx++) {
             resultSeq.add(new XString(tokenList.get(idx)));    
         }
diff --git a/src/org/apache/xpath/xs/types/XSUntyped.java b/src/org/apache/xpath/xs/types/XSUntyped.java
new file mode 100644
index 00000000..07d115a5
--- /dev/null
+++ b/src/org/apache/xpath/xs/types/XSUntyped.java
@@ -0,0 +1,78 @@
+/*
+ * 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.xs.types;
+
+import org.apache.xpath.objects.XObject;
+
+/**
+ * This class represents an XML Schema data type xs:untyped.
+ *  
+ * As per XPath 3.1 spec, xs:untyped is used as the type annotation of an 
+ * XML element node that has not been validated, or has been validated in 
+ * skip mode.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class XSUntyped extends XSAnyType {
+
+    private static final long serialVersionUID = 6146147730252441632L;
+    
+    private static final String XS_UNTYPED = "untyped";
+    
+    private String _value;
+    
+    public XSUntyped() {
+        this(null);
+    }
+    
+    public XSUntyped(String str) {
+        _value = str;
+    }
+
+    public String typeName() {
+        return "untypedAtomic";
+    }
+    
+    @Override
+    public String stringType() {
+        return XS_UNTYPED;
+    }
+
+    @Override
+    public String stringValue() {
+        return _value;
+    }
+    
+    public boolean equals(XObject xObject) {
+       boolean isEquals = false;
+        
+       if (xObject instanceof XSUntyped) {
+          isEquals = _value.equals(((XSUntyped)xObject).stringValue()); 
+       }
+       else if (xObject instanceof XSUntypedAtomic) {
+          isEquals = _value.equals(((XSUntypedAtomic)xObject).stringValue());  
+       }
+       else {
+          isEquals = _value.equals(xObject.str()); 
+       }
+        
+       return isEquals;
+    }
+
+}
diff --git a/src/org/apache/xpath/xs/types/XSUntypedAtomic.java b/src/org/apache/xpath/xs/types/XSUntypedAtomic.java
new file mode 100644
index 00000000..7ef347d1
--- /dev/null
+++ b/src/org/apache/xpath/xs/types/XSUntypedAtomic.java
@@ -0,0 +1,95 @@
+/*
+ * 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.xs.types;
+
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XObject;
+
+/**
+ * This class represents an XML Schema data type xs:untypedAtomic.
+ *  
+ * As per XPath 3.1 spec, xs:untypedAtomic is an XML Schema data type 
+ * that is used to denote untyped atomic data, such as text that has not 
+ * been assigned a more specific type.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class XSUntypedAtomic extends XSCtrType {
+
+    private static final long serialVersionUID = 3034074443706977457L;
+    
+    private static final String XS_UNTYPED_ATOMIC = "untypedAtomic";
+    
+    private String _value;
+    
+    public XSUntypedAtomic() {
+        this(null);
+    }
+    
+    public XSUntypedAtomic(String str) {
+        _value = str;
+    }
+
+    @Override
+    public ResultSequence constructor(ResultSequence arg) {
+        ResultSequence resultSeq = new ResultSequence();
+        
+        if (arg.size() == 0) {
+           return resultSeq;     
+        }
+        
+        XSAnyAtomicType xsAnyAtomicType = (XSAnyAtomicType)arg.item(0);
+        
+        resultSeq.add(new XSUntypedAtomic(xsAnyAtomicType.stringValue()));
+        
+        return resultSeq;
+    }
+
+    @Override
+    public String typeName() {
+        return "untypedAtomic";
+    }
+
+    @Override
+    public String stringType() {
+        return XS_UNTYPED_ATOMIC;
+    }
+
+    @Override
+    public String stringValue() {
+        return _value;
+    }
+    
+    public boolean equals(XObject xObject) {
+        boolean isEquals = false;
+        
+        if (xObject instanceof XSUntypedAtomic) {
+           isEquals = _value.equals(((XSUntypedAtomic)xObject).stringValue()); 
+        }
+        else if (xObject instanceof XSUntyped) {
+           isEquals = _value.equals(((XSUntyped)xObject).stringValue());  
+        }
+        else {
+           isEquals = _value.equals(xObject.str()); 
+        }
+        
+        return isEquals;
+    }
+
+}
diff --git a/tests/fn_distinct_values/gold/test1.out b/tests/fn_distinct_values/gold/test1.out
new file mode 100644
index 00000000..2af48a02
--- /dev/null
+++ b/tests/fn_distinct_values/gold/test1.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><result count="4">
+  <name>John</name>
+  <name>Gary</name>
+  <name>Mukul</name>
+  <name>Joseph</name>
+</result>
diff --git a/tests/fn_distinct_values/gold/test2.out b/tests/fn_distinct_values/gold/test2.out
new file mode 100644
index 00000000..24fec3ca
--- /dev/null
+++ b/tests/fn_distinct_values/gold/test2.out
@@ -0,0 +1 @@
+John,Gary,Mukul,Joseph
\ No newline at end of file
diff --git a/tests/fn_distinct_values/gold/test3.out b/tests/fn_distinct_values/gold/test3.out
new file mode 100644
index 00000000..1d68a6d4
--- /dev/null
+++ b/tests/fn_distinct_values/gold/test3.out
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><result count="3">
+  <val>1</val>
+  <val>2</val>
+  <val>3</val>
+</result>
diff --git a/tests/fn_distinct_values/gold/test4.out b/tests/fn_distinct_values/gold/test4.out
new file mode 100644
index 00000000..11d86647
--- /dev/null
+++ b/tests/fn_distinct_values/gold/test4.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><result count="4">
+  <val>John</val>
+  <val>Gary</val>
+  <val>Mukul</val>
+  <val>Joseph</val>
+</result>
diff --git a/tests/fn_distinct_values/gold/test5.out b/tests/fn_distinct_values/gold/test5.out
new file mode 100644
index 00000000..a5022c22
--- /dev/null
+++ b/tests/fn_distinct_values/gold/test5.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result count="5">
+  <val>Mark</val>
+  <val>John</val>
+  <val>Gary</val>
+  <val>Mukul</val>
+  <val>Joseph</val>
+</result>
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_distinct_values/test1.xsl
similarity index 72%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_distinct_values/test1.xsl
index 861eeaa5..ed8f3f6c 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_distinct_values/test1.xsl
@@ -3,16 +3,20 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function. -->                
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <xsl:variable name="distinctNames" select="distinct-values(name)"/>
+      <result count="{count($distinctNames)}">
+	     <xsl:for-each select="$distinctNames">
+	        <name><xsl:value-of select="."/></name>
+	     </xsl:for-each>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_distinct_values/test1_a.xml b/tests/fn_distinct_values/test1_a.xml
new file mode 100644
index 00000000..bfbeb583
--- /dev/null
+++ b/tests/fn_distinct_values/test1_a.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <name>John</name>
+   <name>Gary</name>
+   <name>Mukul</name>
+   <name>Mukul</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Mukul</name>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_distinct_values/test1_b.xml b/tests/fn_distinct_values/test1_b.xml
new file mode 100644
index 00000000..a1699617
--- /dev/null
+++ b/tests/fn_distinct_values/test1_b.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <name val="John"/>
+   <name val="Gary"/>
+   <name val="Mukul"/>
+   <name val="Mukul"/>
+   <name val="Joseph"/>
+   <name val="Joseph"/>
+   <name val="Joseph"/>
+   <name val="Mukul"/>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_distinct_values/test1_c.xml b/tests/fn_distinct_values/test1_c.xml
new file mode 100644
index 00000000..96342f4b
--- /dev/null
+++ b/tests/fn_distinct_values/test1_c.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <val>1</val>
+   <val>1</val>
+   <val>2</val>
+   <val>1</val>
+   <val>2</val>
+   <val>1</val>
+   <val>3</val>
+   <val>1</val>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_distinct_values/test1_d.xml b/tests/fn_distinct_values/test1_d.xml
new file mode 100644
index 00000000..b014358d
--- /dev/null
+++ b/tests/fn_distinct_values/test1_d.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list val="John">
+   <name>John</name>
+   <name>Gary</name>
+   <name>Mukul</name>
+   <name>Mukul</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Mukul</name>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_distinct_values/test1_e.xml b/tests/fn_distinct_values/test1_e.xml
new file mode 100644
index 00000000..9d14cfa0
--- /dev/null
+++ b/tests/fn_distinct_values/test1_e.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list val="Mark">
+   <name>John</name>
+   <name>Gary</name>
+   <name>Mukul</name>
+   <name>Mukul</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Mukul</name>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_distinct_values/test2.xsl
similarity index 70%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_distinct_values/test2.xsl
index 861eeaa5..d0ad8eff 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_distinct_values/test2.xsl
@@ -3,16 +3,15 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function. -->                  
 
-   <xsl:output method="xml" indent="yes"/>
+   <xsl:output method="text"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <xsl:value-of select="string-join(distinct-values(name),',')"/>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_distinct_values/test3.xsl
similarity index 72%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_distinct_values/test3.xsl
index 861eeaa5..b36a3bc4 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_distinct_values/test3.xsl
@@ -3,16 +3,20 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_b.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function. -->                
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <xsl:variable name="distinctNames" select="distinct-values(name/@val)"/>
+      <result count="{count($distinctNames)}">
+	     <xsl:for-each select="$distinctNames">
+	        <name><xsl:value-of select="."/></name>
+	     </xsl:for-each>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_distinct_values/test4.xsl
similarity index 70%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_distinct_values/test4.xsl
index 861eeaa5..3e37826b 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_distinct_values/test4.xsl
@@ -3,16 +3,15 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_b.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function. -->                  
 
-   <xsl:output method="xml" indent="yes"/>
+   <xsl:output method="text"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <xsl:value-of select="string-join(distinct-values(name/@val),',')"/>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_distinct_values/test5.xsl
similarity index 72%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_distinct_values/test5.xsl
index 861eeaa5..d926bce7 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_distinct_values/test5.xsl
@@ -3,16 +3,20 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_c.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function. -->                 
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <xsl:variable name="distinctVals" select="distinct-values(val)"/>
+      <result count="{count($distinctVals)}">
+   	     <xsl:for-each select="$distinctVals">
+   	        <val><xsl:value-of select="."/></val>
+   	     </xsl:for-each>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_indexof/test1.xsl b/tests/fn_distinct_values/test6.xsl
similarity index 65%
copy from tests/fn_indexof/test1.xsl
copy to tests/fn_distinct_values/test6.xsl
index 41cf5a2c..b7722080 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/fn_distinct_values/test6.xsl
@@ -4,15 +4,21 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- test for the XPath 3.1 fn:index-of() function -->
+   <!-- use with test1_c.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function.
+        Within this XSLT stylesheet, we use the result of
+        evaluation of an XPath 'for' expression as an input
+        to fn:distinct-values() function. -->                 
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-      <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
-      <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+   <xsl:template match="/list">
+      <xsl:variable name="distinctVals" select="distinct-values(for $val in val return number($val))"/>
+      <result count="{count($distinctVals)}">
+   	     <xsl:for-each select="$distinctVals">
+   	        <val><xsl:value-of select="."/></val>
+   	     </xsl:for-each>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_indexof/test1.xsl b/tests/fn_distinct_values/test7.xsl
similarity index 65%
copy from tests/fn_indexof/test1.xsl
copy to tests/fn_distinct_values/test7.xsl
index 41cf5a2c..1f8cd7a9 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/fn_distinct_values/test7.xsl
@@ -4,15 +4,22 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- test for the XPath 3.1 fn:index-of() function -->
+   <!-- use with test1_d.xml, test1_e.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:distinct-values() function.
+   
+        Within this XSLT stylesheet test, the fn:distinct-values() 
+        function takes as input, a combination of XML element and 
+        attribute nodes. -->                 
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-      <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
-      <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+   <xsl:template match="/list">
+      <xsl:variable name="distinctVals" select="distinct-values(name | /list/@val)"/>
+      <result count="{count($distinctVals)}">
+   	     <xsl:for-each select="$distinctVals">
+   	        <val><xsl:value-of select="."/></val>
+   	     </xsl:for-each>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_indexof/gold/test1.out b/tests/fn_indexof/gold/test1.out
index 6ad38795..7f76df0d 100644
--- a/tests/fn_indexof/gold/test1.out
+++ b/tests/fn_indexof/gold/test1.out
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?><result>
-  <one>2 3. size : 2</one>
-  <two>4 6 7. size : 3</two>
+  <one>2 3 :: size 2</one>
+  <two>4 6 7 :: size 3</two>
 </result>
diff --git a/tests/fn_indexof/gold/test2.out b/tests/fn_indexof/gold/test2.out
new file mode 100644
index 00000000..3cb06ba6
--- /dev/null
+++ b/tests/fn_indexof/gold/test2.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>3 4 8</result>
diff --git a/tests/fn_indexof/gold/test3.out b/tests/fn_indexof/gold/test3.out
new file mode 100644
index 00000000..f14a683c
--- /dev/null
+++ b/tests/fn_indexof/gold/test3.out
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><result srchVal="Mukul">
+  <pos>3</pos>
+  <pos>4</pos>
+  <pos>8</pos>
+</result>
diff --git a/tests/fn_indexof/test1.xsl b/tests/fn_indexof/test1.xsl
index 41cf5a2c..7672405f 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/fn_indexof/test1.xsl
@@ -11,8 +11,8 @@
    <xsl:template match="/">
       <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
       <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+         <one><xsl:value-of select="index-of($words, 'abc')"/> :: size <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
+         <two><xsl:value-of select="index-of($words, 'pqr')"/> :: size <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_indexof/test1_a.xml b/tests/fn_indexof/test1_a.xml
new file mode 100644
index 00000000..bfbeb583
--- /dev/null
+++ b/tests/fn_indexof/test1_a.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <name>John</name>
+   <name>Gary</name>
+   <name>Mukul</name>
+   <name>Mukul</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Joseph</name>
+   <name>Mukul</name>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_indexof/test1_b.xml b/tests/fn_indexof/test1_b.xml
new file mode 100644
index 00000000..a1699617
--- /dev/null
+++ b/tests/fn_indexof/test1_b.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <name val="John"/>
+   <name val="Gary"/>
+   <name val="Mukul"/>
+   <name val="Mukul"/>
+   <name val="Joseph"/>
+   <name val="Joseph"/>
+   <name val="Joseph"/>
+   <name val="Mukul"/>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_indexof/test2.xsl
similarity index 73%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_indexof/test2.xsl
index 861eeaa5..6c3fbb05 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_indexof/test2.xsl
@@ -3,16 +3,17 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- test for the XPath 3.1 fn:index-of() function -->                
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <result>
+        <xsl:value-of select="index-of(name, 'Mukul')"/>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_indexof/test3.xsl
similarity index 73%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_indexof/test3.xsl
index 861eeaa5..a2b1c8f6 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_indexof/test3.xsl
@@ -3,16 +3,17 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- test for the XPath 3.1 fn:index-of() function -->                
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <result>
+        <xsl:value-of select="index-of(name, name[3])"/>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_indexof/test4.xsl
similarity index 73%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_indexof/test4.xsl
index 861eeaa5..7895d812 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_indexof/test4.xsl
@@ -3,16 +3,18 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- test for the XPath 3.1 fn:index-of() function -->                
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <result>
+        <xsl:variable name="names" select="for $nm in name return string($nm)"/>
+        <xsl:value-of select="index-of($names, 'Mukul')"/>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_indexof/test1.xsl b/tests/fn_indexof/test5.xsl
similarity index 70%
copy from tests/fn_indexof/test1.xsl
copy to tests/fn_indexof/test5.xsl
index 41cf5a2c..d2391b5a 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/fn_indexof/test5.xsl
@@ -4,15 +4,20 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- test for the XPath 3.1 fn:index-of() function -->
+   <!-- use with test1_a.xml -->
+   
+   <!-- test for the XPath 3.1 fn:index-of() function -->                
 
    <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="srch" select="'Mukul'"/>
 
-   <xsl:template match="/">
-      <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
-      <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+   <xsl:template match="/list">
+      <result srchVal="{$srch}">
+         <xsl:variable name="names" select="for $nm in name return string($nm)"/>
+         <xsl:for-each select="index-of($names, $srch)">
+            <pos><xsl:value-of select="."/></pos>
+         </xsl:for-each>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_indexof/test1.xsl b/tests/fn_indexof/test6.xsl
similarity index 70%
copy from tests/fn_indexof/test1.xsl
copy to tests/fn_indexof/test6.xsl
index 41cf5a2c..9636d6eb 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/fn_indexof/test6.xsl
@@ -4,15 +4,20 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- test for the XPath 3.1 fn:index-of() function -->
+   <!-- use with test1_b.xml -->
+   
+   <!-- test for the XPath 3.1 fn:index-of() function -->                
 
    <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="srch" select="'Mukul'"/>
 
-   <xsl:template match="/">
-      <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
-      <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+   <xsl:template match="/list">
+      <result srchVal="{$srch}">
+         <xsl:variable name="names" select="for $nm in name return string($nm/@val)"/>
+         <xsl:for-each select="index-of($names, $srch)">
+            <pos><xsl:value-of select="."/></pos>
+         </xsl:for-each>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_indexof/gold/test1.out b/tests/fn_string_join/gold/test2.out
similarity index 50%
copy from tests/fn_indexof/gold/test1.out
copy to tests/fn_string_join/gold/test2.out
index 6ad38795..403e82c2 100644
--- a/tests/fn_indexof/gold/test1.out
+++ b/tests/fn_string_join/gold/test2.out
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?><result>
-  <one>2 3. size : 2</one>
-  <two>4 6 7. size : 3</two>
+  <val>123456789</val>
+  <val>1, 2, 3, 4, 5</val>
 </result>
diff --git a/tests/fn_string_join/gold/test3.out b/tests/fn_string_join/gold/test3.out
new file mode 100644
index 00000000..303cd0b5
--- /dev/null
+++ b/tests/fn_string_join/gold/test3.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>abcdefgh</one>
+  <two>a, b, c, d, e, f, g, h</two>
+</result>
diff --git a/tests/fn_string_join/gold/test4.out b/tests/fn_string_join/gold/test4.out
new file mode 100644
index 00000000..294a86f4
--- /dev/null
+++ b/tests/fn_string_join/gold/test4.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>abcdefghi</one>
+  <two>a, b, c, d, e, f, g, h, i</two>
+</result>
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_string_join/test1.xsl
index 861eeaa5..4b490f5d 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_string_join/test1.xsl
@@ -3,6 +3,8 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- Test for the XPath 3.1 fn:string-join() function -->
 
    <xsl:output method="xml" indent="yes"/>
 
diff --git a/tests/fn_string_join/test1_a.xml b/tests/fn_string_join/test1_a.xml
new file mode 100644
index 00000000..2113c87a
--- /dev/null
+++ b/tests/fn_string_join/test1_a.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <str>a</str>
+   <str>b</str>
+   <str>c</str>
+   <str>d</str>
+   <str>e</str>
+   <str>f</str>
+   <str>g</str>
+   <str>h</str>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_string_join/test1_b.xml b/tests/fn_string_join/test1_b.xml
new file mode 100644
index 00000000..acb48235
--- /dev/null
+++ b/tests/fn_string_join/test1_b.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <str val="a"/>
+   <str val="b"/>
+   <str val="c"/>
+   <str val="d"/>
+   <str val="e"/>
+   <str val="f"/>
+   <str val="g"/>
+   <str val="h"/>
+   <val>i</val>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_string_join/test2.xsl
similarity index 75%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_string_join/test2.xsl
index 861eeaa5..7a9fcce4 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_string_join/test2.xsl
@@ -3,16 +3,16 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- Test for the XPath 3.1 fn:string-join() function -->
 
    <xsl:output method="xml" indent="yes"/>
 
    <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+      <result>
+        <val><xsl:value-of select="string-join(1 to 9)"/></val>
+        <val><xsl:value-of select="string-join(1 to 5, ', ')"/></val>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_string_join/test3.xsl
similarity index 73%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_string_join/test3.xsl
index 861eeaa5..fa9f4fda 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_string_join/test3.xsl
@@ -3,16 +3,18 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:string-join() function -->
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <result>
+         <one><xsl:value-of select="string-join(str)"/></one>
+         <two><xsl:value-of select="string-join(str, ', ')"/></two>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_string_join/test1.xsl b/tests/fn_string_join/test4.xsl
similarity index 73%
copy from tests/fn_string_join/test1.xsl
copy to tests/fn_string_join/test4.xsl
index 861eeaa5..1f247358 100644
--- a/tests/fn_string_join/test1.xsl
+++ b/tests/fn_string_join/test4.xsl
@@ -3,16 +3,18 @@
                 version="3.0">
                 
    <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_b.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:string-join() function -->
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-     <result>        
-        <xsl:variable name="str" select="tokenize('Now is the time ...', '\s+')"/>        
-        <one><xsl:value-of select="string-join(tokenize('Now is the time ...', '\s+'), ',')"/></one>
-        <two><xsl:value-of select="string-join($str, ',')"/></two>
-        <three><xsl:value-of select="string-join($str)"/></three>
-     </result>
+   <xsl:template match="/list">
+      <result>
+         <one><xsl:value-of select="string-join(str/@val)"/></one>
+         <two><xsl:value-of select="string-join(str/@val, ', ')"/></two>
+      </result>
    </xsl:template>
    
    <!--
diff --git a/tests/fn_indexof/test1.xsl b/tests/fn_string_join/test5.xsl
similarity index 71%
copy from tests/fn_indexof/test1.xsl
copy to tests/fn_string_join/test5.xsl
index 41cf5a2c..c004f192 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/fn_string_join/test5.xsl
@@ -4,15 +4,20 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- test for the XPath 3.1 fn:index-of() function -->
+   <!-- use with test1_b.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:string-join() function.
+   
+        Within this XSLT stylesheet test, the fn:string-join() 
+        function takes as input, a combination of XML element and 
+        attribute nodes. -->
 
    <xsl:output method="xml" indent="yes"/>
 
-   <xsl:template match="/">
-      <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
+   <xsl:template match="/list">
       <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+         <one><xsl:value-of select="string-join(str/@val | val)"/></one>
+         <two><xsl:value-of select="string-join(str/@val | val, ', ')"/></two>
       </result>
    </xsl:template>
    
diff --git a/tests/inline_function_expr/gold/test5.out b/tests/inline_function_expr/gold/test5.out
new file mode 100644
index 00000000..040a9acd
--- /dev/null
+++ b/tests/inline_function_expr/gold/test5.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>5</result>
diff --git a/tests/fn_indexof/test1.xsl b/tests/inline_function_expr/test5.xsl
similarity index 70%
copy from tests/fn_indexof/test1.xsl
copy to tests/inline_function_expr/test5.xsl
index 41cf5a2c..aba4eda9 100644
--- a/tests/fn_indexof/test1.xsl
+++ b/tests/inline_function_expr/test5.xsl
@@ -4,15 +4,19 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- test for the XPath 3.1 fn:index-of() function -->
+   <!-- An XSLT stylesheet to test, an XPath 3.1 inline function
+        expression, which has no whitespace between its body delimiter
+        characters '{' or '}' and the XPath expression contents of inline
+        function body. i.e, inline function body sub-structures like 
+        '{$a', '$b}' and also '{ $a', '$b }' should be acceptable. -->                
 
    <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="func1" select="function ($a, $b) {$a + $b}"/>
 
    <xsl:template match="/">
-      <xsl:variable name="words" select="tokenize('a abc abc pqr mno pqr pqr','\s+')"/>
       <result>
-         <one><xsl:value-of select="index-of($words, 'abc')"/>. size : <xsl:value-of select="count(index-of($words, 'abc'))"/></one>
-         <two><xsl:value-of select="index-of($words, 'pqr')"/>. size : <xsl:value-of select="count(index-of($words, 'pqr'))"/></two>
+	     <xsl:value-of select="$func1(3, 2)"/>
       </result>
    </xsl:template>
    
diff --git a/tests/let_expr/test2.xsl b/tests/let_expr/test2.xsl
index 8bbc8edc..678b6af6 100644
--- a/tests/let_expr/test2.xsl
+++ b/tests/let_expr/test2.xsl
@@ -6,14 +6,14 @@
    
    <!-- An XSLT stylesheet test, for the XPath 3.1 "let" expression.
         
-        This XSLT stylesheet, borrows an XPath "let" expression example 
-        from https://www.altova.com/, with slight modifications.
-        
         Within this XSLT stylesheet, an XPath "let" expression binds two  
         literal values to the '$r' and '$pi' variables respectively. It also binds 
         a third variable '$area' to an inline function. The return expression calls 
         an inline function by using its variable reference '$area' and passing
-        the '$r' variable as an argument to it. -->
+        the '$r' variable as an argument to it.
+        
+        This XSLT stylesheet, borrows an XPath "let" expression example 
+        from https://www.altova.com/, with slight modifications. -->
         
    <xsl:output method="text"/>
                                             
diff --git a/tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java b/tests/org/apache/xalan/xpath3/FnDistinctValuesTests.java
similarity index 57%
copy from tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java
copy to tests/org/apache/xalan/xpath3/FnDistinctValuesTests.java
index 3fc0480c..1c57c6c2 100644
--- a/tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java
+++ b/tests/org/apache/xalan/xpath3/FnDistinctValuesTests.java
@@ -23,18 +23,17 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
- * XPath 3.1 "function item" inline function expression test 
- * cases.
+ * XPath 3.1 function fn:distinct-values test cases.
  * 
  * @author Mukul Gandhi <mu...@apache.org>
  * 
  * @xsl.usage advanced
  */
-public class InlineFunctionItemExprTests extends XslTransformTestsUtil {        
+public class FnDistinctValuesTests extends XslTransformTestsUtil {        
     
-    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "inline_function_expr/";
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "fn_distinct_values/";
     
-    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "inline_function_expr/gold/";
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "fn_distinct_values/gold/";
 
     @BeforeClass
     public static void setUpBeforeClass() throws Exception {
@@ -49,8 +48,8 @@ public class InlineFunctionItemExprTests extends XslTransformTestsUtil {
     }
 
     @Test
-    public void xslInlineFunctionExprTest1() {
-        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl"; 
+    public void xslFnDistinctValuesTest1() {
+        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";                
@@ -59,18 +58,18 @@ public class InlineFunctionItemExprTests extends XslTransformTestsUtil {
     }
     
     @Test
-    public void xslInlineFunctionExprTest2() {
-        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl"; 
+    public void xslFnDistinctValuesTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
         String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
         
-        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";                
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
     
     @Test
-    public void xslInlineFunctionExprTest3() {
-        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl"; 
+    public void xslFnDistinctValuesTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
         String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
         
         String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";                
@@ -79,13 +78,53 @@ public class InlineFunctionItemExprTests extends XslTransformTestsUtil {
     }
     
     @Test
-    public void xslInlineFunctionExprTest4() {
-        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+    public void xslFnDistinctValuesTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
         String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
         
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnDistinctValuesTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_c.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnDistinctValuesTest6() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_c.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test6.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnDistinctValuesTest7() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_d.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+        
         String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";                
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslFnDistinctValuesTest8() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_e.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
 
 }
diff --git a/tests/org/apache/xalan/xpath3/FnIndexOfTests.java b/tests/org/apache/xalan/xpath3/FnIndexOfTests.java
index 7ae76568..7700dbda 100644
--- a/tests/org/apache/xalan/xpath3/FnIndexOfTests.java
+++ b/tests/org/apache/xalan/xpath3/FnIndexOfTests.java
@@ -56,5 +56,55 @@ public class FnIndexOfTests extends XslTransformTestsUtil {
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslFnIndexOfTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnIndexOfTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnIndexOfTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnIndexOfTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnIndexOfTest6() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test6.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
 
 }
diff --git a/tests/org/apache/xalan/xpath3/FnStringJoinTests.java b/tests/org/apache/xalan/xpath3/FnStringJoinTests.java
index 119c89b1..1b1d9bf5 100644
--- a/tests/org/apache/xalan/xpath3/FnStringJoinTests.java
+++ b/tests/org/apache/xalan/xpath3/FnStringJoinTests.java
@@ -56,5 +56,45 @@ public class FnStringJoinTests extends XslTransformTestsUtil {
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslFnStringJoinTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnStringJoinTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnStringJoinTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnStringJoinTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
 
 }
diff --git a/tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java b/tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java
index 3fc0480c..e9b6eb3b 100644
--- a/tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java
+++ b/tests/org/apache/xalan/xpath3/InlineFunctionItemExprTests.java
@@ -87,5 +87,15 @@ public class InlineFunctionItemExprTests extends XslTransformTestsUtil {
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslInlineFunctionExprTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.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 b86c9063..b155fc67 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -18,6 +18,7 @@ package org.apache.xalan.xslt3;
 
 import org.apache.xalan.xpath3.DynamicFunctionCallTests;
 import org.apache.xalan.xpath3.FnAbsTests;
+import org.apache.xalan.xpath3.FnDistinctValuesTests;
 import org.apache.xalan.xpath3.FnFilterTests;
 import org.apache.xalan.xpath3.FnForEachTests;
 import org.apache.xalan.xpath3.FnIndexOfTests;
@@ -59,7 +60,7 @@ import org.junit.runners.Suite.SuiteClasses;
                 W3c_xslt30_IterateTests.class, W3c_xslt30_AxesTests.class, XslIterateTests.class,
                 ValueComparisonTests.class, InlineFunctionItemExprTests.class, FnForEachTests.class, 
                 FnFilterTests.class, DynamicFunctionCallTests.class, IfExprTests.class, 
-                ForExprTests.class, LetExprTests.class })
+                ForExprTests.class, LetExprTests.class, FnDistinctValuesTests.class })
 public class AllXsl3Tests {
 
 }


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