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/08/19 16:33:59 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 collation support, that has implementations of 'unicode codepoint collation' and 'unicode collation algorithm' as defined by xpath 3.1 f&o spec. also committing an implementation of xpath 3.1 fn:compare function that makes use of these implemented xpath collations. also committing few new working test cases, for these xpath implementation features. committing a minor enhancement to implementation of xsl:for-each-group instruction as well, along with a [...]

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 bd6c5ab1 committing implementation of xpath 3.1 collation support, that has implementations of 'unicode codepoint collation' and 'unicode collation algorithm' as defined by xpath 3.1 f&o spec. also committing an implementation of xpath 3.1 fn:compare function that makes use of these implemented xpath collations. also committing few new working test cases, for these xpath implementation features. committing a minor enhancement to implementation of xsl:for-each-group instruction as [...]
     new bdf0303e Merge pull request #54 from mukulga/xalan-j_xslt3.0_mukul
bd6c5ab1 is described below

commit bd6c5ab1fa9bdf0b958e74429e7d22404eccaf4e
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sat Aug 19 21:57:02 2023 +0530

    committing implementation of xpath 3.1 collation support, that has implementations of 'unicode codepoint collation' and 'unicode collation algorithm' as defined by xpath 3.1 f&o spec. also committing an implementation of xpath 3.1 fn:compare function that makes use of these implemented xpath collations. also committing few new working test cases, for these xpath implementation features. committing a minor enhancement to implementation of xsl:for-each-group instruction as well, along w [...]
---
 .../apache/xalan/templates/ElemForEachGroup.java   |  24 +-
 .../xalan/templates/XSConstructorFunctionUtil.java |  13 +-
 .../xslt/util/XslTransformEvaluationHelper.java    |   7 +-
 src/org/apache/xpath/XPathCollationSupport.java    | 462 +++++++++++++++++++++
 src/org/apache/xpath/XPathContext.java             |  18 +
 src/org/apache/xpath/compiler/FunctionTable.java   |   9 +-
 src/org/apache/xpath/compiler/Keywords.java        |   6 +
 src/org/apache/xpath/functions/FuncCompare.java    | 145 +++++++
 .../xpath/functions/FuncStringToCodepoints.java    |   5 +-
 src/org/apache/xpath/xs/types/XSString.java        | 104 +++++
 tests/fn_compare/gold/test1.out                    |   6 +
 tests/fn_compare/gold/test2.out                    |  10 +
 tests/fn_compare/gold/test3.out                    |   6 +
 tests/fn_compare/test1.xsl                         |  46 ++
 tests/fn_compare/test1_a.xml                       |  23 +
 tests/fn_compare/test2.xsl                         |  54 +++
 tests/fn_compare/test3.xsl                         |  44 ++
 tests/grouping/gold/test25.out                     |  32 ++
 tests/grouping/test1_g.xml                         |  50 +++
 tests/grouping/test25.xsl                          |  47 +++
 tests/org/apache/xalan/xpath3/FnCompareTests.java  |  80 ++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   3 +-
 tests/org/apache/xalan/xslt3/GroupingTests.java    |  10 +
 23 files changed, 1186 insertions(+), 18 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemForEachGroup.java b/src/org/apache/xalan/templates/ElemForEachGroup.java
index d47571e6..c41aaad1 100644
--- a/src/org/apache/xalan/templates/ElemForEachGroup.java
+++ b/src/org/apache/xalan/templates/ElemForEachGroup.java
@@ -33,6 +33,7 @@ import javax.xml.transform.TransformerException;
 
 import org.apache.xalan.transformer.ForEachGroupXslSortSorter;
 import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
 import org.apache.xml.utils.NodeVector;
@@ -41,6 +42,7 @@ import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.axes.NodeSequence;
+import org.apache.xpath.composite.ForExpr;
 import org.apache.xpath.composite.SimpleSequenceConstructor;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XBoolean;
@@ -409,8 +411,9 @@ public class ElemForEachGroup extends ElemTemplateElement
                sourceNodes = getSourceNodesFromResultSequence(resultSeq, xctxt);                
             }
         }
-        else if (m_selectExpression instanceof SimpleSequenceConstructor) {
-            XObject xObj = ((SimpleSequenceConstructor)m_selectExpression).execute(xctxt);
+        else if ((m_selectExpression instanceof SimpleSequenceConstructor) ||
+                                                    (m_selectExpression instanceof ForExpr)) {
+            XObject xObj = m_selectExpression.execute(xctxt);
             
             ResultSequence resultSeq = (ResultSequence)xObj;
             sourceNodes = getSourceNodesFromResultSequence(resultSeq, xctxt);
@@ -422,7 +425,7 @@ public class ElemForEachGroup extends ElemTemplateElement
                       
         // hashmap to store groups formed for, either 'group-by' or 'group-adjacent' attributes.
         // hashmap's key is the grouping key value, and value of that hashmap item entry is the
-        // contents of that group. 
+        // content of that group. 
         Map<Object, List<Integer>> xslForEachGroupMap = new HashMap<Object, List<Integer>>();
         
         // list to store groups formed for, either 'group-starting-with' or 'group-ending-with' 
@@ -811,7 +814,7 @@ public class ElemForEachGroup extends ElemTemplateElement
       }
       else {
           // any other data type for grouping key, is treated as string
-          xpathRawResult = xpathEvalResult.str();   
+          xpathRawResult = XslTransformEvaluationHelper.getStrVal(xpathEvalResult);  
       }
       
       return xpathRawResult;
@@ -856,17 +859,18 @@ public class ElemForEachGroup extends ElemTemplateElement
     
   }
   
+  /*
+   * Get XML document source nodes (represented as an 'DTMIterator' object), from
+   * a list of XNodeSet objects contained within a 'ResultSequence' object.    
+   */
   private DTMIterator getSourceNodesFromResultSequence(ResultSequence resultSeq, XPathContext xctxt) 
                                                                                           throws TransformerException {
      DTMIterator sourceNodes = null;
      
      NodeVector nodeVector = new NodeVector();
      
-     // we're assuming here that, all items within this 'resultSeq'
-     // object shall be XNodeSet objects.
-     
-     // how to do this 'resultSeq' object processing, when any of its
-     // items are other than XML nodes?
+     // how to process the sequence object 'resultSeq', when any of
+     // its items are other than XNodeSet object instances?
      // REVISIT
      for (int idx = 0; idx < resultSeq.size(); idx++) {
          XObject xObject = resultSeq.item(idx);
@@ -881,7 +885,7 @@ public class ElemForEachGroup extends ElemTemplateElement
         sourceNodes = nodeSequence.cloneWithReset();
      } catch (CloneNotSupportedException ex) {
         throw new TransformerException("An error occured during XSL grouping with xsl:for-each-group "
-                                                                                            + "element.", xctxt.getSAXLocator());
+                                                                                            + "instruction.", xctxt.getSAXLocator());
      }
      
      return sourceNodes; 
diff --git a/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java b/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java
index 371afabf..2e44d4d9 100644
--- a/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java
+++ b/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java
@@ -38,6 +38,7 @@ import org.apache.xpath.xs.types.XSFloat;
 import org.apache.xpath.xs.types.XSInt;
 import org.apache.xpath.xs.types.XSInteger;
 import org.apache.xpath.xs.types.XSLong;
+import org.apache.xpath.xs.types.XSString;
 import org.apache.xpath.xs.types.XSYearMonthDuration;
 import org.xml.sax.SAXException;
 
@@ -71,7 +72,17 @@ public class XSConstructorFunctionUtil {
                 // evaluate XPath 3.1 constructor function calls, corresponding to XML Schema 
                 // built-in types.
                 
-                if ((Keywords.XS_DECIMAL).equals(funcExtFunction.getFunctionName())) {                              
+                if ((Keywords.XS_STRING).equals(funcExtFunction.getFunctionName())) {                              
+                    ResultSequence argSequence = new ResultSequence();
+                    for (int idx = 0; idx < funcExtFunction.getArgCount(); idx++) {
+                        XObject argVal = (funcExtFunction.getArg(idx)).execute(xctxt);
+                        argSequence.add(new XSString(XslTransformEvaluationHelper.getStrVal(argVal)));
+                    }
+
+                    ResultSequence rSeq = (new XSString()).constructor(argSequence);
+                    evalResult = rSeq.item(0);              
+                }
+                else if ((Keywords.XS_DECIMAL).equals(funcExtFunction.getFunctionName())) {                              
                     ResultSequence argSequence = new ResultSequence();
                     for (int idx = 0; idx < funcExtFunction.getArgCount(); idx++) {
                         XObject argVal = (funcExtFunction.getArg(idx)).execute(xctxt);
diff --git a/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java b/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
index 1c7fdc32..360896e5 100644
--- a/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
+++ b/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
@@ -16,16 +16,15 @@
  */
 package org.apache.xalan.xslt.util;
 
+import java.util.List;
+
+import org.apache.xalan.templates.XMLNSDecl;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.xs.types.XSAnyType;
 import org.apache.xpath.xs.types.XSUntyped;
 import org.apache.xpath.xs.types.XSUntypedAtomic;
 
-import java.util.List;
-
-import org.apache.xalan.templates.XMLNSDecl;
-
 /**
  * This class, has few utility methods, to help with certain 
  * XalanJ XSLT transformation implementation tasks.
diff --git a/src/org/apache/xpath/XPathCollationSupport.java b/src/org/apache/xpath/XPathCollationSupport.java
new file mode 100644
index 00000000..a903a87e
--- /dev/null
+++ b/src/org/apache/xpath/XPathCollationSupport.java
@@ -0,0 +1,462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xpath;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.transform.TransformerException;
+
+/**
+ * This class provides, collation support to XalanJ's XPath 3.1 
+ * implementation.
+ * 
+ * Ref : https://www.w3.org/TR/xpath-functions-31/#collations
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class XPathCollationSupport {
+    
+    public static final String UNICODE_CODEPOINT_COLLATION_URI = "http://www.w3.org/2005/xpath-functions/collation/codepoint";
+    
+    public static final String UNICODE_COLLATION_ALGORITHM_URI = "http://www.w3.org/2013/collation/UCA";
+    
+    public static final String HTML_ASCII_CASE_INSENSITIVE_COLLATION_URI = "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive";
+    
+    private final String UCA_KEYWORD_FALLBACK = "fallback";
+    
+    private final String UCA_FALLBACK_YES = "yes";    
+    private final String UCA_FALLBACK_NO = "no";
+    
+    private final String UCA_KEYWORD_LANG = "lang";
+    
+    private final String UCA_KEYWORD_STRENGTH = "strength";
+    
+    private final String UCA_STRENGTH_PRIMARY = "primary";
+    private final String UCA_STRENGTH_SECONDARY = "secondary";
+    private final String UCA_STRENGTH_TERTIARY = "tertiary";
+    private final String UCA_STRENGTH_IDENTICAL = "identical";
+    
+    private final String DEFAULT_UCA_FALLBACK_VALUE = UCA_FALLBACK_YES;
+    
+    private final Locale DEFAULT_UCA_LOCALE = Locale.getDefault();     
+    
+    private final String DEFAULT_UCA_STRENGTH_VALUE = UCA_STRENGTH_TERTIARY;
+    
+    private final String UCA_QUERY_STRING_PREFIX = "?";
+    
+    private final String UCA_QUERY_STRING_PARTS_DELIM = ";";
+    
+    private final String UCA_QUERY_STRING_PART_SUB_DELIM = "=";
+    
+    private List<UCAParameter> fUcaSupportedParameters = new ArrayList<UCAParameter>();
+    
+    // This class field, is needed by unicode collation algorithm
+    private String fQueryStrFallbackValue = null;
+    
+    private String fDefaultCollationUri = null;
+    
+    /**
+     * Class constructor.
+     */
+    public XPathCollationSupport(String defaultCollationUri) {
+       fDefaultCollationUri = defaultCollationUri; 
+       buildSupportedUCAParamList();  
+    }
+    
+    /**
+     * This method, compares two string values, using a specified collation.
+     * 
+     * @param str1               the first string
+     * @param str2               the second string
+     * @param collationUri       collation uri
+     * 
+     * @return                   the string comparison result represented as an integer value. The value -1
+     *                           indicates that string 'str1' collates before string 'str2', the value 1
+     *                           indicates that string 'str1' collates after string 'str2', the value 0
+     *                           indicates that string 'str1' is equal to string 'str2'. 
+     *                             
+     * @throws javax.xml.transform.TransformerException
+     */
+    public int compareStringsUsingCollationUri(String str1, String str2, String collationUri) 
+                                                                                       throws javax.xml.transform.TransformerException {
+       int comparisonResult = 0;
+       
+       if (UNICODE_CODEPOINT_COLLATION_URI.equals(collationUri)) {
+          comparisonResult = compareStringsUsingUnicodeCodepointCollation(str1, str2);
+       }
+       else if (collationUri.startsWith(UNICODE_COLLATION_ALGORITHM_URI)) {
+          try {
+             Collator collator = getCollatorFromCollationUri(collationUri);
+             
+             if (collator != null) {
+                comparisonResult = collator.compare(str1, str2);                
+             }
+             else if (UCA_FALLBACK_YES.equals(fQueryStrFallbackValue)) {                    
+                comparisonResult = compareStringsUsingCollationUri(str1, str2, fDefaultCollationUri);
+             }
+             else {
+                throw new javax.xml.transform.TransformerException("FOCH0002 : The requested collation '" + collationUri + "' is not supported.");  
+             }
+          }
+          catch (javax.xml.transform.TransformerException ex) {
+             throw new javax.xml.transform.TransformerException(ex.getMessage());    
+          }
+            
+          if (comparisonResult < 0) {
+             comparisonResult = -1;  
+          }
+          else if (comparisonResult > 0) {
+             comparisonResult = 1; 
+          }    
+       }
+       else if (HTML_ASCII_CASE_INSENSITIVE_COLLATION_URI.equals(collationUri)) {
+          // REVISIT
+          throw new javax.xml.transform.TransformerException("FOCH0002 : The requested collation '" + collationUri + "' "
+                                                                                                           + "is not supported.");          
+       }
+       else {
+          throw new javax.xml.transform.TransformerException("FOCH0002 : The requested collation '" + collationUri + "' "
+                                                                                                           + "is not supported."); 
+       }
+       
+       return comparisonResult;
+    }
+    
+    /**
+     * Given a string, get a corresponding primitive integer array of
+     * the codepoints of all the characters of the string in order.
+     */
+    public int[] getCodepointsFromString(String str) {
+        int[] codePointsArr = null;
+        
+        codePointsArr = (str.codePoints()).toArray();
+        
+        return codePointsArr;
+    }
+    
+    /**
+     * This method compares, two string values using 'unicode codepoint collation'.
+     *
+     * @param str1    the first string
+     * @param str2    the second string
+     * 
+     * @return        an integer value denoting, the result of comparison
+     */
+    private int compareStringsUsingUnicodeCodepointCollation(String str1, String str2) {
+       int comparisonResult = 0;
+       
+       int[] codePointsArr1 = getCodepointsFromString(str1);       
+       int[] codePointsArr2 = getCodepointsFromString(str2);
+       
+       comparisonResult = compareCodepointArrays(codePointsArr1, codePointsArr2); 
+       
+       return comparisonResult; 
+    }
+    
+    /**
+     * Compare two int[] arrays comprising unicode codepoints, according to
+     * 'unicode codepoint collation'.
+     */
+    private int compareCodepointArrays(int[] codePointsArr1, int[] codePointsArr2) {
+       
+       int comparisonResult = 0;
+       
+       if (((codePointsArr1 == null) || (codePointsArr1.length == 0)) && 
+           ((codePointsArr2 == null) || (codePointsArr2.length == 0))) {
+          // both strings are considered equal
+          comparisonResult = 0; 
+       }
+       else if (((codePointsArr1 == null) || (codePointsArr1.length == 0)) &&
+                ((codePointsArr2 != null) && (codePointsArr2.length > 0))) {
+          // the first string is less than the second one
+          comparisonResult = -1; 
+       }
+       else if (((codePointsArr1 != null) && (codePointsArr1.length > 0)) &&
+                ((codePointsArr2 == null) || (codePointsArr2.length == 0))) {
+          // the second string is less than the first one
+          comparisonResult = 1; 
+       }
+       else {
+          // both the strings to be compared, have non empty code point arrays
+          int arr1FirstCodepoint = codePointsArr1[0];
+          int arr2FirstCodepoint = codePointsArr2[0];
+          if (arr1FirstCodepoint > arr2FirstCodepoint) {
+             comparisonResult = 1;  
+          }
+          else if (arr2FirstCodepoint > arr1FirstCodepoint) {
+             comparisonResult = -1; 
+          }
+          else {             
+             List<Integer> list1 = getIntegerListFromIntArray(codePointsArr1);
+             List<Integer> list2 = getIntegerListFromIntArray(codePointsArr2);
+                 
+             // get all, but the first item in the list 'list1'
+             list1 = list1.subList(1, list1.size());
+             
+             // get all, but the first item in the list 'list2'
+             list2 = list2.subList(1, list2.size());
+             
+             // recursive call to this function
+             comparisonResult = compareCodepointArrays(getIntArrayFromIntegerList(list1), 
+                                                                       getIntArrayFromIntegerList(list2));     
+          }
+       }
+       
+       return comparisonResult;
+    }
+    
+    /**
+     * Given an array of primitive integers, get the corresponding
+     * list of type List<Integer>.
+     */
+    private List<Integer> getIntegerListFromIntArray(int[] intArr) {
+       List<Integer> integerList = new ArrayList<Integer>();
+       
+       for (int idx = 0; idx < intArr.length; idx++) {
+          integerList.add(Integer.valueOf(intArr[idx])); 
+       }
+       
+       return integerList;
+    }
+    
+    /**
+     * Given a list of type List<Integer>, get the corresponding array
+     * of primitive integers.  
+     */
+    private int[] getIntArrayFromIntegerList(List<Integer> integerList) {
+       int[] intArray = new int[integerList.size()];
+       
+       for (int idx = 0; idx < integerList.size(); idx++) {
+          intArray[idx] = (integerList.get(idx)).intValue();  
+       }
+       
+       return intArray;
+    }
+    
+    /**
+     * This method helps to implement, unicode collation algorithm as specified by XPath 3.1 F&O
+     * spec, which in turn is based on UTS #10 (Unicode Technical Standard #10 : Unicode Collation
+     * Algorithm).
+     * 
+     * @param collationUri     the collation uri, specified by users of XPath 3.1 string comparison
+     *                         , or sorting of strings.
+     *                         
+     * @return                 a configured Java object of type java.text.Collator, that callers of
+     *                         this method can use to do locale specific string comparisons.
+     * 
+     * @throws TransformerException
+     */
+    private Collator getCollatorFromCollationUri(String collationUri) throws TransformerException {
+       
+       Collator strComparisonCollator = null;
+       
+       try {
+           if (collationUri.equals(UNICODE_COLLATION_ALGORITHM_URI)) {
+              strComparisonCollator = Collator.getInstance(DEFAULT_UCA_LOCALE);
+              strComparisonCollator.setStrength(Collator.TERTIARY);
+           }
+           else {
+              int ucaUriPrefixLength = UNICODE_COLLATION_ALGORITHM_URI.length();              
+              String uriAndQueryStrDelim = collationUri.substring(ucaUriPrefixLength, ucaUriPrefixLength + 1);
+              
+              if (UCA_QUERY_STRING_PREFIX.equals(uriAndQueryStrDelim)) {
+                 String uriQueryStr = collationUri.substring(collationUri.indexOf(UCA_QUERY_STRING_PREFIX) + 1);
+                 Map<String, String> queryStrMap = getUCAQueryStrComponents(uriQueryStr);
+                 
+                 String queryStrFallbackValue = queryStrMap.get(UCA_KEYWORD_FALLBACK);
+                 String queryStrLangCode = queryStrMap.get(UCA_KEYWORD_LANG);
+                 String queryStrStrengthValue = queryStrMap.get(UCA_KEYWORD_STRENGTH);
+                    
+                 if (queryStrFallbackValue == null) {
+                    fQueryStrFallbackValue = DEFAULT_UCA_FALLBACK_VALUE;  
+                 }
+                 else {
+                    fQueryStrFallbackValue = queryStrFallbackValue;  
+                 }
+                    
+                 if (queryStrLangCode == null) {
+                    queryStrLangCode = DEFAULT_UCA_LOCALE.getCountry(); 
+                 }
+                    
+                 if (queryStrStrengthValue == null) {
+                    queryStrStrengthValue = DEFAULT_UCA_STRENGTH_VALUE;  
+                 }
+                    
+                 strComparisonCollator = Collator.getInstance(new Locale(queryStrLangCode));
+                    
+                 switch (queryStrStrengthValue) {
+                    case UCA_STRENGTH_PRIMARY :
+                       strComparisonCollator.setStrength(Collator.PRIMARY);
+                       break;
+                    case UCA_STRENGTH_SECONDARY :
+                       strComparisonCollator.setStrength(Collator.SECONDARY);
+                       break;
+                    case UCA_STRENGTH_TERTIARY :
+                       strComparisonCollator.setStrength(Collator.TERTIARY);
+                       break;
+                    case UCA_STRENGTH_IDENTICAL :
+                       strComparisonCollator.setStrength(Collator.IDENTICAL);
+                       break;
+                    default:
+                       // no op    
+                 }
+              }
+              else {
+                 throw new TransformerException("FOCH0002 : The first character if present after collation uri '" + 
+                                                                        UNICODE_COLLATION_ALGORITHM_URI + "' must be "
+                                                                        + "'" + UCA_QUERY_STRING_PREFIX + "', to denote the "
+                                                                        + "start of query string within the collation uri.");   
+              }
+           }
+       }
+       catch (Exception ex) {
+           throw new TransformerException(ex.getMessage());  
+       }
+       
+       return strComparisonCollator;
+    }
+    
+    /**
+     * From the requested collation uri, build a corresponding java.util.Map object
+     * representation.  
+     */
+    private Map<String, String> getUCAQueryStrComponents(String uriQueryStr) throws TransformerException {
+       Map<String, String> queryStrMap = new HashMap<String, String>();
+       
+       String[] queryStrParts = uriQueryStr.split(UCA_QUERY_STRING_PARTS_DELIM);
+       
+       for (int idx = 0; idx < queryStrParts.length; idx++) {
+          String queryStrPart = queryStrParts[idx];
+          int delimIdx = queryStrPart.indexOf(UCA_QUERY_STRING_PART_SUB_DELIM);
+          String keyword = queryStrPart.substring(0, delimIdx);
+          String value = queryStrPart.substring(delimIdx + 1);
+          if (!queryStrMap.containsKey(keyword)) {
+             if (isUCAKeywordAndValueOk(keyword, value)) {
+                queryStrMap.put(keyword, value);
+             }
+             else {
+                throw new TransformerException("FOCH0002 : The keyword '"+keyword+"' and corresponding value '" + 
+                                                                                      value + "', provided within the "
+                                                                                      + "requested collation uri is not supported.");  
+             }
+          }
+          else {
+             throw new TransformerException("FOCH0002 : The keyword '" + keyword + "' occurs more than once, within "
+                                                                                        + "the specified collation uri."); 
+          }
+       }
+       
+       return queryStrMap;
+    }
+    
+    /**
+     * Check whether, within requested collation uri's query string, the given
+     * keyword and value is supported by XalanJ's XPath 3.1 processor.
+     */
+    private boolean isUCAKeywordAndValueOk(String keyword, String value) {
+       boolean isUCAKeywordAndValueOk = false;
+       
+       for (int idx = 0; idx < fUcaSupportedParameters.size(); idx++) {
+          UCAParameter ucaParameter = fUcaSupportedParameters.get(idx);
+          if ((ucaParameter.getKeywordName()).equals(keyword)) {
+             List<String> paramValues = ucaParameter.getParamValues();
+             if (paramValues.contains(value)) {
+                isUCAKeywordAndValueOk = true;
+                break;
+             }
+          }
+       }
+        
+       return isUCAKeywordAndValueOk; 
+    }
+    
+    /**
+     * This method configures, the collation support provided by
+     * XalanJ XPath 3.1 implementation.
+     */
+    private void buildSupportedUCAParamList() {        
+        List<String> fallbackList = new ArrayList<String>();
+        fallbackList.add(UCA_FALLBACK_YES);
+        fallbackList.add(UCA_FALLBACK_NO);
+        UCAParameter ucaFallbackParam = new UCAParameter(UCA_KEYWORD_FALLBACK, fallbackList);
+        
+        String[] isoLanguageCodes = Locale.getISOLanguages();
+        List<String> isoLanguageList = Arrays.asList(isoLanguageCodes);
+        UCAParameter ucaLanguageParam = new UCAParameter(UCA_KEYWORD_LANG, isoLanguageList);
+        
+        List<String> collationStrengthList = new ArrayList<String>();
+        collationStrengthList.add(UCA_STRENGTH_PRIMARY);
+        collationStrengthList.add(UCA_STRENGTH_SECONDARY);
+        collationStrengthList.add(UCA_STRENGTH_TERTIARY);
+        collationStrengthList.add(UCA_STRENGTH_IDENTICAL);
+        UCAParameter ucaCollationStrengthParam = new UCAParameter(UCA_KEYWORD_STRENGTH, collationStrengthList);
+        
+        fUcaSupportedParameters.add(ucaFallbackParam);
+        fUcaSupportedParameters.add(ucaLanguageParam);
+        fUcaSupportedParameters.add(ucaCollationStrengthParam);
+    }
+    
+    /**
+     * An object of this class, stores definition of one
+     * "Unicode Collation Algorithm" (UCA) uri query
+     * parameter.
+     */
+    private class UCAParameter {        
+        
+        // Variable denoting, keyword/parameter name
+        // (for e.g, 'fallback', 'lang', 'strength').
+        private String keywordName;
+        
+        // Variable denoting, permitted values for the keyword/parameter
+        // name.
+        // For e.g, the 'fallback' parameter has possible values 'yes'/'no'.
+        // The 'strength' parameter has possible values 'primary',
+        // 'secondary', 'tertiary', 'identical'.
+        private List<String> paramValues;
+        
+        public UCAParameter(String keywordName, List<String> paramValues) {
+           this.keywordName = keywordName;
+           this.paramValues = paramValues;
+        }
+
+        public String getKeywordName() {
+            return keywordName;
+        }
+
+        public void setKeywordName(String keywordName) {
+            this.keywordName = keywordName;
+        }
+
+        public List<String> getParamValues() {
+            return paramValues;
+        }
+
+        public void setParamValues(List<String> paramValues) {
+            this.paramValues = paramValues;
+        }
+        
+    }
+
+}
diff --git a/src/org/apache/xpath/XPathContext.java b/src/org/apache/xpath/XPathContext.java
index 71ac656d..6ed89a59 100644
--- a/src/org/apache/xpath/XPathContext.java
+++ b/src/org/apache/xpath/XPathContext.java
@@ -138,6 +138,16 @@ public class XPathContext extends DTMManager // implements ExpressionContext
    * We don't use, XalanJ XPath context's variable stack for this purpose.
    */
   private Map<QName, XObject> xpathVarMap = new HashMap<QName, XObject>();
+  
+  /**
+   * The default collation uri.
+   */
+  private String m_default_collation = XPathCollationSupport.UNICODE_CODEPOINT_COLLATION_URI;
+  
+  /**
+   * An XPathCollationSupport object instance to support, collations within XPath implementation.
+   */
+  private XPathCollationSupport m_collationSupport = new XPathCollationSupport(m_default_collation);
 	
   /**
    * Though XPathContext context extends 
@@ -1469,5 +1479,13 @@ public class XPathContext extends DTMManager // implements ExpressionContext
  public void setXPathVarMap(Map<QName, XObject> xpathVarMap) {
      this.xpathVarMap = xpathVarMap;
  }
+
+ public XPathCollationSupport getXPathCollationSupport() {
+     return m_collationSupport;
+ }
+ 
+ public String getDefaultCollation() {
+     return m_default_collation;
+ }
   
 }
diff --git a/src/org/apache/xpath/compiler/FunctionTable.java b/src/org/apache/xpath/compiler/FunctionTable.java
index cf3a2567..e3170717 100644
--- a/src/org/apache/xpath/compiler/FunctionTable.java
+++ b/src/org/apache/xpath/compiler/FunctionTable.java
@@ -269,6 +269,9 @@ public class FunctionTable
   
   /** The 'string-to-codepoints()' id. */
   public static final int FUNC_STRING_TO_CODE_POINTS = 81;
+  
+  /** The 'compare()' id. */
+  public static final int FUNC_COMPARE = 82;
 
   // Proprietary
 
@@ -326,7 +329,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 = 82;
+  private static final int NUM_BUILT_IN_FUNCS = 83;
 
   /**
    * Number of built-in functions that may be added.
@@ -490,6 +493,8 @@ public class FunctionTable
       org.apache.xpath.functions.FuncCodePointsToString.class;
     m_functions[FUNC_STRING_TO_CODE_POINTS] = 
       org.apache.xpath.functions.FuncStringToCodepoints.class;
+    m_functions[FUNC_COMPARE] = 
+      org.apache.xpath.functions.FuncCompare.class;
   }
 
   static{
@@ -661,6 +666,8 @@ public class FunctionTable
                          new Integer(FunctionTable.FUNC_CODE_POINTS_TO_STRING));
          m_functionID.put(Keywords.FUNC_STRING_TO_CODE_POINTS,
                          new Integer(FunctionTable.FUNC_STRING_TO_CODE_POINTS));
+         m_functionID.put(Keywords.FUNC_COMPARE,
+                         new Integer(FunctionTable.FUNC_COMPARE));
   }
   
   public FunctionTable(){
diff --git a/src/org/apache/xpath/compiler/Keywords.java b/src/org/apache/xpath/compiler/Keywords.java
index 483d3476..bc6d2764 100644
--- a/src/org/apache/xpath/compiler/Keywords.java
+++ b/src/org/apache/xpath/compiler/Keywords.java
@@ -347,8 +347,14 @@ public class Keywords
   /** string-to-codepoints function string. */
   public static final String FUNC_STRING_TO_CODE_POINTS = "string-to-codepoints";
   
+  /** compare function string. */
+  public static final String FUNC_COMPARE = "compare";
+  
   // XML Schema built-in data type name keywords
   
+  /** xs:string data type string. */
+  public static final String XS_STRING = "string";
+  
   /** xs:decimal data type string. */
   public static final String XS_DECIMAL = "decimal";
   
diff --git a/src/org/apache/xpath/functions/FuncCompare.java b/src/org/apache/xpath/functions/FuncCompare.java
new file mode 100644
index 00000000..5c477d6c
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncCompare.java
@@ -0,0 +1,145 @@
+/*
+ * 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 java.math.BigInteger;
+
+import javax.xml.transform.SourceLocator;
+
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathCollationSupport;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.res.XPATHErrorResources;
+import org.apache.xpath.xs.types.XSInteger;
+
+/**
+ * Implementation of the compare() function.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FuncCompare extends FunctionMultiArgs {
+    
+    private static final long serialVersionUID = 4648998919300586767L;
+    
+    /**
+     * The number of arguments passed to the fn:compare function 
+     * call.
+     */
+    private int numOfArgs = 0;
+    
+    /**
+     * 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
+    {
+        
+        XSInteger result = null;
+        
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        Expression arg0 = m_arg0;        
+        Expression arg1 = m_arg1;        
+        Expression arg2 = null;
+        
+        XPathCollationSupport xPathCollationSupport = xctxt.getXPathCollationSupport();
+        
+        try {
+            if (numOfArgs == 2) {
+               XObject xObject0 = arg0.execute(xctxt);               
+               XObject xObject1 = arg1.execute(xctxt);
+               
+               String str0 = XslTransformEvaluationHelper.getStrVal(xObject0);
+               String str1 = XslTransformEvaluationHelper.getStrVal(xObject1);
+               
+               // set the collation to default collation
+               String collationUri = xctxt.getDefaultCollation();
+               
+               int comparisonResult = xPathCollationSupport.compareStringsUsingCollationUri(
+                                                                                       str0, str1, collationUri);
+               
+               result = new XSInteger(BigInteger.valueOf((long)comparisonResult));
+            }
+            else {
+                // a collation uri was, explicitly provided during the function call fn:compare
+                
+                arg2 = m_arg2;
+                
+                XObject xObject0 = arg0.execute(xctxt);
+                XObject xObject1 = arg1.execute(xctxt);
+                
+                XObject xObject2 = arg2.execute(xctxt);
+                
+                String str0 = XslTransformEvaluationHelper.getStrVal(xObject0);
+                String str1 = XslTransformEvaluationHelper.getStrVal(xObject1);
+                
+                String collationUri = XslTransformEvaluationHelper.getStrVal(xObject2);
+                
+                int comparisonResult = xPathCollationSupport.compareStringsUsingCollationUri(
+                                                                                        str0, str1, collationUri);
+                
+                result = new XSInteger(BigInteger.valueOf((long)comparisonResult)); 
+            }
+        }
+        catch (javax.xml.transform.TransformerException ex) {
+           throw new javax.xml.transform.TransformerException(ex.getMessage(), srcLocator);  
+        }
+        
+        return result;
+    }
+    
+    /**
+     * 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 <= 3)) {
+          reportWrongNumberArgs();
+       }
+       else {
+          numOfArgs = argNum;   
+       }
+    }
+    
+    /**
+     * 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_TWO_OR_THREE, 
+                                                                     null));
+    }
+
+}
diff --git a/src/org/apache/xpath/functions/FuncStringToCodepoints.java b/src/org/apache/xpath/functions/FuncStringToCodepoints.java
index b132c90b..a0de7117 100644
--- a/src/org/apache/xpath/functions/FuncStringToCodepoints.java
+++ b/src/org/apache/xpath/functions/FuncStringToCodepoints.java
@@ -22,6 +22,7 @@ package org.apache.xpath.functions;
 
 import java.math.BigInteger;
 
+import org.apache.xpath.XPathCollationSupport;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XObject;
@@ -55,7 +56,9 @@ public class FuncStringToCodepoints extends FunctionDef1Arg
      
      String inpStr = (getArg0AsString(xctxt)).toString();
      
-     int[] codePointsArr = (inpStr.codePoints()).toArray();
+     XPathCollationSupport xPathCollationSupport = xctxt.getXPathCollationSupport();
+     
+     int[] codePointsArr = xPathCollationSupport.getCodepointsFromString(inpStr);
      
      ResultSequence resultSeq = new ResultSequence();
      
diff --git a/src/org/apache/xpath/xs/types/XSString.java b/src/org/apache/xpath/xs/types/XSString.java
new file mode 100644
index 00000000..c933460b
--- /dev/null
+++ b/src/org/apache/xpath/xs/types/XSString.java
@@ -0,0 +1,104 @@
+/*
+ * 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;
+
+/**
+ * An XML Schema data type representation, of the xs:string datatype.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class XSString extends XSCtrType {
+
+    private static final long serialVersionUID = -7351932310979358488L;
+
+    private static final String XS_STRING = "xs:string";
+    
+    private String _value;
+    
+    /*
+     * Class constructor.
+    */
+    public XSString(String str) {
+       _value = str;
+    }
+
+    /*
+     * Class constructor.
+    */
+    public XSString() {
+       this(null);
+    }
+
+    @Override
+    public ResultSequence constructor(ResultSequence arg) {        
+        ResultSequence resultSeq = new ResultSequence();
+        
+        if (arg.size() == 0) {
+           return resultSeq;     
+        }
+        
+        XSAnyType xsAnyType = (XSAnyType)arg.item(0);
+        
+        resultSeq.add(new XSString(xsAnyType.stringValue()));
+           
+        return resultSeq;        
+    }
+
+    @Override
+    public String typeName() {
+        return "string";
+    }
+
+    @Override
+    public String stringType() {
+        return XS_STRING;
+    }
+
+    @Override
+    public String stringValue() {
+        return _value;
+    }
+    
+    /**
+     * Get the actual string value stored, within this object.
+     * 
+     * @return   the actual string value stored
+     */
+    public String value() {
+        return stringValue();
+    }
+    
+    public boolean equals(XSString xsStr) {
+        // TO DO
+        return false; 
+    }
+    
+    public boolean lt(XSString xsStr) {
+        // TO DO
+        return false;  
+    }
+    
+    public boolean gt(XSString xsStr) {
+        // TO DO
+        return false;  
+    }
+
+}
diff --git a/tests/fn_compare/gold/test1.out b/tests/fn_compare/gold/test1.out
new file mode 100644
index 00000000..bf104997
--- /dev/null
+++ b/tests/fn_compare/gold/test1.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>0</one>
+  <two>-1</two>
+  <three>0</three>
+  <four>-1</four>
+</result>
diff --git a/tests/fn_compare/gold/test2.out b/tests/fn_compare/gold/test2.out
new file mode 100644
index 00000000..84f7cb10
--- /dev/null
+++ b/tests/fn_compare/gold/test2.out
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>0</one>
+  <two>-1</two>
+  <three>0</three>
+  <four>-1</four>
+  <five>0</five>
+  <six>-1</six>
+  <seven>0</seven>
+  <eight>-1</eight>
+</result>
diff --git a/tests/fn_compare/gold/test3.out b/tests/fn_compare/gold/test3.out
new file mode 100644
index 00000000..6ac8e133
--- /dev/null
+++ b/tests/fn_compare/gold/test3.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>0</one>
+  <two>-1</two>
+  <three>-1</three>
+  <four>-1</four>
+</result>
diff --git a/tests/fn_compare/test1.xsl b/tests/fn_compare/test1.xsl
new file mode 100644
index 00000000..f2334f82
--- /dev/null
+++ b/tests/fn_compare/test1.xsl
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+      
+   <!-- Test for the XPath 3.1 fn:compare() function. This stylesheet 
+        test case, borrows fn:compare function examples from XPath 3.1 
+        F&O spec.
+        
+        Whereever within fn:compare function calls, if the third argument
+        (for the collation to be used) is not present, then XalanJ uses
+        the collation 'unicode codepoint collation' as its default 
+        collation.  
+   -->                            
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:template match="/">
+     <result>
+        <one><xsl:value-of select="compare('abc', 'abc')"/></one>
+        <two><xsl:value-of select="compare('Strasse', 'Stra�e')"/></two>
+        <three><xsl:value-of select="compare('Strasse', 'Stra�e', 'http://www.w3.org/2013/collation/UCA?lang=de;strength=primary')"/></three>
+        <four><xsl:value-of select="compare('Strassen', 'Stra�e')"/></four>
+     </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/fn_compare/test1_a.xml b/tests/fn_compare/test1_a.xml
new file mode 100644
index 00000000..a5964b97
--- /dev/null
+++ b/tests/fn_compare/test1_a.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document>
+   <elem>
+     <str1>abc</str1>
+     <str2>abc</str2>
+   </elem>
+   <elem>
+     <str1>Strasse</str1>
+     <str2>Straße</str2>
+   </elem>
+   <elem>
+     <str1>Strasse</str1>
+     <str2>Straße</str2>
+   </elem>
+   <elem>
+     <str1>Strassen</str1>
+     <str2>Straße</str2>
+   </elem>
+   <data str1="abc" str2="abc"/>
+   <data str1="Strasse" str2="Straße"/>
+   <data str1="Strasse" str2="Straße"/>
+   <data str1="Strassen" str2="Straße"/>
+</document>
\ No newline at end of file
diff --git a/tests/fn_compare/test2.xsl b/tests/fn_compare/test2.xsl
new file mode 100644
index 00000000..cfd17f25
--- /dev/null
+++ b/tests/fn_compare/test2.xsl
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+      
+   <!-- Test for the XPath 3.1 fn:compare() function. This stylesheet 
+        test case, borrows fn:compare function examples from XPath 3.1 
+        F&O spec. This stylesheet, reads input data to be transformed
+        from an XML external document.
+        
+        Whereever within fn:compare function calls, if the third argument
+        (for the collation to be used) is not present, then XalanJ uses
+        the collation 'unicode codepoint collation' as its default 
+        collation.  
+   -->                           
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:template match="/document">
+     <result>
+        <one><xsl:value-of select="compare(elem[1]/str1, elem[1]/str2)"/></one>
+        <two><xsl:value-of select="compare(elem[2]/str1, elem[2]/str2)"/></two>
+        <three><xsl:value-of select="compare(elem[3]/str1, elem[3]/str2, 'http://www.w3.org/2013/collation/UCA?lang=de;strength=primary')"/></three>
+        <four><xsl:value-of select="compare(elem[4]/str1, elem[4]/str2)"/></four>
+        
+        <five><xsl:value-of select="compare(data[1]/@str1, data[1]/@str2)"/></five>
+        <six><xsl:value-of select="compare(data[2]/@str1, data[2]/@str2)"/></six>
+        <seven><xsl:value-of select="compare(data[3]/@str1, data[3]/@str2, 'http://www.w3.org/2013/collation/UCA?lang=de;strength=primary')"/></seven>
+        <eight><xsl:value-of select="compare(data[4]/@str1, data[4]/@str2)"/></eight>
+     </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/fn_compare/test3.xsl b/tests/fn_compare/test3.xsl
new file mode 100644
index 00000000..f76e504c
--- /dev/null
+++ b/tests/fn_compare/test3.xsl
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- Test for the XPath 3.1 fn:compare() function.
+        
+        Whereever within fn:compare function calls, if the third argument
+        (for the collation to be used) is not present, then XalanJ uses
+        the collation 'unicode codepoint collation' as its default 
+        collation.  
+   -->                             
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:template match="/">
+     <result>
+        <one><xsl:value-of select="compare('Strasse', 'Stra�e', 'http://www.w3.org/2013/collation/UCA?lang=de;strength=primary')"/></one>
+        <two><xsl:value-of select="compare('Strasse', 'Stra�e', 'http://www.w3.org/2013/collation/UCA?lang=de;strength=identical')"/></two>
+        <three><xsl:value-of select="compare('Strasse', 'Stra�e')"/></three>
+        <four><xsl:value-of select="compare('Strasse', 'Stra�e', 'http://www.w3.org/2005/xpath-functions/collation/codepoint')"/></four>
+     </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/grouping/gold/test25.out b/tests/grouping/gold/test25.out
new file mode 100644
index 00000000..59f0a46f
--- /dev/null
+++ b/tests/grouping/gold/test25.out
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?><document>
+  <personList profession="Software Development">
+    <person>
+      <id>1</id>
+      <name>Michael Glavassevich</name>
+    </person>
+    <person>
+      <id>2</id>
+      <name>Joseph Kessselman</name>
+    </person>
+    <person>
+      <id>5</id>
+      <name>Mukul Gandhi</name>
+    </person>
+    <person>
+      <id>6</id>
+      <name>Gary Gregory</name>
+    </person>
+  </personList>
+  <personList profession="Finance">
+    <person>
+      <id>3</id>
+      <name>Dave Carver</name>
+    </person>
+  </personList>
+  <personList profession="IT Support">
+    <person>
+      <id>4</id>
+      <name>Mary Holstege</name>
+    </person>
+  </personList>
+</document>
diff --git a/tests/grouping/test1_g.xml b/tests/grouping/test1_g.xml
new file mode 100644
index 00000000..14cb1fa7
--- /dev/null
+++ b/tests/grouping/test1_g.xml
@@ -0,0 +1,50 @@
+<document>
+  <info>
+    <info>
+      <person id="1">
+        <name>Michael Glavassevich</name>
+        <profession>Software Development</profession>
+      </person>
+    </info>
+  </info>
+  <info>
+    <info>
+      <person id="2">
+        <name>Joseph Kessselman</name>
+        <profession>Software Development</profession>
+      </person>
+    </info>
+  </info>
+  <info>
+    <info>
+      <person id="3">
+        <name>Dave Carver</name>
+        <profession>Finance</profession>
+      </person>
+    </info>
+  </info>
+  <info>
+    <info>
+      <person id="4">
+        <name>Mary Holstege</name>
+        <profession>IT Support</profession>
+      </person>
+    </info>
+  </info>
+  <info>
+    <info>
+      <person id="5">
+        <name>Mukul Gandhi</name>
+        <profession>Software Development</profession>
+      </person>
+    </info>
+  </info>
+  <info>
+    <info>
+      <person id="6">
+        <name>Gary Gregory</name>
+        <profession>Software Development</profession>
+      </person>
+    </info>
+  </info>
+</document>
\ No newline at end of file
diff --git a/tests/grouping/test25.xsl b/tests/grouping/test25.xsl
new file mode 100644
index 00000000..a0c60ccd
--- /dev/null
+++ b/tests/grouping/test25.xsl
@@ -0,0 +1,47 @@
+<?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_g.xml -->                               
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:template match="/document">
+      <document>
+         <xsl:variable name="seq1" select="for $person in .//person return $person"/>
+         <xsl:for-each-group select="$seq1" group-by="profession">
+            <personList profession="{current-grouping-key()}">
+               <xsl:apply-templates select="current-group()"/>
+            </personList>
+         </xsl:for-each-group>
+      </document>
+   </xsl:template>
+   
+   <xsl:template match="person">
+     <person>
+        <id><xsl:value-of select="@id"/></id>
+        <name><xsl:value-of select="name"/></name>
+     </person>
+   </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/FnCompareTests.java b/tests/org/apache/xalan/xpath3/FnCompareTests.java
new file mode 100644
index 00000000..8ea56aad
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnCompareTests.java
@@ -0,0 +1,80 @@
+/*
+ * 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 function fn:compare test cases.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FnCompareTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "fn_compare/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "fn_compare/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 xslFnCompareTest1() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFnCompareTest2() {
+        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 xslFnCompareTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.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 fbd2e753..75169a3e 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -21,6 +21,7 @@ import org.apache.xalan.xpath3.XsDurationComponentExtractionFunctionTests;
 import org.apache.xalan.xpath3.DynamicFunctionCallTests;
 import org.apache.xalan.xpath3.FnAbsTests;
 import org.apache.xalan.xpath3.FnCodepointsToStringTests;
+import org.apache.xalan.xpath3.FnCompareTests;
 import org.apache.xalan.xpath3.FnDistinctValuesTests;
 import org.apache.xalan.xpath3.FnFilterTests;
 import org.apache.xalan.xpath3.FnFoldLeftTests;
@@ -80,7 +81,7 @@ import org.junit.runners.Suite.SuiteClasses;
                 XsDurationComponentExtractionFunctionTests.class, XPathArithmeticOnDurationValuesTests.class,
                 NodeComparisonTests.class, SimpleMapOperatorTests.class, FnFoldLeftTests.class,
                 FnFoldRightTests.class, FnForEachPairTests.class, FnSortTests.class, FnCodepointsToStringTests.class,
-                FnStringToCodepointsTests.class })
+                FnStringToCodepointsTests.class, FnCompareTests.class })
 public class AllXsl3Tests {
 
 }
diff --git a/tests/org/apache/xalan/xslt3/GroupingTests.java b/tests/org/apache/xalan/xslt3/GroupingTests.java
index 43daf667..99cc4b9e 100644
--- a/tests/org/apache/xalan/xslt3/GroupingTests.java
+++ b/tests/org/apache/xalan/xslt3/GroupingTests.java
@@ -289,5 +289,15 @@ public class GroupingTests extends XslTransformTestsUtil {
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslGroupingTest25() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_g.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test25.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test25.out";
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
 
 }


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