001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.expr.*;
004: import net.sf.saxon.instruct.Executable;
005: import net.sf.saxon.om.AttributeCollection;
006: import net.sf.saxon.om.Axis;
007: import net.sf.saxon.om.NamespaceConstant;
008: import net.sf.saxon.sort.SortKeyDefinition;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.ItemType;
011: import net.sf.saxon.value.EmptySequence;
012: import net.sf.saxon.value.SequenceType;
013: import net.sf.saxon.value.StringValue;
014:
015: import java.text.Collator;
016: import java.util.Comparator;
017: import java.util.Locale;
018: import java.net.URI;
019: import java.net.URISyntaxException;
020:
021: /**
022: * An xsl:sort element in the stylesheet. <br>
023: */
024:
025: public class XSLSort extends StyleElement {
026:
027: private SortKeyDefinition sortKeyDefinition;
028: private Expression select;
029: private Expression order;
030: private Expression dataType = null;
031: private Expression caseOrder;
032: private Expression lang;
033: private Expression collationName;
034:
035: /**
036: * Determine whether this type of element is allowed to contain a sequence constructor
037: * @return true: yes, it may contain a sequence constructor
038: */
039:
040: public boolean mayContainSequenceConstructor() {
041: return true;
042: }
043:
044: public void prepareAttributes() throws XPathException {
045:
046: AttributeCollection atts = getAttributeList();
047:
048: String selectAtt = null;
049: String orderAtt = null;
050: String dataTypeAtt = null;
051: String caseOrderAtt = null;
052: String langAtt = null;
053: String collationAtt = null;
054:
055: for (int a = 0; a < atts.getLength(); a++) {
056: int nc = atts.getNameCode(a);
057: String f = getNamePool().getClarkName(nc);
058: if (f == StandardNames.SELECT) {
059: selectAtt = atts.getValue(a);
060: } else if (f == StandardNames.ORDER) {
061: orderAtt = atts.getValue(a).trim();
062: } else if (f == StandardNames.DATA_TYPE) {
063: dataTypeAtt = atts.getValue(a).trim();
064: } else if (f == StandardNames.CASE_ORDER) {
065: caseOrderAtt = atts.getValue(a).trim();
066: } else if (f == StandardNames.LANG) {
067: langAtt = atts.getValue(a).trim();
068: } else if (f == StandardNames.COLLATION) {
069: collationAtt = atts.getValue(a).trim();
070: } else {
071: checkUnknownAttribute(nc);
072: }
073: }
074:
075: if (selectAtt == null) {
076: //select = new ContextItemExpression();
077: } else {
078: select = makeExpression(selectAtt);
079: }
080:
081: if (orderAtt == null) {
082: order = new StringValue("ascending");
083: } else {
084: order = makeAttributeValueTemplate(orderAtt);
085: }
086:
087: if (dataTypeAtt == null) {
088: dataType = EmptySequence.getInstance();
089: } else {
090: dataType = makeAttributeValueTemplate(dataTypeAtt);
091: }
092:
093: if (caseOrderAtt == null) {
094: caseOrder = new StringValue("#default");
095: } else {
096: caseOrder = makeAttributeValueTemplate(caseOrderAtt);
097: }
098:
099: if (langAtt == null) {
100: lang = new StringValue(Locale.getDefault().getLanguage());
101: } else {
102: lang = makeAttributeValueTemplate(langAtt);
103: }
104:
105: if (collationAtt != null) {
106: collationName = makeAttributeValueTemplate(collationAtt);
107: }
108:
109: }
110:
111: public void validate() throws XPathException {
112: if (select != null && hasChildNodes()) {
113: compileError("An xsl:sort element with a select attribute must be empty");
114: }
115: if (select == null && !hasChildNodes()) {
116: select = new ContextItemExpression();
117: }
118:
119: // Get the named or default collation
120:
121: Comparator collator = null;
122: if (collationName instanceof StringValue) {
123: String collationString = ((StringValue) collationName)
124: .getStringValue();
125: try {
126: URI collationURI = new URI(collationString);
127: if (!collationURI.isAbsolute()) {
128: URI base = new URI(getBaseURI());
129: collationURI = base.resolve(collationURI);
130: collationString = collationURI.toString();
131: }
132: } catch (URISyntaxException err) {
133: compileError("Collation name '" + collationString
134: + "' is not a valid URI");
135: collationString = NamespaceConstant.CODEPOINT_COLLATION_URI;
136: }
137: collator = getPrincipalStylesheet().findCollation(
138: collationString);
139: if (collator == null) {
140: compileError("Collation " + collationString
141: + " has not been defined");
142: collator = Collator.getInstance(); // for recovery paths
143: }
144: }
145:
146: select = typeCheck("select", select);
147: order = typeCheck("order", order);
148: caseOrder = typeCheck("case-order", caseOrder);
149: lang = typeCheck("lang", lang);
150: dataType = typeCheck("data-type", dataType);
151: collationName = typeCheck("collation", collationName);
152:
153: if (select != null) {
154: try {
155: RoleLocator role = new RoleLocator(
156: RoleLocator.INSTRUCTION, "xsl:sort/select", 0,
157: null);
158: role.setSourceLocator(new ExpressionLocation(this ));
159: select = TypeChecker.staticTypeCheck(select,
160: SequenceType.ATOMIC_SEQUENCE, false, role,
161: getStaticContext());
162: } catch (XPathException err) {
163: compileError(err);
164: }
165: }
166:
167: sortKeyDefinition = new SortKeyDefinition();
168: sortKeyDefinition.setOrder(order);
169: sortKeyDefinition.setCaseOrder(caseOrder);
170: sortKeyDefinition.setLanguage(lang);
171: sortKeyDefinition.setSortKey(select);
172: sortKeyDefinition.setDataTypeExpression(dataType);
173: sortKeyDefinition.setCollationName(collationName);
174: sortKeyDefinition.setCollation(collator);
175: sortKeyDefinition.setBaseURI(getBaseURI());
176: }
177:
178: /**
179: * Determine the type of item returned by this instruction (only relevant if
180: * it is an instruction). Default implementation returns Type.ITEM, indicating
181: * that we don't know, it might be anything. Returns null in the case of an element
182: * such as xsl:sort or xsl:variable that can appear in a sequence constructor but
183: * contributes nothing to the result sequence.
184: * @return the item type returned
185: */
186:
187: protected ItemType getReturnedItemType() {
188: return null;
189: }
190:
191: public Expression compile(Executable exec) throws XPathException {
192: if (select == null) {
193: Expression b = compileSequenceConstructor(exec,
194: iterateAxis(Axis.CHILD), true);
195: if (b instanceof ComputedExpression) {
196: ((ComputedExpression) b).setParentExpression(this );
197: }
198: if (b == null) {
199: b = EmptySequence.getInstance();
200: }
201: try {
202: StaticContext env = getStaticContext();
203: Atomizer atomizedSortKey = new Atomizer(
204: b.simplify(env), env.getConfiguration());
205: atomizedSortKey.setParentExpression(sortKeyDefinition
206: .getParentExpression());
207: sortKeyDefinition.setSortKey(atomizedSortKey);
208: } catch (XPathException e) {
209: compileError(e);
210: }
211: }
212: // Simplify the sort key definition - this is especially important in the case where
213: // all aspects of the sort key are known statically.
214: sortKeyDefinition = sortKeyDefinition.simplify(
215: getStaticContext(), exec);
216: // not an executable instruction
217: return null;
218: }
219:
220: public SortKeyDefinition getSortKeyDefinition() {
221: return sortKeyDefinition;
222: }
223:
224: }
225:
226: //
227: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
228: // you may not use this file except in compliance with the License. You may obtain a copy of the
229: // License at http://www.mozilla.org/MPL/
230: //
231: // Software distributed under the License is distributed on an "AS IS" basis,
232: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
233: // See the License for the specific language governing rights and limitations under the License.
234: //
235: // The Original Code is: all this file.
236: //
237: // The Initial Developer of the Original Code is Michael H. Kay.
238: //
239: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
240: //
241: // Contributor(s): none.
242: //
|