001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.Err;
004: import net.sf.saxon.expr.Expression;
005: import net.sf.saxon.expr.StaticContext;
006: import net.sf.saxon.expr.XPathContext;
007: import net.sf.saxon.sort.AtomicComparer;
008: import net.sf.saxon.sort.CodepointCollator;
009: import net.sf.saxon.trans.DynamicError;
010: import net.sf.saxon.trans.StaticError;
011: import net.sf.saxon.trans.XPathException;
012: import net.sf.saxon.value.AtomicValue;
013: import net.sf.saxon.value.StringValue;
014: import net.sf.saxon.value.Value;
015:
016: import java.net.URI;
017: import java.net.URISyntaxException;
018: import java.net.URL;
019: import java.net.MalformedURLException;
020: import java.util.Comparator;
021: import java.io.File;
022:
023: /**
024: * Abstract superclass for all functions that take an optional collation argument
025: */
026:
027: // Supports string comparison using a collation
028: public abstract class CollatingFunction extends SystemFunction {
029:
030: // The collation, if known statically
031: private Comparator collation = null;
032: protected XPathContext conversionContext;
033: private URI expressionBaseURI = null;
034:
035: public void checkArguments(StaticContext env) throws XPathException {
036: try {
037: String base = env.getBaseURI();
038: if (base == null) {
039: base = getCurrentDirectory();
040: }
041: if (base != null) {
042: expressionBaseURI = new URI(base);
043: }
044: } catch (URISyntaxException e) {
045: StaticError err = new StaticError("The base URI "
046: + Err.wrap(env.getBaseURI(), Err.URI)
047: + " is not a valid URI");
048: err.setLocator(this );
049: throw err;
050: }
051: super .checkArguments(env);
052: }
053:
054: private String getCurrentDirectory() {
055: String dir;
056: try {
057: dir = System.getProperty("user.dir");
058: } catch (Exception geterr) {
059: // this doesn't work when running an applet
060: return null;
061: }
062: if (!(dir.endsWith("/"))) {
063: dir = dir + '/';
064: }
065:
066: try {
067: URL currentDirectoryURL = new File(dir).toURL();
068: return currentDirectoryURL.toString();
069: } catch (MalformedURLException err2) {
070: return null;
071: }
072: }
073:
074: /**
075: * preEvaluate: if all arguments are known statically, evaluate early
076: */
077:
078: public Expression preEvaluate(StaticContext env)
079: throws XPathException {
080: //conversionContext = env.makeEarlyEvaluationContext();
081: if (getNumberOfArguments() == getDetails().maxArguments) {
082: // A collation was supplied explicitly (as a compile-time name, or we wouldn't be here)
083: String collationName = ((Value) argument[getNumberOfArguments() - 1])
084: .getStringValue();
085: URI collationURI;
086: try {
087: collationURI = new URI(collationName);
088: if (!collationURI.isAbsolute()) {
089: URI base = new URI(env.getBaseURI());
090: collationURI = base.resolve(collationURI);
091: collationName = collationURI.toString();
092: }
093: } catch (URISyntaxException e) {
094: StaticError err = new StaticError("Collation name '"
095: + collationName + "' is not a valid URI");
096: err.setErrorCode("FOCH0002");
097: err.setLocator(this );
098: throw err;
099: }
100: collation = env.getCollation(collationName);
101: if (collation == null) {
102: StaticError err = new StaticError("Unknown collation "
103: + Err.wrap(collationName, Err.URI));
104: err.setErrorCode("FOCH0002");
105: err.setLocator(this );
106: throw err;
107: }
108: return super .preEvaluate(env);
109: } else {
110: // Use the default collation
111: String uri = env.getDefaultCollationName();
112: collation = env.getCollation(uri);
113: return super .preEvaluate(env);
114: }
115: }
116:
117: /**
118: * Get a AtomicComparer that can be used to compare values
119: * @param arg the position of the argument (starting at 0) containing the collation name.
120: * If this argument was not supplied, the default collation is used
121: * @param context The dynamic evaluation context.
122: */
123:
124: protected AtomicComparer getAtomicComparer(int arg,
125: XPathContext context) throws XPathException {
126: return new AtomicComparer(getCollator(arg, context),
127: (context == null ? conversionContext : context));
128: }
129:
130: /**
131: * Get a collator suitable for comparing strings. Returns the collator specified in the
132: * given function argument if present, otherwise returns the default collator.
133: * @param arg The argument position (counting from zero) that holds the collation
134: * URI if present
135: * @param context The dynamic context
136: * @return a Comparator, which will either be a java.text.Collator, or a CodepointCollator
137: */
138:
139: protected Comparator getCollator(int arg, XPathContext context)
140: throws XPathException {
141:
142: if (collation != null) {
143: // the collation was determined statically
144: return collation;
145: } else {
146: int numargs = argument.length;
147: if (numargs > arg) {
148: AtomicValue av = (AtomicValue) argument[arg]
149: .evaluateItem(context);
150: StringValue collationValue = (StringValue) av
151: .getPrimitiveValue();
152: String collationName = collationValue.getStringValue();
153: URI collationURI;
154: try {
155: collationURI = new URI(collationName);
156: if (!collationURI.isAbsolute()) {
157: if (expressionBaseURI == null) {
158: DynamicError err = new DynamicError(
159: "Cannot resolve relative collation URI '"
160: + collationName
161: + "': unknown base URI");
162: err.setErrorCode("FOCH0002");
163: err.setXPathContext(context);
164: err.setLocator(this );
165: throw err;
166: }
167: collationURI = expressionBaseURI
168: .resolve(collationURI);
169: collationName = collationURI.toString();
170: }
171: } catch (URISyntaxException e) {
172: DynamicError err = new DynamicError(
173: "Collation name '" + collationName
174: + "' is not a valid URI");
175: err.setErrorCode("FOCH0002");
176: err.setXPathContext(context);
177: err.setLocator(this );
178: throw err;
179: }
180: return context.getCollation(collationName);
181: } else {
182: Comparator collator = context.getDefaultCollation();
183: return (collator == null ? CodepointCollator
184: .getInstance() : collator);
185: }
186: }
187: }
188: }
189:
190: //
191: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
192: // you may not use this file except in compliance with the License. You may obtain a copy of the
193: // License at http://www.mozilla.org/MPL/
194: //
195: // Software distributed under the License is distributed on an "AS IS" basis,
196: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
197: // See the License for the specific language governing rights and limitations under the License.
198: //
199: // The Original Code is: all this file.
200: //
201: // The Initial Developer of the Original Code is Michael H. Kay.
202: //
203: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
204: //
205: // Contributor(s): none.
206: //
|