You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by bu...@apache.org on 2001/04/19 16:25:30 UTC

[Bug 1396] New - xsltc sort collation incorrect and case-order not working

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=1396

*** shadow/1396	Thu Apr 19 07:25:29 2001
--- shadow/1396.tmp.28533	Thu Apr 19 07:25:30 2001
***************
*** 0 ****
--- 1,293 ----
+ +============================================================================+
+ | xsltc sort collation incorrect and case-order not working                  |
+ +----------------------------------------------------------------------------+
+ |        Bug #: 1396                        Product: XalanJ2                 |
+ |       Status: NEW                         Version: 2.0.0                   |
+ |   Resolution:                            Platform: Sun                     |
+ |     Severity: Normal                   OS/Version: Solaris                 |
+ |     Priority: Medium                    Component: org.apache.xalan.xsltc  |
+ +----------------------------------------------------------------------------+
+ |  Assigned To: xalan-dev@xml.apache.org                                     |
+ |  Reported By: tamiro@east.sun.com                                          |
+ |      CC list: Cc:                                                          |
+ +----------------------------------------------------------------------------+
+ |          URL:                                                              |
+ +============================================================================+
+ |                              DESCRIPTION                                   |
+ [from SunMicrosystem's bug 4398991]
+ When a stylesheet includes case-order="upper-first" attribute, the 
+ selected text is not being sorted with upper case taking 
+ precedence over lower case. For example, the test output has 
+ "czech" coming before "Czech", when the reverse should be the case.
+ 
+ The following test shows xsltc is not collating text correctly, even with
+ english as the default language. 
+ 
+ Here's the style sheet:
+ 
+ <?xml version="1.0"?> 
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ 
+   <!-- FileName: SORT08 -->
+   <!-- Document: http://www.w3.org/TR/xslt -->
+   <!-- DocVersion: 19991116 -->
+   <!-- Section: 10 -->
+   <!-- Purpose: Test for xsl:sort on letters and spaces. -->
+ 
+ <xsl:template match="doc">
+   <out>
+     Ascending order....
+     <xsl:for-each select="t">
+       <xsl:sort data-type="text"/>
+       <xsl:value-of select="."/><xsl:text>|</xsl:text>
+     </xsl:for-each>
+   </out>
+ </xsl:template>
+ 
+ </xsl:stylesheet>
+ 
+ Here's the xml file:
+ 
+ <?xml version="1.0"?> 
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ 
+   <!-- FileName: SORT08 -->
+   <!-- Document: http://www.w3.org/TR/xslt -->
+   <!-- DocVersion: 19991116 -->
+   <!-- Section: 10 -->
+   <!-- Purpose: Test for xsl:sort on letters and spaces. -->
+ 
+ <xsl:template match="doc">
+   <out>
+     Ascending order....
+     <xsl:for-each select="t">
+       <xsl:sort data-type="text"/>
+       <xsl:value-of select="."/><xsl:text>|</xsl:text>
+     </xsl:for-each>
+   </out>
+ </xsl:template>
+ 
+ </xsl:stylesheet>
+ 
+ Here's the differences between xsltc's ouput and the 
+ expected output (as obtained from Saxon):
+ 
+ XSLTC
+ <     Ascending order....
+ <     a!b|a!b |a!b!|a!c|a!cd|ab|ab |a b|ab!|ab%|abc|abcd|abd|ac |a c|ac!|a
+ c%|acc|a  d|</out>
+ 
+ SAXON
+ >     Ascending order....    
+ >     a  d|a b|a c|a c%|a!b|a!b |a!b!|a!c|a!cd|ab|ab |ab!|ab%|abc|abcd|abd|ac
+ |ac!|acc|</out>
+ 
+ According to the collation tables published at
+ www.unicode.org/unicode/reports/tr10,
+ a space should come before the exclamation point which should come before the 
+ percent sign, all of which should come before letters like abcd, etc.
+ 
+ The obtained results don't adhere to this expected collation order.
+ This problem was reproduced on JRE 1.3 on a Windows PC as well as with 
+ JRE 1.2.1 on the Solaris platform. 
+ 
+ I took a look at Saxon's source code to see how it handles sorting, since Saxon 
+ produces the correct results with this test, and it is coded in Java. Looks like
+ he doesn't depend on some built-in Java collation classes. 
+ 
+ Here is a dump of some of Saxon's sorting code that may help you understand
+ how Saxon does it:
+ 
+ package com.icl.saxon.sort;
+ import com.icl.saxon.*;
+ //import com.icl.saxon.om.Name;
+ import org.xml.sax.*;
+ 
+ // Copyright � International Computers Limited 1998
+ // See conditions of use
+ 
+ /**
+  * A Comparer used for comparing keys
+  *
+  * @author Michael H. Kay, ICL (Michael.Kay@icl.com)
+  *
+  */
+ 
+ public abstract class Comparer {
+ 
+     /**
+     * Compare two objects.
+     * @return <0 if a<b, 0 if a=b, >0 if a>b
+     * @throws ClassCastException if the objects are of the wrong type for this
+ Comparer
+     */
+ 
+     public abstract int compare(Object a, Object b);
+ 
+     /**
+     * Set data type. The comparer has the option of returning a different
+ comparer
+     * once it knows the data type
+     */
+ 
+     public Comparer setDataType(String dataTypeURI, String dataTypeLocalName)
+ throws SAXException {
+         return this;
+     }
+ 
+     /**
+     * Set order. The comparer has the option of returning a different comparer
+     */
+ 
+     public Comparer setOrder(boolean isAscending) throws SAXException {
+         return (isAscending ? this : new DescendingComparer(this) );
+     }
+ 
+ }
+  glrr 59 =>cat TextComparer.java
+ package com.icl.saxon.sort;
+ import org.xml.sax.SAXException;
+ 
+ // Copyright � International Computers Limited 1998
+ // See conditions of use
+ 
+ /**
+  * A Comparer used for comparing text keys
+  *
+  * @author Michael H. Kay, ICL (Michael.Kay@icl.com)
+  *
+  */
+ 
+ public abstract class TextComparer extends Comparer {
+ 
+     public final static int DEFAULT_CASE_ORDER = 0;
+     public final static int LOWERCASE_FIRST = 1;
+     public final static int UPPERCASE_FIRST = 2;
+ 
+     /**
+     * Set case order
+     * @param caseOrder one of DEFAULT_CASE_ORDER, LOWERCASE_FIRST, or
+ UPPERCASE_FIRST.
+     * Indicates whether upper case letters precede or follow lower case letters
+ in the ordering
+     * @return either this or a different Comparer that will be used to perform
+ the comparisons.
+     * This allows the TextComparer to delegate the comparison to a Comparer
+ dedicated to a
+     * specific case order.
+     */
+ 
+     public Comparer setCaseOrder(int caseOrder) throws SAXException{
+         return this;
+     }
+ 
+ }
+  glrr 60 =>cat Compare_en.java
+ package com.icl.saxon.sort;
+ 
+ // Copyright � International Computers Limited 1998
+ // See conditions of use
+ 
+ /**
+  * A Comparer used with lang="en". Note this only does anything intelligent with
+ characters
+  * in ISO 8859/1, which are mapped to their unaccented equivalents
+  *
+  * @author Michael H. Kay, ICL (Michael.Kay@icl.com)
+  *
+  */
+ 
+ public class Compare_en extends TextComparer {
+ 
+     // Following string maps Latin-1 characters in the range C0-FF to equivalent
+ unaccented letter
+ 
+     private static String supp =
+     "AAAAAAACEEEEIIII[NOOOOO*OUUUUY]Saaaaaaaceeeeiiii{nooooo*ouuuuy}y";
+ 
+     int caseOrder = UPPERCASE_FIRST;
+ 
+     /**
+     * Compare two string objects, in three phases:
+     * (a) ignoring accents and case
+     * (b) if still equal, ignoring case
+     * (c) if still equal, taking case into account
+     * @return <0 if a<b, 0 if a=b, >0 if a>b
+     */
+ 
+     public int compare(Object a, Object b) {
+ 
+         char[] a1 = ((String)a).toCharArray();
+         char[] b1 = ((String)b).toCharArray();
+         int alen = a1.length;
+         int blen = b1.length;
+ 
+         // strip off the accents
+         for (int k=0; k<alen; k++) {
+             int code = (int)a1[k];
+             if (code>=192 && code<=255) {
+                 a1[k] = supp.charAt(code-192);
+             }
+         }
+         for (int k=0; k<blen; k++) {
+             int code = (int)b1[k];
+             if (code>=192 && code<=255) {
+                 b1[k] = supp.charAt(code-192);
+             }
+         }
+         int i = 0;
+         int j = 0;
+         
+         // do an accent-blind comparison
+         while (true) {
+             if (i==alen && j==blen) break;
+             if (i==alen) return -1;
+             if (j==blen) return +1;
+             int diff = Character.toLowerCase(a1[i]) -
+                              Character.toLowerCase(b1[j]);
+             i++;
+             j++;
+             if (diff!=0) return diff;
+         }
+ 
+         // still equal - try again with accents, but still case-blind
+         
+         a1 = ((String)a).toCharArray();
+         b1 = ((String)b).toCharArray();
+         i = 0;
+         j = 0;
+         while (true) {
+             if (i==alen && j==blen) break;
+             if (i==alen) return -1;
+             if (j==blen) return +1;
+             int diff = Character.toLowerCase(a1[i]) -
+                              Character.toLowerCase(b1[j]);
+             i++;
+             j++;
+             if (diff!=0) return diff;
+         }
+ 
+         // still equal: take case into account
+         
+         i = 0;
+         j = 0;
+         while (true) {
+             if (i==alen) return 0;
+             int diff = a1[i++] - b1[j++]; 
+             if (diff!=0) {
+                 if (caseOrder==LOWERCASE_FIRST) {
+                     return (Character.isLowerCase(a1[i-1]) ? -1 : +1);
+                 } else {
+                     return (Character.isUpperCase(a1[i-1]) ? -1 : +1);
+                 }
+             }
+         }        
+             
+     }
+ 
+     public Comparer setCaseOrder(int caseOrder) {
+         this.caseOrder = caseOrder;
+         return this;
+     }
+         
+ }