KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > xpath > StandaloneContext


1 package net.sf.saxon.xpath;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.expr.StaticContext;
4 import net.sf.saxon.expr.VariableDeclaration;
5 import net.sf.saxon.functions.ConstructorFunctionLibrary;
6 import net.sf.saxon.functions.FunctionLibrary;
7 import net.sf.saxon.functions.FunctionLibraryList;
8 import net.sf.saxon.functions.SystemFunctionLibrary;
9 import net.sf.saxon.instruct.LocationMap;
10 import net.sf.saxon.instruct.SlotManager;
11 import net.sf.saxon.om.*;
12 import net.sf.saxon.trans.StaticError;
13 import net.sf.saxon.trans.Variable;
14 import net.sf.saxon.trans.XPathException;
15 import net.sf.saxon.type.AtomicType;
16 import net.sf.saxon.value.QNameValue;
17
18 import javax.xml.namespace.NamespaceContext JavaDoc;
19 import javax.xml.transform.SourceLocator JavaDoc;
20 import javax.xml.xpath.XPathFunctionResolver JavaDoc;
21 import javax.xml.xpath.XPathVariableResolver JavaDoc;
22 import java.util.Comparator JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25
26 /**
27 * A StandaloneContext provides a context for parsing an XPath expression
28 * in a context other than a stylesheet. In particular, it is used to support
29 * the JAXP 1.3 XPath API. This API does not actually expose the StaticContext
30 * object directly; rather, the static context (namespaces, variables, and functions)
31  * is manipulated through the XPath object, implemented in Saxon by the {@link XPathEvaluator}
32 */

33
34 public class StandaloneContext implements StaticContext, NamespaceResolver {
35
36     private NamePool namePool;
37     private HashMap JavaDoc namespaces = new HashMap JavaDoc(10);
38     private HashMap JavaDoc collations = new HashMap JavaDoc(10);
39     private HashMap JavaDoc variables = new HashMap JavaDoc(20);
40     private SlotManager stackFrameMap;
41     private String JavaDoc defaultCollationName = null;
42     private String JavaDoc baseURI = null;
43     private Configuration config;
44     private LocationMap locationMap = new LocationMap();
45     private FunctionLibrary functionLibrary;
46     private XPathFunctionLibrary xpathFunctionLibrary;
47     private String JavaDoc defaultFunctionNamespace = NamespaceConstant.FN;
48     private short defaultElementNamespace = NamespaceConstant.NULL_CODE;
49     private boolean backwardsCompatible = false;
50
51     private NamespaceContext JavaDoc namespaceContext;
52     private XPathVariableResolver JavaDoc variableResolver;
53
54     /**
55     * Create a StandaloneContext using the default Configuration and NamePool
56     */

57
58     public StandaloneContext() {
59         this(new Configuration());
60     }
61
62     /**
63     * Create a StandaloneContext using a specific NamePool
64     */

65
66     public StandaloneContext(Configuration config) {
67         this.config = config;
68         namePool = config.getNamePool();
69         stackFrameMap = config.makeSlotManager();
70         clearNamespaces();
71
72         // Set up a default function library. This can be overridden using setFunctionLibrary()
73

74         FunctionLibraryList lib = new FunctionLibraryList();
75         lib.addFunctionLibrary(new SystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY));
76         lib.addFunctionLibrary(getConfiguration().getVendorFunctionLibrary());
77         lib.addFunctionLibrary(new ConstructorFunctionLibrary(getConfiguration()));
78         if (config.isAllowExternalFunctions()) {
79             xpathFunctionLibrary = new XPathFunctionLibrary();
80             lib.addFunctionLibrary(xpathFunctionLibrary);
81             lib.addFunctionLibrary(config.getExtensionBinder());
82         }
83         functionLibrary = lib;
84     }
85
86     /**
87     * Create a StandaloneContext using a specific Node. This node is used to initialize
88     * the NamePool and also to establish the initial set of in-scope namespaces
89     */

90
91     public StandaloneContext(NodeInfo node) {
92         DocumentInfo doc = node.getDocumentRoot();
93         if (doc==null) {
94             throw new IllegalArgumentException JavaDoc(
95                         "The node used to establish a standalone context must be in a tree whose root is a document node");
96         }
97         namePool = doc.getNamePool();
98         setNamespaces(node);
99     }
100
101     /**
102      * Get the system configuration
103      */

104
105     public Configuration getConfiguration() {
106         return config;
107     }
108
109     public LocationMap getLocationMap() {
110         return locationMap;
111     }
112
113     public void setLocationMap(LocationMap locationMap) {
114         this.locationMap = locationMap;
115     }
116
117     /**
118     * Declare a namespace whose prefix can be used in expressions. Namespaces may either be
119      * pre-declared (the traditional Saxon interface), or they may be resolved on demand
120      * using a supplied NamespaceContext. When a prefix has to be resolved, the parser looks
121      * first in the pre-declared namespaces, then in the supplied NamespaceContext object.
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 JavaDoc prefix, String JavaDoc uri) {
128         if (prefix==null) {
129             throw new NullPointerException JavaDoc("Null prefix supplied to declareNamespace()");
130         }
131         if (uri==null) {
132             throw new NullPointerException JavaDoc("Null namespace URI supplied to declareNamespace()");
133         }
134         namespaces.put(prefix, uri);
135         namePool.allocateNamespaceCode(prefix, uri);
136     }
137
138     /**
139      * Supply the NamespaceContext used to resolve namespaces. This supplements namespaces
140      * that have been explicitly declared using {@link #declareNamespace} or
141      * that have been implicitly declared using {@link #setNamespaces(net.sf.saxon.om.NodeInfo)}
142      */

143
144     public void setNamespaceContext(NamespaceContext JavaDoc context) {
145         this.namespaceContext = context;
146     }
147
148     /**
149      * Get the NamespaceContext that was set using {@link #setNamespaceContext}
150      */

151
152     public NamespaceContext JavaDoc getNamespaceContext() {
153         return namespaceContext;
154     }
155
156     /**
157     * Clear all the declared namespaces, except for the standard ones (xml, xslt, saxon, xdt).
158      * This doesn't clear the namespace context set using {@link #setNamespaceContext}
159     */

160
161     public void clearNamespaces() {
162         namespaces.clear();
163         declareNamespace("xml", NamespaceConstant.XML);
164         declareNamespace("xsl", NamespaceConstant.XSLT);
165         declareNamespace("saxon", NamespaceConstant.SAXON);
166         declareNamespace("xs", NamespaceConstant.SCHEMA);
167         declareNamespace("xdt", NamespaceConstant.XDT);
168         declareNamespace("", "");
169     }
170
171     /**
172     * Clear all the declared namespaces, including the standard ones (xml, xslt, saxon).
173      * Leave only the XML namespace and the default namespace (xmlns="")
174     */

175
176     public void clearAllNamespaces() {
177         namespaces.clear();
178         declareNamespace("xml", NamespaceConstant.XML);
179         declareNamespace("", "");
180     }
181
182     /**
183     * Set all the declared namespaces to be the namespaces that are in-scope for a given node.
184     * In addition, the standard namespaces (xml, xslt, saxon) are declared.
185     * @param node The node whose in-scope namespaces are to be used as the context namespaces.
186     * Note that this will have no effect unless this node is an element.
187     */

188
189     public void setNamespaces(NodeInfo node) {
190         namespaces.clear();
191         AxisIterator iter = node.iterateAxis(Axis.NAMESPACE);
192         while (true) {
193             NodeInfo ns = (NodeInfo)iter.next();
194             if (ns == null) {
195                 return;
196             }
197             declareNamespace(ns.getLocalPart(), ns.getStringValue());
198         }
199     }
200
201     /**
202      * Set the base URI in the static context
203      */

204
205     public void setBaseURI(String JavaDoc baseURI) {
206         this.baseURI = baseURI;
207     }
208
209     /**
210     * Declare a named collation
211     * @param name The name of the collation (technically, a URI)
212     * @param comparator The Java Comparator used to implement the collating sequence
213     * @param isDefault True if this is to be used as the default collation
214     */

215
216     public void declareCollation(String JavaDoc name, Comparator JavaDoc comparator, boolean isDefault) {
217         collations.put(name, comparator);
218         if (isDefault) {
219             defaultCollationName = name;
220         }
221     }
222
223     /**
224      * Get the stack frame map containing the slot number allocations for the variables declared
225      * in this static context
226      */

227
228     public SlotManager getStackFrameMap() {
229         return stackFrameMap;
230     }
231
232     /**
233     * Declare a variable. A variable may be declared before an expression referring
234     * to it is compiled. Alternatively, a JAXP XPathVariableResolver may be supplied
235      * to perform the resolution. A variable that has been explicitly declared is
236      * used in preference.
237      * @param qname Lexical QName identifying the variable. The namespace prefix, if
238      * any, must have been declared before this method is called, or must be resolvable
239      * using the namespace context.
240      * @param initialValue The initial value of the variable. A Java object that can
241      * be converted to an XPath value.
242     */

243
244     public Variable declareVariable(String JavaDoc qname, Object JavaDoc initialValue) throws XPathException {
245         String JavaDoc prefix;
246         String JavaDoc localName;
247         try {
248             String JavaDoc[] parts = Name.getQNameParts(qname);
249             prefix = parts[0];
250             localName = parts[1];
251         } catch (QNameException err) {
252             throw new StaticError("Invalid QName for variable: " + qname);
253         }
254         String JavaDoc uri = "";
255         if (!("".equals(prefix))) {
256             uri = getURIForPrefix(prefix);
257         }
258         QNameValue q = new QNameValue(prefix, uri, localName);
259         Variable var = Variable.make(q, getConfiguration());
260         if (initialValue instanceof ValueRepresentation) {
261             var.setXPathValue((ValueRepresentation)initialValue);
262         } else {
263             var.setValue(initialValue);
264         }
265         int fingerprint = namePool.allocate(prefix, uri, localName) & 0xfffff;
266         variables.put(new Integer JavaDoc(fingerprint), var);
267         stackFrameMap.allocateSlotNumber(fingerprint);
268         return var;
269     }
270
271     /**
272      * Set an XPathVariableResolver. This is used to resolve variable references
273      * if no variable has been explicitly declared.
274      * @param resolver A JAXP 1.3 XPathVariableResolver
275      */

276
277     public void setXPathVariableResolver(XPathVariableResolver JavaDoc resolver) {
278         this.variableResolver = resolver;
279     }
280
281     /**
282      * Get the XPathVariableResolver
283      */

284
285     public XPathVariableResolver JavaDoc getXPathVariableResolver() {
286         return variableResolver;
287     }
288
289     public void setXPathFunctionResolver(XPathFunctionResolver JavaDoc xPathFunctionResolver) {
290         if (xpathFunctionLibrary != null) {
291             xpathFunctionLibrary.setXPathFunctionResolver(xPathFunctionResolver);
292         }
293         // otherwise, external functions are disabled for security reasons
294
}
295
296     public XPathFunctionResolver JavaDoc getXPathFunctionResolver() {
297         if (xpathFunctionLibrary != null) {
298             return xpathFunctionLibrary.getXPathFunctionResolver();
299         } else {
300             return null;
301         }
302     }
303
304     /**
305     * Get the NamePool used for compiling expressions
306     */

307
308     public NamePool getNamePool() {
309         return namePool;
310     }
311
312     /**
313     * Issue a compile-time warning. This method is used during XPath expression compilation to
314     * output warning conditions. The default implementation writes the message to System.err. To
315     * change the destination of messages, create a subclass of StandaloneContext that overrides
316     * this method.
317     */

318
319     public void issueWarning(String JavaDoc s, SourceLocator JavaDoc locator) {
320         System.err.println(s);
321     }
322
323     /**
324     * Get the system ID of the container of the expression. Used to construct error messages.
325     * @return "" always
326     */

327
328     public String JavaDoc getSystemId() {
329         return "";
330     }
331
332     /**
333     * Get the Base URI of the stylesheet element, for resolving any relative URI's used
334     * in the expression.
335     * Used by the document() function, resolve-uri(), etc.
336     * @return "" if no base URI has been set
337     */

338
339     public String JavaDoc getBaseURI() {
340         return baseURI==null ? "" : baseURI;
341     }
342
343     /**
344     * Get the line number of the expression within that container.
345     * Used to construct error messages.
346     * @return -1 always
347     */

348
349     public int getLineNumber() {
350         return -1;
351     }
352
353     /**
354      * Get the URI for a prefix, using the declared namespaces as
355      * the context for namespace resolution. The default namespace is NOT used
356      * when the prefix is empty.
357      * This method is provided for use by the XPath parser.
358      * @param prefix The prefix
359      * @throws net.sf.saxon.trans.XPathException if the prefix is not declared
360     */

361
362     public String JavaDoc getURIForPrefix(String JavaDoc prefix) throws XPathException {
363         String JavaDoc uri = getURIForPrefix(prefix, false);
364         if (uri==null) {
365             throw new StaticError("Prefix " + prefix + " has not been declared");
366         }
367         return uri;
368     }
369
370     public NamespaceResolver getNamespaceResolver() {
371         return this;
372     }
373
374     /**
375      * Get the namespace URI corresponding to a given prefix. Return null
376      * if the prefix is not in scope. This method first searches any namespaces
377      * declared using {@link #declareNamespace(String, String)}, and then searches
378      * any namespace context supplied using {@link #setNamespaceContext(javax.xml.namespace.NamespaceContext)}.
379      * @param prefix the namespace prefix
380      * @param useDefault true if the default namespace is to be used when the
381      * prefix is ""
382      * @return the uri for the namespace, or null if the prefix is not in scope.
383      * Return "" if the prefix maps to the null namespace.
384      */

385
386     public String JavaDoc getURIForPrefix(String JavaDoc prefix, boolean useDefault) {
387         if (prefix.equals("") && !useDefault) {
388             return "";
389         } else {
390             String JavaDoc uri = (String JavaDoc)namespaces.get(prefix);
391             if (uri == null && namespaceContext != null) {
392                 return namespaceContext.getNamespaceURI(prefix);
393             } else {
394                 return uri;
395             }
396         }
397     }
398
399     /**
400      * Get an iterator over all the prefixes declared in this namespace context. This will include
401      * the default namespace (prefix="") and the XML namespace where appropriate. The iterator only
402      * covers namespaces explicitly declared using {@link #declareNamespace(String, String)}; it does not
403      * include namespaces declared using {@link #setNamespaceContext(javax.xml.namespace.NamespaceContext)},
404      * because the JAXP {@link NamespaceContext} class provides no way to discover all the namespaces
405      * available.
406      */

407
408     public Iterator JavaDoc iteratePrefixes() {
409         return namespaces.keySet().iterator();
410     }
411
412     /**
413      * Bind a variable used in an XPath Expression to the XSLVariable element in which it is declared.
414      * This method is provided for use by the XPath parser, and it should not be called by the user of
415      * the API, or overridden, unless variables are to be declared using a mechanism other than the
416      * declareVariable method of this class.
417      * <p>
418      * If the variable has been explicitly declared using {@link #declareVariable(String, Object)},
419      * that value is used; otherwise if a variable resolved has been supplied using
420      * {@link #setXPathVariableResolver(javax.xml.xpath.XPathVariableResolver)} then that is used.
421      * @throws StaticError If no variable with the given name is found, or if the value supplied
422      * for the variable cannot be converted to an XPath value.
423      */

424
425     public VariableDeclaration bindVariable(int fingerprint) throws StaticError {
426         Variable var = (Variable)variables.get(new Integer JavaDoc(fingerprint));
427         if (var!=null) {
428             return var;
429         }
430         // bindVariable is called at compile time, but the JAXP variable resolver
431
// is designed to be called at run time. So we need to create a variable now,
432
// which will call the variableResolver when called upon to return the run-time value
433
if (variableResolver != null) {
434             QNameValue qname = new QNameValue(namePool, fingerprint);
435
436             return new JAXPVariable(qname, variableResolver);
437         }
438         throw new StaticError("Undeclared variable in a standalone expression");
439
440     }
441
442     /**
443      * Get the function library containing all the in-scope functions available in this static
444      * context
445      */

446
447     public FunctionLibrary getFunctionLibrary() {
448         return functionLibrary;
449     }
450
451     /**
452      * Set the function library to be used
453      */

454
455     public void setFunctionLibrary(FunctionLibrary lib) {
456         functionLibrary = lib;
457     }
458
459     /**
460     * Get a named collation.
461     * @return the collation identified by the given name, as set previously using declareCollation.
462     * Return null if no collation with this name is found.
463     */

464
465     public Comparator JavaDoc getCollation(String JavaDoc name) {
466         Configuration config = getConfiguration();
467         return config.getCollationURIResolver().resolve(name, getBaseURI(), config);
468     }
469
470     /**
471     * Get the name of the default collation.
472     * @return the name of the default collation; or the name of the codepoint collation
473     * if no default collation has been defined
474     */

475
476     public String JavaDoc getDefaultCollationName() {
477         if (defaultCollationName != null) {
478             return defaultCollationName;
479         } else {
480             return NamespaceConstant.CODEPOINT_COLLATION_URI;
481         }
482     }
483
484     /**
485      * Set the default namespace for element and type names
486      */

487
488     public void setDefaultElementNamespace(String JavaDoc uri) {
489         defaultElementNamespace = namePool.allocateCodeForURI(uri);
490     }
491
492     /**
493     * Get the default XPath namespace, as a namespace code that can be looked up in the NamePool
494     */

495
496     public short getDefaultElementNamespace() {
497         return defaultElementNamespace;
498     }
499
500     /**
501      * Set the default function namespace
502      */

503
504     public void setDefaultFunctionNamespace(String JavaDoc uri) {
505         defaultFunctionNamespace = uri;
506     }
507
508     /**
509      * Get the default function namespace
510      */

511
512     public String JavaDoc getDefaultFunctionNamespace() {
513         return defaultFunctionNamespace;
514     }
515
516     /**
517      * Set XPath 1.0 backwards compatibility mode
518      * @param backwardsCompatible if true, expressions will be evaluated with
519      * XPath 1.0 compatibility mode set to true.
520      */

521
522     public void setBackwardsCompatibilityMode(boolean backwardsCompatible) {
523         this.backwardsCompatible = true;
524     }
525     /**
526      * Determine whether Backwards Compatible Mode is used
527      * @return false; XPath 1.0 compatibility mode is not supported in the standalone
528      * XPath API
529      */

530
531     public boolean isInBackwardsCompatibleMode() {
532         return backwardsCompatible;
533     }
534
535     /**
536      * Determine whether a Schema for a given target namespace has been imported. Note that the
537      * in-scope element declarations, attribute declarations and schema types are the types registered
538      * with the (schema-aware) configuration, provided that their namespace URI is registered
539      * in the static context as being an imported schema namespace. (A consequence of this is that
540      * within a Configuration, there can only be one schema for any given namespace, including the
541      * null namespace).
542      * @return This implementation always returns false: the standalone XPath API does not support
543      * schema-aware processing.
544      */

545
546     public boolean isImportedSchema(String JavaDoc namespace) {
547         return false;
548     }
549
550     /**
551      * Determine whether a built-in type is available in this context. This method caters for differences
552      * between host languages as to which set of types are built in.
553      *
554      * @param type the supposedly built-in type. This will always be a type in the
555      * XS or XDT namespace.
556      * @return true if this type can be used in this static context
557      */

558
559     public boolean isAllowedBuiltInType(AtomicType type) {
560         return true;
561     }
562 }
563
564 //
565
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
566
// you may not use this file except in compliance with the License. You may obtain a copy of the
567
// License at http://www.mozilla.org/MPL/
568
//
569
// Software distributed under the License is distributed on an "AS IS" basis,
570
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
571
// See the License for the specific language governing rights and limitations under the License.
572
//
573
// The Original Code is: all this file.
574
//
575
// The Initial Developer of the Original Code is Michael H. Kay
576
//
577
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
578
//
579
// Contributor(s): none.
580
//
581
Popular Tags