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;
+ }
+
+ }