KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > query > StaticQueryContext


1 package net.sf.saxon.query;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.event.Builder;
5 import net.sf.saxon.event.Stripper;
6 import net.sf.saxon.expr.StaticContext;
7 import net.sf.saxon.expr.VariableDeclaration;
8 import net.sf.saxon.expr.VariableReference;
9 import net.sf.saxon.expr.ExpressionLocation;
10 import net.sf.saxon.functions.ConstructorFunctionLibrary;
11 import net.sf.saxon.functions.FunctionLibrary;
12 import net.sf.saxon.functions.FunctionLibraryList;
13 import net.sf.saxon.functions.SystemFunctionLibrary;
14 import net.sf.saxon.instruct.*;
15 import net.sf.saxon.om.*;
16 import net.sf.saxon.sort.CodepointCollator;
17 import net.sf.saxon.trans.StaticError;
18 import net.sf.saxon.trans.XPathException;
19 import net.sf.saxon.type.AtomicType;
20 import net.sf.saxon.type.SchemaType;
21 import org.xml.sax.SAXParseException JavaDoc;
22
23 import javax.xml.transform.Source JavaDoc;
24 import javax.xml.transform.SourceLocator JavaDoc;
25 import javax.xml.transform.TransformerException JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.Reader JavaDoc;
29 import java.util.*;
30
31 /**
32  * StaticQueryContext is the implementation of StaticContext used when processing XQuery
33  * expressions.
34  * <p/>
35  * The StaticQueryContext object has two different usages. The application constructs a StaticQueryContext
36  * and initializes it with information about the context, for example, default namespaces, base URI, and so on.
37  * When a query is compiled using this StaticQueryContext, the query parser makes a copy of the StaticQueryContext
38  * and uses this internally, modifying it with information obtained from the query prolog, as well as information
39  * such as namespace and variable declarations that can occur at any point in the query. The query parser does
40  * not modify the original StaticQueryContext supplied by the calling application, which may therefore be used
41  * for compiling multiple queries, serially or even in multiple threads.
42  * <p/>
43  * This class forms part of Saxon's published XQuery API.
44  * Note that some of the methods are intended for use internally by the
45  * query processor itself: these are labelled as such. Methods that
46  * are considered stable are labelled with the JavaDoc "since" tag.
47  * The value 8.4 indicates a method introduced at or before Saxon 8.4; other
48  * values indicate the version at which the method was introduced.
49  * <p/>
50  * In the longer term, this entire API may at some stage be superseded by a proposed
51  * standard Java API for XQuery.
52  *
53  * @since 8.4
54  */

55
56 public class StaticQueryContext implements StaticContext {
57
58     private Configuration config;
59     private NamePool namePool;
60     private String JavaDoc locationURI;
61     private String JavaDoc moduleNamespace;
62     private String JavaDoc baseURI;
63     private HashMap passiveNamespaces;
64     private HashSet explicitPrologNamespaces;
65     private Stack activeNamespaces;
66     private boolean inheritNamespaces = true;
67     private boolean preserveNamespaces = true;
68     private HashMap collations;
69     private HashMap variables;
70     private List variableList; // unlike the hashmap, this preserves the order in which variables were declared
71
private HashSet importedSchemata;
72     private String JavaDoc defaultCollationName;
73     private String JavaDoc defaultFunctionNamespace;
74     private short defaultElementNamespace;
75     private SlotManager stackFrameMap; // map of the outermost local stackframe
76
private short moduleNamespaceURICode;
77     private int constructionMode;
78     private Executable executable;
79     private StaticQueryContext importer;
80     private FunctionLibraryList functionLibraryList;
81     private XQueryFunctionLibrary functions;
82     private Set importedModuleNamespaces;
83
84     private StaticQueryContext() {
85     }
86
87     /**
88      * Create a StaticQueryContext using a given Configuration
89      *
90      * @since 8.4
91      */

92
93     public StaticQueryContext(Configuration config) {
94         this.config = config;
95         this.namePool = config.getNamePool();
96         reset();
97     }
98
99     /**
100      * Reset the state of this StaticQueryContext to an uninitialized state
101      *
102      * @since 8.4
103      */

104
105     public void reset() {
106         passiveNamespaces = new HashMap(10);
107         explicitPrologNamespaces = new HashSet(10);
108         activeNamespaces = new Stack();
109         collations = new HashMap(5);
110         variables = new HashMap(40);
111         variableList = new ArrayList(40);
112         functions = new XQueryFunctionLibrary(config, true);
113         importedSchemata = new HashSet(5);
114         importedModuleNamespaces = new HashSet(5);
115         defaultFunctionNamespace = NamespaceConstant.FN;
116         defaultElementNamespace = NamespaceConstant.NULL_CODE;
117         moduleNamespace = null;
118         moduleNamespaceURICode = 0;
119         constructionMode = Validation.PRESERVE;
120
121         // Set up a "default default" collation based on the Java locale
122
// String lang = Locale.getDefault().getLanguage();
123
// defaultCollationName = "http://saxon.sf.net/collation?lang=" + lang + ";strength=tertiary";
124
defaultCollationName = NamespaceConstant.CODEPOINT_COLLATION_URI;
125         declareCollation(defaultCollationName, CodepointCollator.getInstance());
126         functionLibraryList = new FunctionLibraryList();
127         functionLibraryList.addFunctionLibrary(new SystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY));
128         functionLibraryList.addFunctionLibrary(config.getVendorFunctionLibrary());
129         functionLibraryList.addFunctionLibrary(new ConstructorFunctionLibrary(config));
130         if (config.isAllowExternalFunctions()) {
131             functionLibraryList.addFunctionLibrary(config.getExtensionBinder());
132         }
133         functionLibraryList.addFunctionLibrary(functions);
134
135         clearPassiveNamespaces();
136     }
137
138     /**
139      * Get the StaticQueryContext representing the module that imported this module.
140      * TODO: there might be more than one
141      */

142
143     public StaticQueryContext getImporter() {
144         return importer;
145     }
146
147     /**
148      * Register that this module imports a particular module namespace
149      */

150
151     public void addImportedNamespace(String JavaDoc uri) {
152         if (importedModuleNamespaces == null) {
153             importedModuleNamespaces = new HashSet(5);
154         }
155         importedModuleNamespaces.add(uri);
156     }
157
158     /**
159      * Test whether this module imports a particular namespace
160      */

161
162     public boolean importsNamespace(String JavaDoc uri) {
163         return importedModuleNamespaces != null &&
164                 importedModuleNamespaces.contains(uri);
165     }
166
167     /**
168      * Get an iterator over all the module namespaces that this module imports
169      */

170
171     public Iterator iterateImportedNamespaces() {
172         if (importedModuleNamespaces == null) {
173             return Collections.EMPTY_LIST.iterator();
174         }
175         return importedModuleNamespaces.iterator();
176     }
177
178     /**
179      * Make a copy of this StaticQueryContext. The StaticQueryContext that is constructed by a user
180      * application and passed to Saxon when a query is compiled should not be modified by the query
181      * compiler. Saxon therefore makes a copy of the StaticQueryContext and uses this copy internally,
182      * to capture any changes to the StaticQueryContext defined in the query prolog.
183      *
184      * @return a copy of this StaticQueryContext
185      */

186
187     public StaticQueryContext copy() {
188         StaticQueryContext n = new StaticQueryContext();
189         n.config = config;
190         n.namePool = namePool;
191         n.passiveNamespaces = new HashMap(passiveNamespaces);
192         n.explicitPrologNamespaces = new HashSet(explicitPrologNamespaces);
193         n.activeNamespaces = new Stack();
194         n.inheritNamespaces = inheritNamespaces;
195         n.preserveNamespaces = preserveNamespaces;
196         n.collations = new HashMap(collations);
197         n.variables = new HashMap(variables);
198         n.variableList = new ArrayList(variableList);
199         n.importedSchemata = new HashSet(importedSchemata);
200         n.defaultCollationName = defaultCollationName;
201         n.defaultFunctionNamespace = defaultFunctionNamespace;
202         n.defaultElementNamespace = defaultElementNamespace;
203         n.locationURI = locationURI;
204         n.baseURI = baseURI;
205         n.stackFrameMap = stackFrameMap;
206         n.moduleNamespace = moduleNamespace;
207         n.moduleNamespaceURICode = moduleNamespaceURICode;
208         n.constructionMode = constructionMode;
209         n.executable = executable;
210         n.importer = importer;
211         n.functionLibraryList = (FunctionLibraryList)functionLibraryList.copy();
212         List list = n.functionLibraryList.getLibraryList();
213         for (int i = 0; i < list.size(); i++) {
214             if (list.get(i) instanceof XQueryFunctionLibrary) {
215                 n.functions = (XQueryFunctionLibrary)list.get(i);
216                 break;
217             }
218         }
219         return n;
220     }
221
222     /**
223      * Set the Configuration options
224      *
225      * @throws IllegalArgumentException if the configuration supplied is different from the existing
226      * configuration
227      * @since 8.4
228      * @deprecated This method serves no purpose, since it is not possible to change the configuration
229      * once the StaticQueryContext has been initialized.
230      */

231
232     public void setConfiguration(Configuration config) {
233         if (this.config != config) {
234             throw new IllegalArgumentException JavaDoc("Configuration cannot be changed dynamically");
235         }
236         this.config = config;
237     }
238
239     /**
240      * Get the Configuration options
241      *
242      * @since 8.4
243      */

244
245     public Configuration getConfiguration() {
246         return config;
247     }
248
249     /**
250      * Convenience method for building Saxon's internal representation of a source XML
251      * document. The document will be built using the default NamePool, which means that
252      * any process that uses it must also use the default NamePool.
253      *
254      * @param source Any javax.xml.transform.Source object representing the document against
255      * which queries will be executed. Note that a Saxon {@link net.sf.saxon.om.DocumentInfo DocumentInfo}
256      * (indeed any {@link net.sf.saxon.om.NodeInfo NodeInfo})
257      * can be used as a Source. To use a third-party DOM Document as a source, create an instance of
258      * {@link javax.xml.transform.dom.DOMSource DOMSource} to wrap it.
259      * <p>For additional control over the way in which the source document is processed,
260      * supply an {@link net.sf.saxon.AugmentedSource AugmentedSource} object and set appropriate options on the object.</p>
261      * @return the DocumentInfo representing the root node of the resulting document object.
262      * @since 8.4
263      */

264
265     public DocumentInfo buildDocument(Source JavaDoc source) throws XPathException {
266         // TODO: handle an AugmentedSource
267
Source JavaDoc s2 = config.getSourceResolver().resolveSource(source, config);
268         if (s2 != null) {
269             source = s2;
270         }
271         Stripper stripper = null;
272         if (config.isStripsAllWhiteSpace()) {
273             stripper = AllElementStripper.getInstance();
274             stripper.setStripAll();
275         }
276         try {
277             NodeInfo contextNode = Builder.build(source, stripper, config);
278             return contextNode.getDocumentRoot();
279         } catch (XPathException err) {
280             Throwable JavaDoc cause = err.getException();
281             if (cause != null && cause instanceof SAXParseException JavaDoc) {
282                 // This generally means the error was already reported.
283
// But if a RuntimeException occurs in Saxon during a callback from
284
// the Crimson parser, Crimson wraps this in a SAXParseException without
285
// reporting it further.
286
SAXParseException JavaDoc spe = (SAXParseException JavaDoc)cause;
287                 cause = spe.getException();
288                 if (cause instanceof RuntimeException JavaDoc) {
289                     try {
290                         config.getErrorListener().fatalError(err);
291                     } catch (TransformerException JavaDoc e) {
292                         //
293
}
294                 }
295             } else {
296                 while (err.getException() instanceof XPathException) {
297                     err = (XPathException)err.getException();
298                 }
299                 try {
300                     config.getErrorListener().fatalError(err);
301                 } catch (TransformerException JavaDoc e) {
302                     //
303
}
304             }
305             throw err;
306         }
307     }
308
309     /**
310      * Prepare an XQuery query for subsequent evaluation. The source text of the query
311      * is supplied as a String. The base URI of the query is taken from the static context,
312      * and defaults to the current working directory.
313      *
314      * @param query The XQuery query to be evaluated, supplied as a string.
315      * @return an XQueryExpression object representing the prepared expression
316      * @throws net.sf.saxon.trans.XPathException
317      * if the syntax of the expression is wrong,
318      * or if it references namespaces, variables, or functions that have not been declared,
319      * or contains other static errors.
320      * @since 8.4
321      */

322
323     public XQueryExpression compileQuery(String JavaDoc query) throws XPathException {
324         QueryParser qp = new QueryParser();
325         XQueryExpression queryExp = qp.makeXQueryExpression(query, copy(), config);
326         return queryExp;
327     }
328
329     /**
330      * Prepare an XQuery query for subsequent evaluation. The Query is supplied
331      * in the form of a Reader. The base URI of the query is taken from the static context,
332      * and defaults to the current working directory.
333      *
334      * @param source A Reader giving access to the text of the XQuery query to be compiled.
335      * @return an XPathExpression object representing the prepared expression.
336      * @throws net.sf.saxon.trans.XPathException
337      * if the syntax of the expression is wrong, or if it references namespaces,
338      * variables, or functions that have not been declared, or any other static error is reported.
339      * @throws java.io.IOException if a failure occurs reading the supplied input.
340      * @since 8.4
341      */

342
343     public XQueryExpression compileQuery(Reader JavaDoc source)
344             throws XPathException, IOException JavaDoc {
345         char[] buffer = new char[4096];
346         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(4096);
347         while (true) {
348             int n = source.read(buffer);
349             if (n > 0) {
350                 sb.append(buffer, 0, n);
351             } else {
352                 break;
353             }
354         }
355         return compileQuery(sb.toString());
356     }
357
358     /**
359      * Prepare an XQuery query for subsequent evaluation. The Query is supplied
360      * in the form of a InputStream, with an optional encoding. If the encoding is not specified,
361      * the query parser attempts to obtain the encoding by inspecting the input stream: it looks specifically
362      * for a byte order mark, and for the encoding option in the version declaration of an XQuery prolog.
363      * The encoding defaults to UTF-8.
364      * The base URI of the query is taken from the static context,
365      * and defaults to the current working directory.
366      *
367      * @param source An InputStream giving access to the text of the XQuery query to be compiled, as a stream
368      * of octets
369      * @param encoding The encoding used to translate characters to octets in the query source. The parameter
370      * may be null: in this case the query parser attempts to infer the encoding by inspecting the source,
371      * and if that fails, it assumes UTF-8 encoding
372      * @return an XPathExpression object representing the prepared expression.
373      * @throws net.sf.saxon.trans.XPathException
374      * if the syntax of the expression is wrong, or if it references namespaces,
375      * variables, or functions that have not been declared, or any other static error is reported.
376      * @throws java.io.IOException if a failure occurs reading the supplied input.
377      * @since 8.5
378      */

379
380     public XQueryExpression compileQuery(InputStream JavaDoc source, String JavaDoc encoding)
381             throws XPathException, IOException JavaDoc {
382         String JavaDoc query = QueryReader.readInputStream(source, encoding);
383         return compileQuery(query);
384     }
385
386     /**
387      * Get the Executable, an object representing the compiled query and its environment.
388      * <p/>
389      * This method is intended for internal use only.
390      *
391      * @return the Executable
392      */

393
394     public Executable getExecutable() {
395         return executable;
396     }
397
398     /**
399      * Set the executable.
400      * <p/>
401      * This method is intended for internal use only.
402      *
403      * @param executable the Executable
404      */

405
406     public void setExecutable(Executable executable) {
407         this.executable = executable;
408     }
409
410     /**
411      * Get the LocationMap, an data structure used to identify the location of compiled expressions within
412      * the query source text.
413      * <p/>
414      * This method is intended for internal use only.
415      *
416      * @return the LocationMap
417      */

418
419     public LocationMap getLocationMap() {
420         return executable.getLocationMap();
421     }
422
423     /**
424      * Declare a namespace whose prefix can be used in expressions. This is
425      * a passive namespace, it won't be copied into the result tree. Passive
426      * namespaces are never undeclared, and active namespaces override them.
427      *
428      * @param prefix The namespace prefix. Must not be null.
429      * @param uri The namespace URI. Must not be null.
430      * @param explicit This parameter is set to true when Saxon calls the method internally to
431      * define a namespace declared within the query prolog. It should normally be set to false
432      * in the case of a call from a user application.
433      * @since 8.4
434      */

435
436     public void declarePassiveNamespace(String JavaDoc prefix, String JavaDoc uri, boolean explicit) throws StaticError {
437         if (prefix == null) {
438             throw new NullPointerException JavaDoc("Null prefix supplied to declarePassiveNamespace()");
439         }
440         if (uri == null) {
441             throw new NullPointerException JavaDoc("Null namespace URI supplied to declarePassiveNamespace()");
442         }
443         if (explicit) {
444             if (explicitPrologNamespaces.contains(prefix)) {
445                 StaticError err = new StaticError("Duplicate declaration of namespace prefix \"" + prefix + '"');
446                 err.setErrorCode("XQST0033");
447                 throw err;
448             }
449             explicitPrologNamespaces.add(prefix);
450         }
451         passiveNamespaces.put(prefix, uri);
452         namePool.allocateNamespaceCode(prefix, uri);
453     }
454
455     /**
456      * Declare an active namespace, that is, a namespace which as well as affecting the static
457      * context of the query, will also be copied to the result tree when element constructors
458      * are evaluated. When searching for a prefix-URI binding, active namespaces are searched
459      * first, then passive namespaces. Active namespaces may be undeclared (in reverse sequence)
460      * using {@link #undeclareNamespace()}.
461      * <p/>
462      * This method is intended for internal use only.
463      */

464
465     public void declareActiveNamespace(String JavaDoc prefix, String JavaDoc uri) {
466         if (prefix == null) {
467             throw new NullPointerException JavaDoc("Null prefix supplied to declareActiveNamespace()");
468         }
469         if (uri == null) {
470             throw new NullPointerException JavaDoc("Null namespace URI supplied to declareActiveNamespace()");
471         }
472
473         int nscode = namePool.allocateNamespaceCode(prefix, uri);
474         ActiveNamespace entry = new ActiveNamespace();
475         entry.prefix = prefix;
476         entry.uri = uri;
477         entry.code = nscode;
478         activeNamespaces.push(entry);
479
480         if (prefix.equals("")) {
481             defaultElementNamespace = (short)(nscode & 0xffff);
482         }
483
484     }
485
486     /**
487      * Undeclare the most recently-declared active namespace. This method is called
488      * when a namespace declaration goes out of scope (while processing an element end tag).
489      * It is NOT called when an XML 1.1-style namespace undeclaration is encountered.
490      * <p/>
491      * This method is intended for internal use only.
492      *
493      * @see #declareActiveNamespace(String, String)
494      */

495
496     public void undeclareNamespace() {
497         ActiveNamespace entry = (ActiveNamespace)activeNamespaces.pop();
498         if (entry.prefix.equals("")) {
499             for (int i = activeNamespaces.size() - 1; i >= 0; i--) {
500                 if (((ActiveNamespace)activeNamespaces.get(i)).prefix.equals("")) {
501                     defaultElementNamespace = (short)(((ActiveNamespace)activeNamespaces.get(i)).code & 0xffff);
502                     return;
503                 }
504             }
505             String JavaDoc defaultNS = (String JavaDoc)passiveNamespaces.get("");
506             if ("".equals(defaultNS)) {
507                 defaultElementNamespace = NamespaceConstant.NULL_CODE;
508             } else {
509                 defaultElementNamespace = getNamePool().getCodeForURI(defaultNS);
510             }
511         }
512     }
513
514     /**
515      * Clear all the declared passive namespaces, except for the standard ones (xml, saxon, etc)
516      *
517      * @since 8.4
518      */

519
520     public void clearPassiveNamespaces() {
521         try {
522             if (passiveNamespaces != null) {
523                 passiveNamespaces.clear();
524                 declarePassiveNamespace("xml", NamespaceConstant.XML, false);
525                 declarePassiveNamespace("saxon", NamespaceConstant.SAXON, false);
526                 declarePassiveNamespace("xs", NamespaceConstant.SCHEMA, false);
527                 declarePassiveNamespace("fn", NamespaceConstant.FN, false);
528                 declarePassiveNamespace("xdt", NamespaceConstant.XDT, false);
529                 declarePassiveNamespace("xsi", NamespaceConstant.SCHEMA_INSTANCE, false);
530                 declarePassiveNamespace("local", NamespaceConstant.LOCAL, false);
531                 declarePassiveNamespace("", "", false);
532             }
533         } catch (StaticError staticError) {
534 // can't happen when third argument is "false"
535
throw new IllegalStateException JavaDoc("Internal Failure initializing namespace declarations");
536         }
537     }
538
539     /**
540      * Get the URI for a prefix.
541      * This method is used by the XQuery parser to resolve namespace prefixes.
542      * <p/>
543      * This method is intended primarily for internal use.
544      *
545      * @param prefix The prefix
546      * @return the corresponding namespace URI
547      * @throws net.sf.saxon.trans.XPathException
548      * if the prefix has not been declared
549      */

550
551     public String JavaDoc getURIForPrefix(String JavaDoc prefix) throws XPathException {
552         String JavaDoc uri = checkURIForPrefix(prefix);
553         if (uri == null) {
554             throw new StaticError("Prefix " + prefix + " has not been declared");
555         }
556         return uri;
557     }
558
559     /**
560      * Get the URI for a prefix if there is one, return null if not.
561      * This method is used by the XQuery parser to resolve namespace prefixes.
562      * <p/>
563      * This method is intended primarily for internal use.
564      *
565      * @param prefix The prefix. Supply "" to obtain the default namespace.
566      * @return the corresponding namespace URI, or null if the prefix has not
567      * been declared. If the prefix is "" and the default namespace is the non-namespace,
568      * return "".
569      */

570
571     public String JavaDoc checkURIForPrefix(String JavaDoc prefix) {
572         // Search the active namespaces first, then the passive ones.
573
for (int i = activeNamespaces.size() - 1; i >= 0; i--) {
574             if (((ActiveNamespace)activeNamespaces.get(i)).prefix.equals(prefix)) {
575                 return ((ActiveNamespace)activeNamespaces.get(i)).uri;
576             }
577         }
578         return (String JavaDoc)passiveNamespaces.get(prefix);
579     }
580
581     /**
582      * Get an array containing the namespace codes of all active
583      * namespaces.
584      * <p/>
585      * This method is for internal use only.
586      */

587
588     public int[] getActiveNamespaceCodes() {
589         int[] nscodes = new int[activeNamespaces.size()];
590         int used = 0;
591         HashSet prefixes = new HashSet(10);
592         for (int n = activeNamespaces.size() - 1; n >= 0; n--) {
593             ActiveNamespace an = (ActiveNamespace)activeNamespaces.get(n);
594             if (!prefixes.contains(an.prefix)) {
595                 prefixes.add(an.prefix);
596                 nscodes[used++] = an.code;
597             }
598         }
599         if (used < nscodes.length) {
600             int[] nscodes2 = new int[used];
601             System.arraycopy(nscodes, 0, nscodes2, 0, used);
602             nscodes = nscodes2;
603         }
604         return nscodes;
605     }
606
607     /**
608      * Get a copy of the Namespace Context. This method is used internally
609      * by the query parser when a construct is encountered that needs
610      * to save the namespace context for use at run-time.
611      * <p/>
612      * This method is for internal use only.
613      */

614
615     public NamespaceResolver getNamespaceResolver() {
616         int[] active = getActiveNamespaceCodes();
617         int[] nscodes = new int[passiveNamespaces.size() + active.length];
618
619         int used = 0;
620         for (Iterator iter = passiveNamespaces.keySet().iterator(); iter.hasNext();) {
621             String JavaDoc prefix = (String JavaDoc)iter.next();
622             String JavaDoc uri = (String JavaDoc)passiveNamespaces.get(prefix);
623             nscodes[used++] = namePool.getNamespaceCode(prefix, uri);
624             ;
625         }
626         for (int a = 0; a < active.length; a++) {
627             nscodes[used++] = active[a];
628         }
629
630         return new SavedNamespaceContext(nscodes, namePool);
631     }
632
633     /**
634      * Get the default function namespace
635      *
636      * @return the default function namespace (defaults to the fn: namespace)
637      * @since 8.4
638      */

639
640     public String JavaDoc getDefaultFunctionNamespace() {
641         return defaultFunctionNamespace;
642     }
643
644     /**
645      * Set the default function namespace
646      *
647      * @param defaultFunctionNamespace The namespace to be used for unprefixed function calls
648      * @since 8.4
649      */

650
651     public void setDefaultFunctionNamespace(String JavaDoc defaultFunctionNamespace) {
652         this.defaultFunctionNamespace = defaultFunctionNamespace;
653     }
654
655     /**
656      * Set the default element namespace
657      *
658      * @since 8.4
659      */

660
661     public void setDefaultElementNamespace(String JavaDoc uri) throws StaticError {
662         int nscode = namePool.allocateNamespaceCode("", uri);
663         defaultElementNamespace = (short)(nscode & 0xffff);
664         declarePassiveNamespace("", uri, true);
665     }
666
667     /**
668      * Get the default XPath namespace, as a namespace URI code that can be looked up in the NamePool
669      *
670      * @since 8.4
671      */

672
673     public short getDefaultElementNamespace() {
674         return defaultElementNamespace;
675     }
676
677     /**
678      * Set the namespace for a library module.
679      * <p/>
680      * This method is for internal use only.
681      */

682
683     public void setModuleNamespace(String JavaDoc uri) {
684         moduleNamespace = uri;
685         moduleNamespaceURICode = namePool.getCodeForURI(uri);
686     }
687
688     /**
689      * Get the namespace of the current library module.
690      * <p/>
691      * This method is intended primarily for internal use.
692      *
693      * @return the module namespace, or null if this is a main module
694      */

695
696     public String JavaDoc getModuleNamespace() {
697         return moduleNamespace;
698     }
699
700     /**
701      * Get the namesapce code of the current library module.
702      * <p/>
703      * This method is intended primarily for internal use.
704      *
705      * @return the module namespace, or null if this is a main module
706      */

707
708     public short getModuleNamespaceCode() {
709         return moduleNamespaceURICode;
710     }
711
712     /**
713      * Set the location URI for a module
714      */

715
716     public void setLocationURI(String JavaDoc uri) {
717         locationURI = uri;
718     }
719
720     /**
721      * Get the location URI for a module
722      */

723
724     public String JavaDoc getLocationURI() {
725         return locationURI;
726     }
727
728     /**
729      * Set the namespace inheritance mode
730      *
731      * @param inherit true if namespaces are inherited, false if not
732      * @since 8.4
733      */

734
735     public void setInheritNamespaces(boolean inherit) {
736         inheritNamespaces = inherit;
737     }
738
739     /**
740      * Get the namespace inheritance mode
741      *
742      * @return true if namespaces are inherited, false if not
743      * @since 8.4
744      */

745
746     public boolean isInheritNamespaces() {
747         return inheritNamespaces;
748     }
749
750     /**
751      * Set the namespace copy mode
752      *
753      * @param inherit true if namespaces are preserved, false if not
754      * @since 8.4
755      */

756
757     public void setPreserveNamespaces(boolean inherit) {
758         preserveNamespaces = inherit;
759     }
760
761     /**
762      * Get the namespace copy mode
763      *
764      * @return true if namespaces are preserved, false if not
765      * @since 8.4
766      */

767
768     public boolean isPreserveNamespaces() {
769         return preserveNamespaces;
770     }
771
772     /**
773      * Declare a named collation. Collations are only available in a query if this method
774      * has been called externally to declare the collation and associate it with an
775      * implementation, in the form of a Java Comparator. The default collation is the
776      * Unicode codepoint collation, unless otherwise specified.
777      *
778      * @param name The name of the collation (technically, a URI)
779      * @param comparator The Java Comparator used to implement the collating sequence
780      * @since 8.4
781      */

782
783     public void declareCollation(String JavaDoc name, Comparator comparator) {
784         collations.put(name, comparator);
785     }
786
787     /**
788      * Set the default collation. The collation that is specified must be one that has
789      * been previously registered using the declareCollation() method.
790      *
791      * @param name The collation name
792      * @throws XPathException if the collation name has not been registered
793      * @since 8.4
794      */

795
796     public void declareDefaultCollation(String JavaDoc name) throws XPathException {
797         Comparator c = getCollation(name);
798         if (c == null) {
799             throw new StaticError("Collation " + name + " is not recognized");
800         }
801         defaultCollationName = name;
802     }
803
804     /**
805      * Get a named collation.
806      *
807      * @return the collation identified by the given name, as set previously using declareCollation.
808      * Return null if no collation with this name is found.
809      * @since 8.4
810      */

811
812     public Comparator getCollation(String JavaDoc name) {
813         Comparator c = (Comparator)collations.get(name);
814         if (c != null) {
815             return c;
816         }
817         return config.getCollationURIResolver().resolve(name, getBaseURI(), config);
818         //return CollationFactory.makeCollationFromURI(name, config);
819
}
820
821     /**
822      * Get the name of the default collation.
823      *
824      * @return the name of the default collation; or the name of the codepoint collation
825      * if no default collation has been defined
826      * @since 8.4
827      */

828
829     public String JavaDoc getDefaultCollationName() {
830         if (defaultCollationName != null) {
831             return defaultCollationName;
832         } else {
833             return NamespaceConstant.CODEPOINT_COLLATION_URI;
834         }
835     }
836
837     /**
838      * Get a HashMap that maps all registered collations to Comparators.
839      * Note that this returns a snapshot copy of the data held by the static context.
840      * This method is provided for internal use by the query processor.
841      * <p/>
842      * This method is intended for internal use.
843      */

844
845     public HashMap getAllCollations() {
846         return new HashMap(collations);
847     }
848
849     /**
850      * Get the stack frame map for global variables.
851      * <p/>
852      * This method is intended for internal use.
853      */

854
855     public SlotManager getGlobalStackFrameMap() {
856         return executable.getGlobalVariableMap();
857     }
858
859     /**
860      * Declare a global variable. A variable must be declared before an expression referring
861      * to it is compiled. Global variables are normally declared in the Query Prolog, but
862      * they can also be predeclared using this API.
863      *
864      * @since 8.4
865      */

866
867     public void declareVariable(VariableDeclaration var) throws StaticError {
868         int key = var.getNameCode() & NamePool.FP_MASK;
869         Integer JavaDoc keyObj = new Integer JavaDoc(key);
870         if (variables.get(keyObj) != null) {
871             GlobalVariableDefinition old = (GlobalVariableDefinition)variables.get(keyObj);
872             if (old instanceof UndeclaredVariable) {
873                 // We've already encountered references to this variable, and created an UndeclaredVariable
874
// object to hold the references for later fixup. Forwards references are not allowed within
875
// a single module (for some bizarre reason...) but can arise as a result of recursive module
876
// imports.
877
UndeclaredVariable u = (UndeclaredVariable)old;
878                 if (((GlobalVariableDefinition)var).getSystemId().equals(u.getSystemId())) {
879                     StaticError err = new StaticError("Forwards reference to global variable " + var.getVariableName());
880                     err.setErrorCode("XPST0008");
881                     throw err;
882                 }
883                 u.transferReferences(var);
884                 variableList.remove(old);
885             } else if (old == var) {
886                 // do nothing
887
} else {
888                 StaticError err = new StaticError("Duplicate definition of global variable "
889                         + var.getVariableName()
890                         + " (see line " + old.getLineNumber() + " in module " + old.getSystemId() + ')');
891                 err.setErrorCode("XQST0049");
892                 if (var instanceof GlobalVariableDefinition) {
893                     ExpressionLocation loc = new ExpressionLocation();
894                     loc.setLineNumber(((GlobalVariableDefinition)var).getLineNumber());
895                     loc.setSystemId(((GlobalVariableDefinition)var).getSystemId());
896                     err.setLocator(loc);
897                 }
898                 throw err;
899             }
900         }
901         variables.put(keyObj, var);
902         variableList.add(var);
903 // if (var instanceof GlobalVariableDefinition) {
904
// ((GlobalVariableDefinition)var).setSystemId(getBaseURI());
905
// }
906
}
907
908     /**
909      * Fixup all references to global variables.
910      * <p/>
911      * This method is for internal use by the Query Parser only.
912      */

913
914     public List fixupGlobalVariables(SlotManager globalVariableMap) throws StaticError {
915         List compiledVars = new ArrayList(20);
916         Iterator iter = variableList.iterator();
917         while (iter.hasNext()) {
918             GlobalVariableDefinition var = (GlobalVariableDefinition)iter.next();
919             if (var instanceof UndeclaredVariable) {
920                 Iterator refs = var.iterateReferences();
921                 while (refs.hasNext()) {
922                     VariableReference ref = (VariableReference)refs.next();
923                     StaticError err = new StaticError("Unresolved reference to variable " + var.getVariableName());
924                     err.setLocator(ref);
925                     err.setErrorCode("XPST0008");
926                     throw err;
927                     // TODO: report more than one error
928
}
929                 // Note: not an error if there are no references
930
} else {
931                 try {
932                     int slot = globalVariableMap.allocateSlotNumber(var.getNameCode() & NamePool.FP_MASK);
933                     GlobalVariable gv = var.compile(this, slot);
934                     compiledVars.add(gv);
935                 } catch (XPathException err) {
936                     throw StaticError.makeStaticError(err);
937                 }
938             }
939         }
940         return compiledVars;
941     }
942
943     public void typeCheckGlobalVariables(List compiledVars) throws StaticError {
944         try {
945             Iterator iter = compiledVars.iterator();
946             Stack stack = new Stack();
947             while (iter.hasNext()) {
948                 GlobalVariable gv = (GlobalVariable)iter.next();
949                 gv.lookForCycles(stack);
950                 GlobalVariableDefinition.typeCheck(this, gv);
951             }
952         } catch (XPathException e) {
953             throw StaticError.makeStaticError(e);
954         }
955     }
956
957     /**
958      * Produce "explain" output for all global variables.
959      * <p/>
960      * This method is intended primarily for internal use.
961      */

962
963     public void explainGlobalVariables() {
964         Iterator iter = variableList.iterator();
965         while (iter.hasNext()) {
966             GlobalVariableDefinition var = (GlobalVariableDefinition)iter.next();
967             var.explain(getNamePool());
968         }
969     }
970
971     /**
972      * Get an iterator over the variables defined in this module.
973      * <p/>
974      * This method is intended primarily for internal use.
975      *
976      * @return an Iterator, whose items are VariableDeclaration objects. It returns
977      * all variables known to this module including those imported from elsewhere; they
978      * can be distinguished by their namespace. The variables are returned in order of
979      * declaration.
980      */

981
982     public Iterator getVariableDeclarations() {
983         return variableList.iterator();
984     }
985
986     /**
987      * Get the stack frame map for local variables in the "main" query expression.
988      * <p/>
989      * This method is intended for internal use only.
990      */

991
992     public SlotManager getStackFrameMap() {
993         if (stackFrameMap == null) {
994             stackFrameMap = getConfiguration().makeSlotManager();
995         }
996         return stackFrameMap;
997     }
998
999     /**
1000     * Get the NamePool used for compiling expressions
1001     *
1002     * @since 8.4
1003     */

1004
1005    public NamePool getNamePool() {
1006        return namePool;
1007    }
1008
1009    /**
1010     * Issue a compile-time warning. This method is used during XQuery expression compilation to
1011     * output warning conditions.
1012     * <p/>
1013     * This method is intended for internal use only.
1014     */

1015
1016    public void issueWarning(String JavaDoc s, SourceLocator JavaDoc locator) {
1017        StaticError err = new StaticError(s);
1018        err.setLocator(locator);
1019        try {
1020            config.getErrorListener().warning(err);
1021        } catch (TransformerException JavaDoc e) {
1022            // ignore any error thrown
1023
}
1024    }
1025
1026    /**
1027     * Set the Base URI of the query
1028     *
1029     * @since 8.4
1030     */

1031
1032    public void setBaseURI(String JavaDoc baseURI) {
1033        this.baseURI = baseURI;
1034    }
1035
1036    /**
1037     * Get the system ID of the container of the expression. Used to construct error messages.
1038     * Note that the systemID and the Base URI are currently identical, but they might be distinguished
1039     * in the future.
1040     *
1041     * @return the Base URI
1042     * @since 8.4
1043     */

1044
1045    public String JavaDoc getSystemId() {
1046        return baseURI;
1047    }
1048
1049    /**
1050     * Get the Base URI of the query, for resolving any relative URI's used
1051     * in the expression.
1052     * Note that the systemID and the Base URI are currently identical, but they might be distinguished
1053     * in the future.
1054     * Used by the document() function.
1055     *
1056     * @return the base URI of the query
1057     * @since 8.4
1058     */

1059
1060    public String JavaDoc getBaseURI() {
1061        return baseURI;
1062    }
1063
1064    /**
1065     * Get the line number of the expression within that container.
1066     * Used to construct error messages. This method is provided to satisfy the StaticContext interface,
1067     * but the value is meaningful only for XPath expressions within a document such as a stylesheet.
1068     *
1069     * @return -1 always
1070     */

1071
1072    public int getLineNumber() {
1073        return -1;
1074    }
1075
1076
1077    /**
1078     * Bind a variable used in a query to the expression in which it is declared.
1079     * <p/>
1080     * This method is provided for use by the XQuery parser, and it should not be called by the user of
1081     * the API, or overridden, unless variables are to be declared using a mechanism other than the
1082     * declareVariable method of this class.
1083     */

1084
1085    public VariableDeclaration bindVariable(int fingerprint) throws StaticError {
1086
1087        VariableDeclaration var = (VariableDeclaration)variables.get(new Integer JavaDoc(fingerprint));
1088        if (var == null) {
1089            UndeclaredVariable uvar = new UndeclaredVariable();
1090            uvar.setSystemId(getLocationURI());
1091            uvar.setLineNumber(getLineNumber());
1092            uvar.setNameCode(fingerprint);
1093            uvar.setVariableName(getNamePool().getDisplayName(fingerprint));
1094            declareVariable(uvar);
1095            return uvar;
1096        }
1097        return var;
1098    }
1099
1100    /**
1101     * Set the function library used for binding any function call appearing within the query module.
1102     * <p/>
1103     * This method is available for use by advanced applications. The details of the FunctionLibrary
1104     * interface are subject to change. Applications using this interface take responsibility for
1105     * ensuring that the results conform to the constraints imposed by the XQuery language specification,
1106     * for example that one function within a query module can call other functions defined in the same
1107     * query module.
1108     *
1109     * @param functionLibrary the FunctionLibrary to be used. This will typically be a
1110     * FunctionLibraryList; in most cases it will be a slightly modified copy of a FunctionLibraryList
1111     * constructed by the system and obtained using the {@link #getFunctionLibrary} method.
1112     * @see FunctionLibraryList
1113     */

1114
1115    public void setFunctionLibraryList(FunctionLibraryList functionLibrary) {
1116        this.functionLibraryList = functionLibrary;
1117    }
1118
1119    /**
1120     * Get the function library containing all the in-scope functions available in this static
1121     * context (that is, the functions available in this query module).
1122     * <p/>
1123     * This method is provided for use by advanced applications.
1124     * The details of the interface are subject to change.
1125     *
1126     * @return the FunctionLibrary used. For XQuery, this will always be a FunctionLibraryList.
1127     * @see FunctionLibraryList
1128     */

1129
1130    public FunctionLibrary getFunctionLibrary() {
1131        return functionLibraryList;
1132    }
1133
1134    /**
1135     * Register a user-defined XQuery function.
1136     * <p/>
1137     * This method is intended for internal use only.
1138     */

1139
1140    public void declareFunction(XQueryFunction function) throws StaticError {
1141        if (function.getNumberOfArguments() == 1) {
1142            SchemaType t = config.getSchemaType(function.getNameCode() & NamePool.FP_MASK);
1143            if (t != null && t instanceof AtomicType) {
1144                StaticError err = new StaticError("Function name " + function.getFunctionDisplayName(getNamePool()) +
1145                        " clashes with the name of the constructor function for an atomic type");
1146                err.setErrorCode("XQST0034");
1147                throw err;
1148            }
1149        }
1150        functions.declareFunction(function);
1151    }
1152
1153    /**
1154     * Bind function calls that could not be bound when first encountered. These
1155     * will either be forwards references to functions declared later in the same query module,
1156     * or in modules that are being imported recursively, or errors.
1157     * <p/>
1158     * This method is for internal use only.
1159     *
1160     * @throws net.sf.saxon.trans.StaticError if a function call refers to a function that has
1161     * not been declared
1162     */

1163
1164    public void bindUnboundFunctionCalls() throws StaticError {
1165        functions.bindUnboundFunctionCalls();
1166    }
1167
1168    /**
1169     * Get an iterator over the Functions defined in this module.
1170     * <p/>
1171     * This method is intended primarily for internal use.
1172     *
1173     * @return an Iterator, whose items are {@link XQueryFunction} objects. It returns
1174     * all function known to this module including those imported from elsewhere; they
1175     * can be distinguished by their namespace.
1176     */

1177
1178    public Iterator getFunctionDefinitions() {
1179        return functions.getFunctionDefinitions();
1180    }
1181
1182    /**
1183     * Fixup all references to global functions. This method is called
1184     * on completion of query parsing. Each XQueryFunction is required to
1185     * bind all references to that function to the object representing the run-time
1186     * executable code of the function.
1187     * <p/>
1188     * This method is for internal use only.
1189     */

1190
1191    public void fixupGlobalFunctions() throws XPathException {
1192        functions.fixupGlobalFunctions(this);
1193    }
1194
1195    /**
1196     * Output "explain" information about each declared function.
1197     * <p/>
1198     * This method is intended primarily for internal use.
1199     */

1200
1201    public void explainGlobalFunctions() throws XPathException {
1202        functions.explainGlobalFunctions();
1203    }
1204
1205    /**
1206     * Get the function with a given name and arity. This method is provided so that XQuery functions
1207     * can be called directly from a Java application. Note that there is no type checking or conversion
1208     * of arguments when this is done: the arguments must be provided in exactly the form that the function
1209     * signature declares them.
1210     *
1211     * @param uri the uri of the function name
1212     * @param localName the local part of the function name
1213     * @param arity the number of arguments.
1214     * @since 8.4
1215     */

1216
1217    public UserFunction getUserDefinedFunction(String JavaDoc uri, String JavaDoc localName, int arity) {
1218        return functions.getUserDefinedFunction(uri, localName, arity);
1219    }
1220
1221    /**
1222     * Determine whether Backwards Compatible Mode is used
1223     *
1224     * @return false; XPath 1.0 compatibility mode is not supported in XQuery
1225     * @since 8.4
1226     */

1227
1228    public boolean isInBackwardsCompatibleMode() {
1229        return false;
1230    }
1231
1232    /**
1233     * Add an imported schema to this static context. A query module can reference
1234     * types in a schema provided two conditions are satisfied: the schema containing those
1235     * types has been loaded into the Configuration, and the target namespace has been imported
1236     * by this query module. This method achieves the second of these conditions. It does not
1237     * cause the schema to be loaded.
1238     * <p/>
1239     *
1240     * @param targetNamespace The target namespace of the schema to be added
1241     * @since 8.4
1242     */

1243
1244    public void addImportedSchema(String JavaDoc targetNamespace) {
1245        if (importedSchemata == null) {
1246            importedSchemata = new HashSet(5);
1247        }
1248        importedSchemata.add(targetNamespace);
1249    }
1250
1251    /**
1252     * Get the schema for a given namespace, if it has been imported
1253     *
1254     * @param namespace The namespace of the required schema. Supply "" for
1255     * a no-namespace schema.
1256     * @return The schema if found, or null if not found.
1257     * @since 8.4
1258     */

1259
1260    public boolean isImportedSchema(String JavaDoc namespace) {
1261        if (importedSchemata == null) {
1262            return false;
1263        }
1264        return importedSchemata.contains(namespace);
1265    }
1266
1267    /**
1268     * Determine whether a built-in type is available in this context. This method caters for differences
1269     * between host languages as to which set of types are built in.
1270     *
1271     * @param type the supposedly built-in type. This will always be a type in the
1272     * XS or XDT namespace.
1273     * @return true if this type can be used in this static context
1274     */

1275
1276    public boolean isAllowedBuiltInType(AtomicType type) {
1277        return true;
1278    }
1279
1280    /**
1281     * Set the construction mode for this module
1282     *
1283     * @param mode one of {@link Validation#STRIP}, {@link Validation#PRESERVE}
1284     * @since 8.4
1285     */

1286
1287    public void setConstructionMode(int mode) {
1288        constructionMode = mode;
1289    }
1290
1291    /**
1292     * Get the current validation mode
1293     *
1294     * @return one of {@link Validation#STRIP}, {@link Validation#PRESERVE}
1295     * @since 8.4
1296     */

1297
1298    public int getConstructionMode() {
1299        return constructionMode;
1300    }
1301
1302    /**
1303     * Supporting method to load a query module. Used also by saxon:import-query in XSLT.
1304     * <p/>
1305     * This method is intended for internal use only.
1306     *
1307     * @param baseURI The base URI and location URI of the module
1308     * @param executable The Executable
1309     * @param importer The importing query module (used to check for cycles). This is null
1310     * when loading a query module from XSLT.
1311     * @param query The text of the query, after decoding and normalizing line endings
1312     * @param namespaceURI namespace of the query module to be loaded
1313     * @return The StaticQueryContext representing the loaded query module
1314     * @throws net.sf.saxon.trans.StaticError
1315     */

1316
1317    public static StaticQueryContext makeStaticQueryContext(
1318            String JavaDoc baseURI, Executable executable, StaticQueryContext importer,
1319            String JavaDoc query, String JavaDoc namespaceURI) throws StaticError {
1320        Configuration config = executable.getConfiguration();
1321        StaticQueryContext module = new StaticQueryContext(config);
1322        module.setLocationURI(baseURI);
1323        module.setBaseURI(baseURI);
1324        module.setModuleNamespace(namespaceURI);
1325        module.setExecutable(executable);
1326        module.importer = importer;
1327        executable.addQueryLibraryModule(module);
1328        QueryParser qp = new QueryParser();
1329        qp.parseLibraryModule(query, module);
1330        if (module.getModuleNamespace() == null) {
1331            throw new StaticError("Imported module must be a library module");
1332        }
1333        if (!module.getModuleNamespace().equals(namespaceURI)) {
1334            throw new StaticError("Imported module's namespace does not match requested namespace");
1335        }
1336
1337        return module;
1338    }
1339
1340    /**
1341     * Inner class containing information about an active namespace entry
1342     */

1343
1344    private static class ActiveNamespace {
1345        public String JavaDoc prefix;
1346        public String JavaDoc uri;
1347        public int code;
1348    }
1349
1350}
1351
1352//
1353
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1354
// you may not use this file except in compliance with the License. You may obtain a copy of the
1355
// License at http://www.mozilla.org/MPL/
1356
//
1357
// Software distributed under the License is distributed on an "AS IS" basis,
1358
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1359
// See the License for the specific language governing rights and limitations under the License.
1360
//
1361
// The Original Code is: all this file.
1362
//
1363
// The Initial Developer of the Original Code is Michael H. Kay.
1364
//
1365
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1366
//
1367
// Contributor(s): none.
1368
//
1369
Popular Tags