All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.query.StaticQueryContext Maven / Gradle / Ivy

Go to download

Provides a basic XSLT 2.0 and XQuery 1.0 processor (W3C Recommendations, January 2007). Command line interfaces and implementations of several Java APIs (DOM, XPath, s9api) are also included.

The newest version!
package net.sf.saxon.query;

import net.sf.saxon.Configuration;
import net.sf.saxon.StandardErrorListener;
import net.sf.saxon.instruct.Executable;
import net.sf.saxon.expr.CollationMap;
import net.sf.saxon.om.*;
import net.sf.saxon.sort.NamedCollation;
import net.sf.saxon.sort.StringCollator;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.AnyItemType;
import net.sf.saxon.type.ItemType;

import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.*;

/**
 * StaticQueryContext contains information used to build a StaticContext for use when processing XQuery
 * expressions.
 *
 * 

Despite its name, StaticQueryContext no longer implements the StaticContext * interface, which means it cannot be used directly by Saxon when parsing a query. Instead it is first copied * to create a QueryModule object, which does implement the StaticContext interface. * *

The application constructs a StaticQueryContext * and initializes it with information about the context, for example, default namespaces, base URI, and so on. * When a query is compiled using this StaticQueryContext, the query parser makes a copy of the StaticQueryContext * and uses this internally, modifying it with information obtained from the query prolog, as well as information * such as namespace and variable declarations that can occur at any point in the query. The query parser does * not modify the original StaticQueryContext supplied by the calling application, which may therefore be used * for compiling multiple queries, serially or even in multiple threads.

* *

This class forms part of Saxon's published XQuery API. Methods that * are considered stable are labelled with the JavaDoc "since" tag. * The value 8.4 indicates a method introduced at or before Saxon 8.4; other * values indicate the version at which the method was introduced.

* *

In the longer term, this entire API may at some stage be superseded by a proposed * standard Java API for XQuery.

* * @since 8.4 */ public class StaticQueryContext { private Configuration config; private NamePool namePool; private String baseURI; private HashMap userDeclaredNamespaces; private Executable executable; private boolean inheritNamespaces = true; private boolean preserveNamespaces = true; private int constructionMode = Validation.PRESERVE; private NamespaceResolver externalNamespaceResolver = null; private CollationMap collations; private String defaultFunctionNamespace; private String defaultElementNamespace; private ItemType requiredContextItemType = AnyItemType.getInstance(); private boolean preserveSpace = false; private boolean defaultEmptyLeast = true; private ModuleURIResolver moduleURIResolver; private ErrorListener errorListener; private boolean tracing; private boolean generateCode = false; /** * Private constructor used when copying a context */ protected StaticQueryContext() { } /** * Create a StaticQueryContext using a given Configuration. This creates a StaticQueryContext for a main module * (that is, a module that is not a library module). * @param config the Saxon Configuration * * @since 8.4 */ public StaticQueryContext(Configuration config) { this.config = config; namePool = config.getNamePool(); errorListener = config.getErrorListener(); moduleURIResolver = config.getModuleURIResolver(); if (errorListener instanceof StandardErrorListener) { errorListener = ((StandardErrorListener)errorListener).makeAnother(Configuration.XQUERY); ((StandardErrorListener)errorListener).setRecoveryPolicy(Configuration.DO_NOT_RECOVER); } collations = new CollationMap(config); reset(); } /** * Reset the state of this StaticQueryContext to an uninitialized state * * @since 8.4 */ public void reset() { userDeclaredNamespaces = new HashMap(10); externalNamespaceResolver = null; collations = new CollationMap(config); errorListener = config.getErrorListener(); if (errorListener instanceof StandardErrorListener) { errorListener = ((StandardErrorListener)errorListener).makeAnother(Configuration.XQUERY); ((StandardErrorListener)errorListener).setRecoveryPolicy(Configuration.DO_NOT_RECOVER); } constructionMode = getConfiguration().isSchemaAware(Configuration.XQUERY) ? Validation.PRESERVE : Validation.STRIP; preserveSpace = false; defaultEmptyLeast = true; requiredContextItemType = AnyItemType.getInstance(); defaultFunctionNamespace = NamespaceConstant.FN; defaultElementNamespace = NamespaceConstant.NULL; moduleURIResolver = config.getModuleURIResolver(); collations.setDefaultCollationName(NamespaceConstant.CODEPOINT_COLLATION_URI); clearNamespaces(); generateCode = false; } /** * Set the Configuration options * @param config the Saxon Configuration * @throws IllegalArgumentException if the configuration supplied is different from the existing * configuration * @since 8.4 */ public void setConfiguration(Configuration config) { if (this.config != null && this.config != config) { throw new IllegalArgumentException("Configuration cannot be changed dynamically"); } this.config = config; namePool = config.getNamePool(); } /** * Get the Configuration options * @return the Saxon configuration * @since 8.4 */ public Configuration getConfiguration() { return config; } /** * Set the Executable to contain this query. Normally a query constitutes its own Executable, * and the executable will then be created automatically. This method is used when the query is to * share the same executable as a host program, specifically, an XSLT stylesheet that imports the * query. * @param executable the executable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the executable containing this query * @return the executable (or null if not set) */ public Executable getExecutable() { return executable; } /** * Set the Base URI of the query * @param baseURI the base URI of the query * @since 8.4 */ public void setBaseURI(String baseURI) { this.baseURI = baseURI; } /** * Convenience method for building Saxon's internal representation of a source XML * document. The document will be built using Configuration (and NamePool) associated * with this StaticQueryContext. * *

This method is retained for backwards compatibility; however, it is merely a wrapper * around the method {@link Configuration#buildDocument}, which should be called in preference.

* * @param source Any javax.xml.transform.Source object representing the document against * which queries will be executed. Note that a Saxon {@link net.sf.saxon.om.DocumentInfo DocumentInfo} * (indeed any {@link net.sf.saxon.om.NodeInfo NodeInfo}) * can be used as a Source. To use a third-party DOM Document as a source, create an instance of * {@link javax.xml.transform.dom.DOMSource DOMSource} to wrap it. *

For additional control over the way in which the source document is processed, * supply an {@link net.sf.saxon.AugmentedSource AugmentedSource} object and set appropriate * options on the object.

* @return the DocumentInfo representing the root node of the resulting document object. * @since 8.4 */ public DocumentInfo buildDocument(Source source) throws XPathException { return config.buildDocument(source); } /** * Ask whether compile-time generation of trace code was requested * @since 9.0 * @return true if compile-time generation of code was requested */ public boolean isCompileWithTracing() { return tracing; } /** * Request compile-time generation of trace code (or not) * @param trace true if compile-time generation of trace code is required * @since 9.0 */ public void setCompileWithTracing(boolean trace) { tracing = trace; } /** * Indicate that the query should be optimized with a view to generating Java code. * This inhibits some rewrites to constructs for which code generation is not possible. * @param generateCode true if Java code is to be generated as the final output */ public void setGeneratingJavaCode(boolean generateCode) { this.generateCode = generateCode; } /** * Ask whether this query is to be optimized with a view to generating Java code. * This inhibits some rewrites to constructs for which code generation is not possible. * @return true if Java code is to be generated as the final output */ public boolean isGeneratingJavaCode() { return generateCode; } /** * Set the namespace inheritance mode * * @param inherit true if namespaces are inherited, false if not * @since 8.4 */ public void setInheritNamespaces(boolean inherit) { inheritNamespaces = inherit; } /** * Get the namespace inheritance mode * * @return true if namespaces are inherited, false if not * @since 8.4 */ public boolean isInheritNamespaces() { return inheritNamespaces; } /** * Set the namespace copy mode * * @param inherit true if namespaces are preserved, false if not * @since 8.4 */ public void setPreserveNamespaces(boolean inherit) { preserveNamespaces = inherit; } /** * Get the namespace copy mode * * @return true if namespaces are preserved, false if not * @since 8.4 */ public boolean isPreserveNamespaces() { return preserveNamespaces; } /** * Set the construction mode for this module * * @param mode one of {@link net.sf.saxon.om.Validation#STRIP}, {@link net.sf.saxon.om.Validation#PRESERVE} * @since 8.4 */ public void setConstructionMode(int mode) { constructionMode = mode; } /** * Get the current construction mode * * @return one of {@link net.sf.saxon.om.Validation#STRIP}, {@link net.sf.saxon.om.Validation#PRESERVE} * @since 8.4 */ public int getConstructionMode() { return constructionMode; } /** * Prepare an XQuery query for subsequent evaluation. The source text of the query * is supplied as a String. The base URI of the query is taken from the static context, * and defaults to the current working directory. * *

Note that this interface makes caller responsible for decoding the query and * presenting it as a string of characters. This means it is likely that any encoding * specified in the query prolog will be ignored.

* * @param query The XQuery query to be evaluated, supplied as a string. * @return an XQueryExpression object representing the prepared expression * @throws net.sf.saxon.trans.XPathException * if the syntax of the expression is wrong, * or if it references namespaces, variables, or functions that have not been declared, * or contains other static errors. * @since 8.4 */ public XQueryExpression compileQuery(String query) throws XPathException { QueryParser qp = new QueryParser(); qp.setCompileWithTracing(isCompileWithTracing() || config.isCompileWithTracing()); QueryModule mainModule = new QueryModule(this); mainModule.setExecutable(executable); return qp.makeXQueryExpression(query, mainModule, config); } /** * Prepare an XQuery query for subsequent evaluation. The Query is supplied * in the form of a Reader. The base URI of the query is taken from the static context, * and defaults to the current working directory. * *

Note that this interface makes the Reader responsible for decoding the query and * presenting it as a stream of characters. This means it is likely that any encoding * specified in the query prolog will be ignored. Also, some implementations of Reader * cannot handle a byte order mark.

* * @param source A Reader giving access to the text of the XQuery query to be compiled. * @return an XPathExpression object representing the prepared expression. * @throws net.sf.saxon.trans.XPathException * if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared, or any other static error is reported. * @throws java.io.IOException if a failure occurs reading the supplied input. * @since 8.4 */ public XQueryExpression compileQuery(Reader source) throws XPathException, IOException { char[] buffer = new char[4096]; StringBuffer sb = new StringBuffer(4096); while (true) { int n = source.read(buffer); if (n > 0) { sb.append(buffer, 0, n); } else { break; } } return compileQuery(sb.toString()); } /** * Prepare an XQuery query for subsequent evaluation. The Query is supplied * in the form of a InputStream, with an optional encoding. If the encoding is not specified, * the query parser attempts to obtain the encoding by inspecting the input stream: it looks specifically * for a byte order mark, and for the encoding option in the version declaration of an XQuery prolog. * The encoding defaults to UTF-8. * The base URI of the query is taken from the static context, * and defaults to the current working directory. * * @param source An InputStream giving access to the text of the XQuery query to be compiled, as a stream * of octets * @param encoding The encoding used to translate characters to octets in the query source. The parameter * may be null: in this case the query parser attempts to infer the encoding by inspecting the source, * and if that fails, it assumes UTF-8 encoding * @return an XPathExpression object representing the prepared expression. * @throws net.sf.saxon.trans.XPathException * if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared, or any other static error is reported. * @throws java.io.IOException if a failure occurs reading the supplied input. * @since 8.5 */ public XQueryExpression compileQuery(InputStream source, String encoding) throws XPathException, IOException { String query = QueryReader.readInputStream(source, encoding, config.getNameChecker()); return compileQuery(query); } /** * Declare a namespace whose prefix can be used in expressions. This is * equivalent to declaring a prefix in the Query prolog. * Any namespace declared in the Query prolog overrides a namespace declared using * this API. * * @param prefix The namespace prefix. Must not be null. Setting this to "" means that the * namespace will be used as the default namespace for elements and types. * @param uri The namespace URI. Must not be null. The value "" (zero-length string) is used * to undeclare a namespace; it is not an error if there is no existing binding for * the namespace prefix. * @throws NullPointerException if either the prefix or URI is null * @throws IllegalArgumentException if the prefix is "xml" and the namespace is not the XML namespace, or vice * versa. * @since 9.0 */ public void declareNamespace(String prefix, String uri) { if (prefix == null) { throw new NullPointerException("Null prefix supplied to declareNamespace()"); } if (uri == null) { throw new NullPointerException("Null namespace URI supplied to declareNamespace()"); } if ((prefix.equals("xml") != uri.equals(NamespaceConstant.XML))) { throw new IllegalArgumentException("Misdeclaration of XML namespace"); } if (prefix.length() == 0) { defaultElementNamespace = (uri==null ? "" : uri); } if (uri.length() == 0 && prefix.length() != 0) { userDeclaredNamespaces.remove(prefix); } else { userDeclaredNamespaces.put(prefix, uri); namePool.allocateNamespaceCode(prefix, uri); } } /** * Declare a namespace whose prefix can be used in expressions. This is * equivalent to declaring a prefix in the Query prolog. The term "passive" * was a term from a draft XQuery proposal indicating a namespace that won't * be copied into the result tree. Passive namespaces are never undeclared. * Any namespace declared in the Query prolog overrides a namespace declared using * this API. * * @param prefix The namespace prefix. Must not be null. * @param uri The namespace URI. Must not be null. The value "" (zero-length string) is used * to undeclare a namespace; it is not an error if there is no existing binding for * the namespace prefix. * @param explicit Must be false (the value true was previously reserved for internal use, but is * no longer permitted) * @since 8.4 * @deprecated since 9.0. Use {@link #declareNamespace} */ public void declarePassiveNamespace(String prefix, String uri, boolean explicit) throws XPathException { if (explicit) { throw new IllegalArgumentException("explicit must be false"); } declareNamespace(prefix, uri); } /** * Clear all the user-declared namespaces * * @since 9.0 */ public void clearNamespaces() { userDeclaredNamespaces.clear(); declareNamespace("xml", NamespaceConstant.XML); declareNamespace("xs", NamespaceConstant.SCHEMA); declareNamespace("xsi", NamespaceConstant.SCHEMA_INSTANCE); declareNamespace("fn", NamespaceConstant.FN); declareNamespace("local", NamespaceConstant.LOCAL); declareNamespace("saxon", NamespaceConstant.SAXON); declareNamespace("", ""); } /** * Get the map of user-declared namespaces * @return the user-declared namespaces */ protected HashMap getUserDeclaredNamespaces() { return userDeclaredNamespaces; } /** * Clear all the declared passive namespaces, except for the standard ones (xml, saxon, etc) * * @since 8.4 * @deprecated since 9.0 - use {@link #clearNamespaces} */ public void clearPassiveNamespaces() { clearNamespaces(); } /** * Get the namespace prefixes that have been declared using the method {@link #declareNamespace} * @return an iterator that returns the namespace prefixes that have been explicitly declared, as * strings. The default namespace for elements and types will be included, using the prefix "". * @since 9.0 */ public Iterator iterateDeclaredPrefixes() { return userDeclaredNamespaces.keySet().iterator(); } /** * Get the namespace URI for a given prefix, which must have been declared using the method * {@link #declareNamespace}. Note that this method will not call the external namespace resolver * to resolve the prefix. * @param prefix the namespace prefix, or "" to represent the null prefix * @return the namespace URI. Returns "" to represent the non-namespace, * null to indicate that the prefix has not been declared */ public String getNamespaceForPrefix(String prefix) { return (String)userDeclaredNamespaces.get(prefix); } /** * Set an external namespace resolver. If a namespace prefix cannot be resolved using any * other mechanism, then as a last resort the external namespace resolver is called to * obtain a URI for the given prefix. * *

Changed in Saxon 9.0 so that the namespaces resolved by the external namespace resolver * are available at run-time, just like namespaces declared in the query prolog. In consequence, * the supplied NamespaceResolver must now implement the * {@link net.sf.saxon.om.NamespaceResolver#iteratePrefixes()} method.

* * @param resolver the external namespace resolver */ public void setExternalNamespaceResolver(NamespaceResolver resolver) { externalNamespaceResolver = resolver; } /** * Get the external namespace resolver that has been registered using * setExternalNamespaceResolver(), if any. * @return the external namespace resolver */ public NamespaceResolver getExternalNamespaceResolver() { return externalNamespaceResolver; } /** * Get the default function namespace * * @return the default function namespace (defaults to the fn: namespace) * @since 8.4 */ public String getDefaultFunctionNamespace() { return defaultFunctionNamespace; } /** * Set the default function namespace * * @param defaultFunctionNamespace The namespace to be used for unprefixed function calls * @since 8.4 */ public void setDefaultFunctionNamespace(String defaultFunctionNamespace) { this.defaultFunctionNamespace = defaultFunctionNamespace; } /** * Set the default element namespace * @param uri the namespace URI to be used as the default namespace for elements and types * @since 8.4 */ public void setDefaultElementNamespace(String uri) throws XPathException { defaultElementNamespace = uri; declareNamespace("", uri); } /** * Get the default namespace for elements and types * @return the namespace URI to be used as the default namespace for elements and types * @since 8.9 Modified in 8.9 to return the namespace URI as a string rather than an integer code */ public String getDefaultElementNamespace() { return defaultElementNamespace; } /** * Set a user-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in the XQuery prolog. * This will be used for resolving URIs in XQuery "import module" declarations, overriding * any ModuleURIResolver that was specified as part of the configuration. * @param resolver the ModuleURIResolver to be used */ public void setModuleURIResolver(ModuleURIResolver resolver) { moduleURIResolver = resolver; } /** * Get the user-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in the XQuery prolog; returns null if none has been explicitly set either * on the StaticQueryContext or on the Configuration. * @return the registered ModuleURIResolver */ public ModuleURIResolver getModuleURIResolver() { return moduleURIResolver; } /** * Declare a named collation. Collations are only available in a query if this method * has been called externally to declare the collation and associate it with an * implementation, in the form of a Java Comparator. The default collation is the * Unicode codepoint collation, unless otherwise specified. * * @param name The name of the collation (technically, a URI) * @param comparator The Java Comparator used to implement the collating sequence * @since 8.4. */ public void declareCollation(String name, Comparator comparator) { declareCollation(name, new NamedCollation(name, comparator)); } /** * Declare a named collation. Collations are only available in a query if this method * has been called externally to declare the collation and associate it with an * implementation, in the form of a Java StringCollator. The default collation is the * Unicode codepoint collation, unless otherwise specified. * * @param name The name of the collation (technically, a URI) * @param comparator The Java Comparator used to implement the collating sequence * @since 8.9. */ public void declareCollation(String name, StringCollator comparator) { collations.setNamedCollation(name, comparator); } /** * Set the default collation. * @param name The collation name, as specified in the query prolog. The name * is not validated until it is used. * @since 8.4. Changed in 8.6 so it no longer validates the collation name: this is * because the base URI is not necessarily known at the point where the default * collation is declared. */ public void declareDefaultCollation(String name) { collations.setDefaultCollationName(name); } /** * Get a named collation. * @param name the name of the collation, as an absolute URI * @return the collation identified by the given name, as set previously using declareCollation. * If no collation with this name has been declared, the method calls the CollationURIResolver * to locate a collation with this name. * Return null if no collation with this name is found. * @since 8.4 */ public StringCollator getCollation(String name) { return collations.getNamedCollation(name); } /** * Get the collation map * @return the collation map, which identifies all the known collations */ public CollationMap getCollationMap() { return collations; } /** * Get the name of the default collation. * * @return the name of the default collation; or the name of the codepoint collation * if no default collation has been defined. The name is returned in the form * it was specified; that is, it is not yet resolved against the base URI. (This * is because the base URI declaration can follow the default collation declaration * in the query prolog.) If no default collation has been specified, the "default default" * (that is, the Unicode codepoint collation) is returned. * @since 8.4 */ public String getDefaultCollationName() { return collations.getDefaultCollationName(); } /** * Get a HashMap that maps all registered collations to Comparators. * Note that this returns a snapshot copy of the data held by the static context. * This method is provided for internal use by the query processor. *

* This method is intended for internal use. * @return the CollationMap containing all the collations defined in this static context */ public CollationMap getAllCollations() { return new CollationMap(collations); } /** * Declare the static type of the context item. If this type is declared, and if a context item * is supplied when the query is invoked, then the context item must conform to this type (no * type conversion will take place to force it into this type). * @param type the required type of the context item */ public void setRequiredContextItemType(ItemType type) { requiredContextItemType = type; } /** * Get the required type of the context item. If no type has been explicitly declared for the context * item, an instance of AnyItemType (representing the type item()) is returned. * @return the required type of the context item */ public ItemType getRequiredContextItemType() { return requiredContextItemType; } /** * Get the NamePool used for compiling expressions * @return the name pool * @since 8.4 */ public NamePool getNamePool() { return namePool; } /** * Get the system ID of the container of the expression. Used to construct error messages. * Note that the systemID and the Base URI are currently identical, but they might be distinguished * in the future. * * @return the Base URI * @since 8.4 */ public String getSystemId() { return baseURI; } /** * Get the Base URI of the query, for resolving any relative URI's used * in the expression. * Note that the systemID and the Base URI are currently identical, but they might be distinguished * in the future. * Used by the document() function. * * @return the base URI of the query * @since 8.4 */ public String getBaseURI() { return baseURI; } /** * Set the policy for preserving boundary space * @param preserve true if boundary space is to be preserved, false if it is to be stripped * @since 9.0 */ public void setPreserveBoundarySpace(boolean preserve) { preserveSpace = preserve; } /** * Ask whether the policy for boundary space is "preserve" or "strip" * @return true if the policy is to preserve boundary space, false if it is to strip it * @since 9.0 */ public boolean isPreserveBoundarySpace() { return preserveSpace; } /** * Set the option for where an empty sequence appears in the collation order, if not otherwise * specified in the "order by" clause * @param least true if the empty sequence is considered less than any other value (the default), * false if it is considered greater than any other value * @since 9.0 */ public void setEmptyLeast(boolean least) { defaultEmptyLeast = least; } /** * Ask what is the option for where an empty sequence appears in the collation order, if not otherwise * specified in the "order by" clause * @return true if the empty sequence is considered less than any other value (the default), * false if it is considered greater than any other value * @since 9.0 */ public boolean isEmptyLeast() { return defaultEmptyLeast; } /** * Set the ErrorListener to be used to report compile-time errors in a query. This will also * be the default for the run-time error listener used to report dynamic errors * @param listener the ErrorListener to be used */ public void setErrorListener(ErrorListener listener) { errorListener = listener; } /** * Get the ErrorListener in use for this static context * @return the registered ErrorListener */ public ErrorListener getErrorListener() { if (errorListener == null) { errorListener = config.getErrorListener(); } return errorListener; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //





© 2015 - 2025 Weber Informatics LLC | Privacy Policy