001: package net.sf.saxon.sort;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.expr.CardinalityChecker;
005: import net.sf.saxon.expr.RoleLocator;
006: import net.sf.saxon.expr.StaticProperty;
007: import net.sf.saxon.expr.XPathContext;
008: import net.sf.saxon.trans.DynamicError;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.value.EmptySequence;
011: import net.sf.saxon.value.StringValue;
012:
013: import java.text.Collator;
014: import java.util.Comparator;
015: import java.util.Locale;
016:
017: /**
018: * A FixedSortKeyDefinition is a SortKeyDefinition in which all aspects of the
019: * sort key definition (sort order, data type, etc,) are known.
020: * A SortKeyDefinition defines one component of a sort key. <BR>
021: *
022: */
023:
024: public class FixedSortKeyDefinition extends SortKeyDefinition {
025:
026: public FixedSortKeyDefinition() {
027: }
028:
029: private transient Comparator comparer = null;
030:
031: // Note, the "collation" defines the collating sequence for the sort key. The
032: // "comparer" is what is actually used to do comparisons, after taking into account
033: // ascending/descending, caseOrder, etc.
034:
035: public SortKeyDefinition simplify() throws XPathException {
036: return this ;
037: }
038:
039: /**
040: * Eliminate dependencies of the sort key definition on the context. For the sort key select
041: * expression, this means things that don't depend on the individual node: specifically, variables
042: * and current-group(). For the AVTs used to select data type, case order, language, it means
043: * all dependencies: after reduction, these values will be constants.
044: */
045:
046: public FixedSortKeyDefinition reduce(XPathContext context)
047: throws XPathException {
048: return this ;
049: }
050:
051: /**
052: * Allocate a reusable Comparer to implement this sort key comparison
053: */
054:
055: public void bindComparer(XPathContext context)
056: throws XPathException {
057:
058: String orderX = ((StringValue) order).getStringValue();
059: String caseOrderX = ((StringValue) caseOrder).getStringValue();
060: String languageX = ((StringValue) language).getStringValue();
061:
062: Comparator comp;
063: if (collation != null) {
064: comp = collation;
065: } else {
066: Collator base;
067: if (languageX.equals("")) {
068: // get Java collator for the default locale
069: base = Collator.getInstance();
070: } else {
071: Locale locale = Configuration.getLocale(languageX);
072: base = Collator.getInstance(locale);
073: }
074: comp = getCaseOrderComparer(base, caseOrderX);
075: }
076:
077: if (dataTypeExpression == null
078: || dataTypeExpression instanceof EmptySequence) {
079: RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION,
080: "xsl:sort/sort-key", 0, null);
081: sortKey = CardinalityChecker.makeCardinalityChecker(
082: sortKey, StaticProperty.ALLOWS_ZERO_OR_ONE, role);
083: comp = new AtomicSortComparer(comp, context);
084: } else {
085: String dataType = ((StringValue) dataTypeExpression)
086: .getStringValue();
087: if (dataType.equals("text")) {
088: comp = new TextComparer(comp);
089: } else if (dataType.equals("number")) {
090: comp = new NumericComparer();
091: } else {
092: DynamicError err = new DynamicError(
093: "data-type on xsl:sort must be 'text' or 'number'");
094: err.setErrorCode("XTDE0030");
095: throw err;
096: }
097: }
098:
099: comparer = getOrderedComparer(comp, orderX);
100: }
101:
102: private Comparator getOrderedComparer(Comparator base, String order)
103: throws XPathException {
104: if (order.equals("ascending")) {
105: return base;
106: } else if (order.equals("descending")) {
107: return new DescendingComparer(base);
108: } else {
109: DynamicError err = new DynamicError(
110: "order must be 'ascending' or 'descending'");
111: err.setErrorCode("XTDE0030");
112: throw err;
113: }
114: }
115:
116: private Comparator getCaseOrderComparer(Collator base,
117: String caseOrder) throws XPathException {
118: if (caseOrder.equals("#default")) {
119: return base;
120: } else if (caseOrder.equals("lower-first")) {
121: return new LowercaseFirstComparer(base);
122: } else if (caseOrder.equals("upper-first")) {
123: return new UppercaseFirstComparer(base);
124: } else {
125: DynamicError err = new DynamicError(
126: "case-order must be 'lower-first' or 'upper-first'");
127: err.setErrorCode("XTDE0030");
128: throw err;
129: }
130: }
131:
132: /**
133: * Get the comparer which is used to compare two values according to this sort key.
134: */
135:
136: public Comparator getComparer(XPathContext context)
137: throws XPathException {
138: return comparer;
139: }
140:
141: }
142:
143: //
144: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
145: // you may not use this file except in compliance with the License. You may obtain a copy of the
146: // License at http://www.mozilla.org/MPL/
147: //
148: // Software distributed under the License is distributed on an "AS IS" basis,
149: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
150: // See the License for the specific language governing rights and limitations under the License.
151: //
152: // The Original Code is: all this file.
153: //
154: // The Initial Developer of the Original Code is Michael H. Kay.
155: //
156: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
157: //
158: // Contributor(s): none.
159: //
|