001: package net.sf.saxon.trans;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.sort.IntHashMap;
005: import net.sf.saxon.value.QNameValue;
006: import net.sf.saxon.expr.*;
007: import net.sf.saxon.functions.ConstructorFunctionLibrary;
008: import net.sf.saxon.functions.FunctionLibrary;
009: import net.sf.saxon.functions.FunctionLibraryList;
010: import net.sf.saxon.functions.SystemFunctionLibrary;
011: import net.sf.saxon.instruct.LocationMap;
012: import net.sf.saxon.instruct.SlotManager;
013: import net.sf.saxon.om.*;
014: import net.sf.saxon.type.AtomicType;
015: import net.sf.saxon.type.Type;
016:
017: import javax.xml.transform.SourceLocator;
018: import java.io.Serializable;
019: import java.util.*;
020:
021: /**
022: * An IndependentContext provides a context for parsing an expression or pattern appearing
023: * in a context other than a stylesheet.
024: *
025: * This class was formerly named StandaloneContext. It has forked from that class, so that
026: * StandaloneContext could be changed to meet the demands of the JAXP 1.3 XPath API.
027: */
028:
029: public class IndependentContext implements StaticContext,
030: NamespaceResolver, Serializable {
031:
032: private NamePool namePool;
033: private HashMap namespaces = new HashMap(10);
034: private HashMap collations = new HashMap(10);
035: private IntHashMap variables = new IntHashMap(20);
036: private SlotManager stackFrameMap;
037: private String defaultCollationName = null;
038: private String baseURI = null;
039: private Configuration config;
040: private LocationMap locationMap = new LocationMap();
041: private FunctionLibrary functionLibrary;
042: private String defaultFunctionNamespace = NamespaceConstant.FN;
043: //private StaticContext schemaImporter = null;
044: private NamespaceResolver externalResolver = null;
045: private Set importedSchemaNamespaces = Collections.EMPTY_SET;
046:
047: public IndependentContext() {
048: this (new Configuration());
049: }
050:
051: /**
052: * Create an IndependentContext using a specific Configuration
053: */
054:
055: public IndependentContext(Configuration config) {
056: this .config = config;
057: namePool = config.getNamePool();
058: stackFrameMap = config.makeSlotManager();
059: clearNamespaces();
060:
061: // Set up a default function library. This can be overridden using setFunctionLibrary()
062:
063: FunctionLibraryList lib = new FunctionLibraryList();
064: lib.addFunctionLibrary(new SystemFunctionLibrary(
065: SystemFunctionLibrary.XPATH_ONLY));
066: lib.addFunctionLibrary(getConfiguration()
067: .getVendorFunctionLibrary());
068: lib.addFunctionLibrary(new ConstructorFunctionLibrary(
069: getConfiguration()));
070: if (config.isAllowExternalFunctions()) {
071: lib.addFunctionLibrary(config.getExtensionBinder());
072: }
073: functionLibrary = lib;
074: }
075:
076: /**
077: * Create a copy of this IndependentContext. All aspects of the context are copied
078: * except for declared variables.
079: */
080:
081: public IndependentContext copy() {
082: IndependentContext ic = new IndependentContext(config);
083: ic.namespaces = new HashMap(namespaces);
084: ic.collations = new HashMap(collations);
085: ic.variables = new IntHashMap(10);
086: ic.defaultCollationName = defaultCollationName;
087: ic.baseURI = baseURI;
088: ic.locationMap = locationMap;
089: ic.functionLibrary = functionLibrary;
090: ic.defaultFunctionNamespace = defaultFunctionNamespace;
091: ic.importedSchemaNamespaces = importedSchemaNamespaces;
092: ic.externalResolver = externalResolver;
093: return ic;
094: }
095:
096: /**
097: * Get the system configuration
098: */
099:
100: public Configuration getConfiguration() {
101: return config;
102: }
103:
104: /**
105: * Construct a dynamic context for early evaluation of constant subexpressions
106: */
107:
108: public XPathContext makeEarlyEvaluationContext() {
109: return new EarlyEvaluationContext(this );
110: }
111:
112: public LocationMap getLocationMap() {
113: return locationMap;
114: }
115:
116: public void setLocationMap(LocationMap locationMap) {
117: this .locationMap = locationMap;
118: }
119:
120: /**
121: * Declare a namespace whose prefix can be used in expressions
122: * @param prefix The namespace prefix. Must not be null. Must not be the empty string
123: * ("") - unqualified names in an XPath expression always refer to the null namespace.
124: * @param uri The namespace URI. Must not be null.
125: */
126:
127: public void declareNamespace(String prefix, String uri) {
128: if (prefix == null) {
129: throw new NullPointerException(
130: "Null prefix supplied to declareNamespace()");
131: }
132: if (uri == null) {
133: throw new NullPointerException(
134: "Null namespace URI supplied to declareNamespace()");
135: }
136: namespaces.put(prefix, uri);
137: namePool.allocateNamespaceCode(prefix, uri);
138: }
139:
140: /**
141: * Clear all the declared namespaces, except for the standard ones (xml, xslt, saxon, xdt)
142: */
143:
144: public void clearNamespaces() {
145: namespaces.clear();
146: declareNamespace("xml", NamespaceConstant.XML);
147: declareNamespace("xsl", NamespaceConstant.XSLT);
148: declareNamespace("saxon", NamespaceConstant.SAXON);
149: declareNamespace("xs", NamespaceConstant.SCHEMA);
150: declareNamespace("xdt", NamespaceConstant.XDT);
151: declareNamespace("", "");
152: }
153:
154: /**
155: * Clear all the declared namespaces, including the standard ones (xml, xslt, saxon).
156: * Leave only the XML namespace and the default namespace (xmlns="")
157: */
158:
159: public void clearAllNamespaces() {
160: namespaces.clear();
161: declareNamespace("xml", NamespaceConstant.XML);
162: declareNamespace("", "");
163: }
164:
165: /**
166: * Set all the declared namespaces to be the namespaces that are in-scope for a given node.
167: * In addition, the standard namespaces (xml, xslt, saxon) are declared.
168: * @param node The node whose in-scope namespaces are to be used as the context namespaces.
169: * If the node is an attribute, text node, etc, then the namespaces of its parent element are used.
170: */
171:
172: public void setNamespaces(NodeInfo node) {
173: namespaces.clear();
174: int kind = node.getNodeKind();
175: if (kind == Type.ATTRIBUTE || kind == Type.TEXT
176: || kind == Type.COMMENT
177: || kind == Type.PROCESSING_INSTRUCTION
178: || kind == Type.NAMESPACE) {
179: node = node.getParent();
180: }
181: if (node == null) {
182: return;
183: }
184:
185: AxisIterator iter = node.iterateAxis(Axis.NAMESPACE);
186: while (true) {
187: NodeInfo ns = (NodeInfo) iter.next();
188: if (ns == null) {
189: return;
190: }
191: declareNamespace(ns.getLocalPart(), ns.getStringValue());
192: }
193: }
194:
195: /**
196: * Set an external namespace resolver. If this is set, then all resolution of namespace
197: * prefixes is delegated to the external namespace resolver, and namespaces declared
198: * individually on this IndependentContext object are ignored.
199: */
200:
201: public void setNamespaceResolver(NamespaceResolver resolver) {
202: this .externalResolver = resolver;
203: }
204:
205: /**
206: * Set the base URI in the static context
207: */
208:
209: public void setBaseURI(String baseURI) {
210: this .baseURI = baseURI;
211: }
212:
213: /**
214: * Declare a named collation
215: * @param name The name of the collation (technically, a URI)
216: * @param comparator The Java Comparator used to implement the collating sequence
217: * @param isDefault True if this is to be used as the default collation
218: */
219:
220: public void declareCollation(String name, Comparator comparator,
221: boolean isDefault) {
222: collations.put(name, comparator);
223: if (isDefault) {
224: defaultCollationName = name;
225: }
226: }
227:
228: /**
229: * Get the stack frame map containing the slot number allocations for the variables declared
230: * in this static context
231: */
232:
233: public SlotManager getStackFrameMap() {
234: return stackFrameMap;
235: }
236:
237: /**
238: * Declare a variable. A variable must be declared before an expression referring
239: * to it is compiled. The initial value of the variable will be the empty sequence
240: * @param qname The name of the variable
241: */
242:
243: public Variable declareVariable(QNameValue qname) {
244: Variable var = Variable.make(qname, getConfiguration());
245: var.setXPathValue(null);
246: int fingerprint = qname.allocateNameCode(getNamePool()) & 0xfffff;
247: variables.put(fingerprint, var);
248: stackFrameMap.allocateSlotNumber(fingerprint);
249: return var;
250: }
251:
252: /**
253: * Declare a variable. A variable may be declared before an expression referring
254: * to it is compiled. Alternatively, a JAXP XPathVariableResolver may be supplied
255: * to perform the resolution. A variable that has been explicitly declared is
256: * used in preference.
257: * @param qname Lexical QName identifying the variable. The namespace prefix, if
258: * any, must have been declared before this method is called, or must be resolvable
259: * using the namespace context.
260: */
261:
262: public Variable declareVariable(String qname) throws XPathException {
263: String prefix;
264: String localName;
265: final NameChecker checker = getConfiguration().getNameChecker();
266: try {
267: String[] parts = checker.getQNameParts(qname);
268: prefix = parts[0];
269: localName = parts[1];
270: } catch (QNameException err) {
271: throw new StaticError("Invalid QName for variable: "
272: + qname);
273: }
274: String uri = "";
275: if (!("".equals(prefix))) {
276: uri = getURIForPrefix(prefix);
277: }
278: QNameValue q = new QNameValue(prefix, uri, localName, checker);
279: Variable var = Variable.make(q, getConfiguration());
280: int fingerprint = namePool.allocate(prefix, uri, localName) & 0xfffff;
281: variables.put(fingerprint, var);
282: stackFrameMap.allocateSlotNumber(fingerprint);
283: return var;
284: }
285:
286: /**
287: * Get the NamePool used for compiling expressions
288: */
289:
290: public NamePool getNamePool() {
291: return namePool;
292: }
293:
294: /**
295: * Issue a compile-time warning. This method is used during XPath expression compilation to
296: * output warning conditions. The default implementation writes the message to System.err. To
297: * change the destination of messages, create a subclass of StandaloneContext that overrides
298: * this method.
299: */
300:
301: public void issueWarning(String s, SourceLocator locator) {
302: System.err.println(s);
303: }
304:
305: /**
306: * Get the system ID of the container of the expression. Used to construct error messages.
307: * @return "" always
308: */
309:
310: public String getSystemId() {
311: return "";
312: }
313:
314: /**
315: * Get the Base URI of the stylesheet element, for resolving any relative URI's used
316: * in the expression.
317: * Used by the document() function, resolve-uri(), etc.
318: * @return "" if no base URI has been set
319: */
320:
321: public String getBaseURI() {
322: return baseURI == null ? "" : baseURI;
323: }
324:
325: /**
326: * Get the line number of the expression within that container.
327: * Used to construct error messages.
328: * @return -1 always
329: */
330:
331: public int getLineNumber() {
332: return -1;
333: }
334:
335: /**
336: * Get the URI for a prefix, using the declared namespaces as
337: * the context for namespace resolution. The default namespace is NOT used
338: * when the prefix is empty.
339: * This method is provided for use by the XPath parser.
340: * @param prefix The prefix
341: * @throws net.sf.saxon.trans.XPathException if the prefix is not declared
342: */
343:
344: public String getURIForPrefix(String prefix) throws XPathException {
345: String uri = getURIForPrefix(prefix, false);
346: if (uri == null) {
347: throw new StaticError("Prefix " + prefix
348: + " has not been declared");
349: }
350: return uri;
351: }
352:
353: public NamespaceResolver getNamespaceResolver() {
354: if (externalResolver != null) {
355: return externalResolver;
356: } else {
357: return this ;
358: }
359: }
360:
361: /**
362: * Get the namespace URI corresponding to a given prefix. Return null
363: * if the prefix is not in scope.
364: * @param prefix the namespace prefix
365: * @param useDefault true if the default namespace is to be used when the
366: * prefix is ""
367: * @return the uri for the namespace, or null if the prefix is not in scope.
368: * Return "" if the prefix maps to the null namespace.
369: */
370:
371: public String getURIForPrefix(String prefix, boolean useDefault) {
372: if (externalResolver != null) {
373: return externalResolver.getURIForPrefix(prefix, useDefault);
374: }
375: if (prefix.equals("") && !useDefault) {
376: return "";
377: } else {
378: return (String) namespaces.get(prefix);
379: }
380: }
381:
382: /**
383: * Get an iterator over all the prefixes declared in this namespace context. This will include
384: * the default namespace (prefix="") and the XML namespace where appropriate
385: */
386:
387: public Iterator iteratePrefixes() {
388: if (externalResolver != null) {
389: return externalResolver.iteratePrefixes();
390: } else {
391: return namespaces.keySet().iterator();
392: }
393: }
394:
395: /**
396: * Bind a variable used in an XPath Expression to the XSLVariable element in which it is declared.
397: * This method is provided for use by the XPath parser, and it should not be called by the user of
398: * the API, or overridden, unless variables are to be declared using a mechanism other than the
399: * declareVariable method of this class.
400: */
401:
402: public VariableReference bindVariable(int fingerprint)
403: throws StaticError {
404: Variable var = (Variable) variables.get(fingerprint);
405: if (var == null) {
406: throw new StaticError(
407: "Undeclared variable in a standalone expression");
408: } else {
409: return new VariableReference(var);
410: }
411: }
412:
413: /**
414: * Get the function library containing all the in-scope functions available in this static
415: * context
416: */
417:
418: public FunctionLibrary getFunctionLibrary() {
419: return functionLibrary;
420: }
421:
422: /**
423: * Set the function library to be used
424: */
425:
426: public void setFunctionLibrary(FunctionLibrary lib) {
427: functionLibrary = lib;
428: }
429:
430: /**
431: * Get a named collation.
432: * @return the collation identified by the given name, as set previously using declareCollation.
433: * Return null if no collation with this name is found.
434: */
435:
436: public Comparator getCollation(String name) {
437: Configuration config = getConfiguration();
438: return config.getCollationURIResolver().resolve(name,
439: getBaseURI(), config);
440: }
441:
442: /**
443: * Get the name of the default collation.
444: * @return the name of the default collation; or the name of the codepoint collation
445: * if no default collation has been defined
446: */
447:
448: public String getDefaultCollationName() {
449: if (defaultCollationName != null) {
450: return defaultCollationName;
451: } else {
452: return NamespaceConstant.CODEPOINT_COLLATION_URI;
453: }
454: }
455:
456: /**
457: * Get the default XPath namespace, as a namespace code that can be looked up in the NamePool
458: */
459:
460: public short getDefaultElementNamespace() {
461: return NamespaceConstant.NULL_CODE;
462: }
463:
464: /**
465: * Set the default function namespace
466: */
467:
468: public void setDefaultFunctionNamespace(String uri) {
469: defaultFunctionNamespace = uri;
470: }
471:
472: /**
473: * Get the default function namespace
474: */
475:
476: public String getDefaultFunctionNamespace() {
477: return defaultFunctionNamespace;
478: }
479:
480: /**
481: * Determine whether Backwards Compatible Mode is used
482: * @return false; XPath 1.0 compatibility mode is not supported in the standalone
483: * XPath API
484: */
485:
486: public boolean isInBackwardsCompatibleMode() {
487: return false;
488: }
489:
490: public boolean isImportedSchema(String namespace) {
491: return importedSchemaNamespaces.contains(namespace);
492: }
493:
494: /**
495: * Determine whether a built-in type is available in this context. This method caters for differences
496: * between host languages as to which set of types are built in.
497: *
498: * @param type the supposedly built-in type. This will always be a type in the
499: * XS or XDT namespace.
500: * @return true if this type can be used in this static context
501: */
502:
503: public boolean isAllowedBuiltInType(AtomicType type) {
504: return true;
505: }
506:
507: /**
508: * Get the set of imported schemas
509: *
510: * @return a Set, the set of URIs representing the names of imported schemas
511: */
512:
513: public Set getImportedSchemaNamespaces() {
514: return importedSchemaNamespaces;
515: }
516:
517: public void setImportedSchemaNamespaces(Set namespaces) {
518: importedSchemaNamespaces = namespaces;
519: }
520:
521: // public void setSchemaImporter(StaticContext importer) {
522: // schemaImporter = importer;
523: // }
524:
525: }
526:
527: //
528: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
529: // you may not use this file except in compliance with the License. You may obtain a copy of the
530: // License at http://www.mozilla.org/MPL/
531: //
532: // Software distributed under the License is distributed on an "AS IS" basis,
533: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
534: // See the License for the specific language governing rights and limitations under the License.
535: //
536: // The Original Code is: all this file.
537: //
538: // The Initial Developer of the Original Code is Michael H. Kay
539: //
540: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
541: //
542: // Contributor(s): none.
543: //
|