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

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

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.query;

import net.sf.saxon.Configuration;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.instruct.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.functions.*;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.lib.Validation;
import net.sf.saxon.om.*;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trace.TraceCodeInjector;
import net.sf.saxon.trans.DecimalFormatManager;
import net.sf.saxon.trans.KeyManager;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.*;
import net.sf.saxon.value.SequenceType;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

/**
 * This class represents a query module, and includes information about the static context of the query module.
 * The class is intended for internal Saxon use. User settings that affect the static context are made in the
 * StaticQueryContext object, and those settings are copied to each QueryModule when the query module is compiled.
 */

public class QueryModule implements StaticContext {
    private boolean isMainModule;
    private Configuration config;
    private StaticQueryContext userQueryContext;
    private QueryModule topModule;
    private URI locationURI;
    private String baseURI;
    private String moduleNamespace; // null only if isMainModule is false
    private HashMap explicitPrologNamespaces;
    private Stack activeNamespaces;
    private HashMap variables;
    // global variables declared in this module
    private HashMap libraryVariables;
    // all global variables defined in library modules
    // defined only on the top-level module
    private HashMap undeclaredVariables;
    private HashSet importedSchemata;    // The schema target namespaces imported into this module
    private HashMap> loadedSchemata;
    // For the top-level module only, all imported schemas for all modules,
    // Key is the targetNamespace, value is the set of absolutized location URIs
    private Executable executable;
    private List importers;  // A list of QueryModule objects representing the modules that import this one,
    // Null for the main module
    // This is needed *only* to implement the rules banning cyclic imports
    private FunctionLibraryList functionLibraryList;
    private XQueryFunctionLibrary globalFunctionLibrary;      // used only on a top-level module
    private int localFunctionLibraryNr;
    private int importedFunctionLibraryNr;
    private int unboundFunctionLibraryNr;
    private Set importedModuleNamespaces;
    private boolean inheritNamespaces = true;
    private boolean preserveNamespaces = true;
    private int constructionMode = Validation.PRESERVE;
    private String defaultFunctionNamespace;
    private String defaultElementNamespace;
    private boolean preserveSpace = false;
    private boolean defaultEmptyLeast = true;
    private String defaultCollationName;
    private int revalidationMode = Validation.SKIP;
    private boolean isUpdating = false;
    private int languageVersion = 10;       // The decimal version times ten
    private ItemType requiredContextItemType = AnyItemType.getInstance(); // must be the same for all modules
    private DecimalFormatManager decimalFormatManager = null;   // used only in XQuery 3.0
    private CodeInjector codeInjector;
    private PackageData packageData;
    private RetainedStaticContext moduleStaticContext = null;
    private Location moduleLocation;

    /**
     * Create a QueryModule for a main module, copying the data that has been set up in a
     * StaticQueryContext object
     *
     * @param sqc the StaticQueryContext object from which this module is initialized
     * @throws XPathException if information supplied is invalid
     */

    public QueryModule(/*@NotNull*/ StaticQueryContext sqc) throws XPathException {
        config = sqc.getConfiguration();
        isMainModule = true;
        topModule = this;
        activeNamespaces = new Stack();
        baseURI = sqc.getBaseURI();
        defaultCollationName = sqc.getDefaultCollationName();
        try {
            locationURI = baseURI == null ? null : new URI(baseURI);
        } catch (URISyntaxException err) {
            throw new XPathException("Invalid location URI: " + baseURI);
        }
        executable = sqc.makeExecutable();
        importers = null;
        init(sqc);

        PackageData pd = new PackageData(config);
        pd.setXPathVersion(getXPathVersion());
        pd.setHostLanguage(Configuration.XQUERY);
        pd.setSchemaAware(isSchemaAware());
        packageData = pd;

        for (Iterator vars = sqc.iterateDeclaredGlobalVariables(); vars.hasNext(); ) {
            GlobalVariable var = vars.next();
            declareVariable(var);
            pd.addGlobalVariable(var);
            var.setPackageData(pd);
        }


        executable.setTopLevelPackage(pd);
        executable.addPackage(pd);

        if (sqc.getModuleLocation() == null) {
            moduleLocation = new ExplicitLocation(sqc.getSystemId(), 1, -1);
        } else {
            moduleLocation = sqc.getModuleLocation();
        }
    }

    /**
     * Create a QueryModule for a library module.
     *
     * @param config   the Saxon configuration
     * @param importer the module that imported this module. This may be null, in the case where
     *                 the library module is being imported into an XSLT stylesheet
     */

    public QueryModule(Configuration config, /*@Nullable*/ QueryModule importer) {
        this.config = config;
        importers = null;
        if (importer == null) {
            topModule = this;
        } else {
            topModule = importer.topModule;
            userQueryContext = importer.userQueryContext;
            importers = new ArrayList(2);
            importers.add(importer);
        }
        init(userQueryContext);
        packageData = importer.getPackageData();
        activeNamespaces = new Stack();
        executable = null;
    }

    /**
     * Initialize data from a user-supplied StaticQueryContext object
     *
     * @param sqc the user-supplied StaticQueryContext. Null if this is a library module imported
     *            into XSLT.
     */

    private void init(/*@Nullable*/ StaticQueryContext sqc) {
        //reset();
        userQueryContext = sqc;
        variables = new HashMap(10);
        undeclaredVariables = new HashMap(5);
        if (isTopLevelModule()) {
            libraryVariables = new HashMap(10);
        }
        importedSchemata = new HashSet(5);
        //importedSchemata.add(NamespaceConstant.JSON);
        importedModuleNamespaces = new HashSet(5);
        moduleNamespace = null;
        activeNamespaces = new Stack();

        explicitPrologNamespaces = new HashMap(10);
        if (sqc != null) {
            //executable = sqc.getExecutable();
            inheritNamespaces = sqc.isInheritNamespaces();
            preserveNamespaces = sqc.isPreserveNamespaces();
            preserveSpace = sqc.isPreserveBoundarySpace();
            defaultEmptyLeast = sqc.isEmptyLeast();
            defaultFunctionNamespace = sqc.getDefaultFunctionNamespace();
            defaultElementNamespace = sqc.getDefaultElementNamespace();
            defaultCollationName = sqc.getDefaultCollationName();
            constructionMode = sqc.getConstructionMode();
            if (constructionMode == Validation.PRESERVE && !sqc.isSchemaAware()) {
                // if not schema-aware, generate untyped output by default
                constructionMode = Validation.STRIP;
            }
            requiredContextItemType = sqc.getRequiredContextItemType();
            isUpdating = sqc.isUpdatingEnabled();
            languageVersion = sqc.getLanguageVersion();
            codeInjector = sqc.getCodeInjector();
            //allowTypedNodes = sqc.isAllowTypedNodes();
        }
        initializeFunctionLibraries(sqc);
    }

    /**
     * Supporting method to load an imported library module.
     * Used also by saxon:import-query in XSLT.
     * 

* This method is intended for internal use only. * * @param baseURI The base URI and location URI of the module * @param executable The Executable * @param importer The importing query module (used to check for cycles). This is null * when loading a query module from XSLT. * @param query The text of the query, after decoding and normalizing line endings * @param namespaceURI namespace of the query module to be loaded * @param allowCycles True if cycles of module imports (disallowed by the spec) are to be permitted * @return The StaticQueryContext representing the loaded query module * @throws XPathException if an error occurs */ /*@NotNull*/ public static QueryModule makeQueryModule( String baseURI, /*@NotNull*/ Executable executable, /*@NotNull*/ QueryModule importer, String query, String namespaceURI, boolean allowCycles) throws XPathException { Configuration config = executable.getConfiguration(); QueryModule module = new QueryModule(config, importer); try { module.setLocationURI(new URI(baseURI)); } catch (URISyntaxException e) { throw new XPathException("Invalid location URI " + baseURI, e); } module.setBaseURI(baseURI); module.setExecutable(executable); module.setModuleNamespace(namespaceURI); executable.addQueryLibraryModule(module); XQueryParser qp = (XQueryParser) config.newExpressionParser( "XQ", importer.isUpdating(), importer.getLanguageVersion()); if (importer.getCodeInjector() != null) { qp.setCodeInjector(importer.getCodeInjector()); } else if (config.isCompileWithTracing()) { qp.setCodeInjector(new TraceCodeInjector()); } qp.setDisableCycleChecks(allowCycles); QNameParser qnp = new QNameParser(module.getLiveNamespaceResolver()); qnp.setAcceptEQName(importer.getXPathVersion() >= 30); qp.setQNameParser(qnp); qp.parseLibraryModule(query, module); String namespace = module.getModuleNamespace(); if (namespace == null) { XPathException err = new XPathException("Imported module must be a library module"); err.setErrorCode("XQST0059"); err.setIsStaticError(true); throw err; } if (!namespace.equals(namespaceURI)) { XPathException err = new XPathException("Imported module's namespace does not match requested namespace"); err.setErrorCode("XQST0059"); err.setIsStaticError(true); throw err; } return module; } /** * Reset function libraries * * @param sqc The static query context set up by the caller */ private void initializeFunctionLibraries(/*@Nullable*/ StaticQueryContext sqc) { Configuration config = getConfiguration(); if (isTopLevelModule()) { globalFunctionLibrary = new XQueryFunctionLibrary(config); } int functionSet = StandardFunction.CORE; if (isUpdating()) { functionSet |= StandardFunction.XQUPDATE; } if (getLanguageVersion() >= 30) { functionSet |= StandardFunction.XPATH30; } if (getLanguageVersion() >= 31) { functionSet |= StandardFunction.XPATH31; } functionLibraryList = new FunctionLibraryList(); functionLibraryList.addFunctionLibrary( SystemFunctionLibrary.getSystemFunctionLibrary(functionSet, config)); functionLibraryList.addFunctionLibrary(config.getVendorFunctionLibrary()); functionLibraryList.addFunctionLibrary(new ConstructorFunctionLibrary(config)); localFunctionLibraryNr = functionLibraryList.addFunctionLibrary( new XQueryFunctionLibrary(config)); importedFunctionLibraryNr = functionLibraryList.addFunctionLibrary( new ImportedFunctionLibrary(this, getTopLevelModule().getGlobalFunctionLibrary())); if (sqc != null && sqc.getExtensionFunctionLibrary() != null) { functionLibraryList.addFunctionLibrary(sqc.getExtensionFunctionLibrary()); } functionLibraryList.addFunctionLibrary(config.getIntegratedFunctionLibrary()); config.addExtensionBinders(functionLibraryList); unboundFunctionLibraryNr = functionLibraryList.addFunctionLibrary( new UnboundFunctionLibrary()); } /** * Get the Saxon Configuration * * @return the Saxon Configuration */ public Configuration getConfiguration() { return config; } /** * Get package data. This is a small data object containing information about the unit * of compilation, which in the case of XQuery is a query module * * @return data about this query module */ public PackageData getPackageData() { return packageData; } /** * Set the package data. This method is used when we want the QueryModule to share the same * package data as another module: notably when fn:load-query-module creates a "dummy" main * module to go with the dynamic library module * @param packageData the package information */ public void setPackageData(PackageData packageData) { this.packageData = packageData; } /** * Test whether this is a "top-level" module. This is true for a main module and also for a * module directly imported into an XSLT stylesheet. It may also be true in future for independently-compiled * modules * * @return true if this is top-level module */ public boolean isTopLevelModule() { return this == topModule; } /** * Set whether this is a "Main" module, in the sense of the XQuery language specification * * @param main true if this is a main module, false if it is a library module */ public void setIsMainModule(boolean main) { isMainModule = main; } /** * Ask whether this is a "main" module, in the sense of the XQuery language specification * * @return true if this is a main module, false if it is a library model */ public boolean isMainModule() { return isMainModule; } /** * Check whether this module is allowed to import a module with namespace N. Note that before * calling this we have already handled the exception case where a module imports another in the same * namespace (this is the only case where cycles are allowed, though as a late change to the spec they * are no longer useful, since they cannot depend on each other cyclically) * * @param namespace the namespace to be tested * @return true if the import is permitted */ public boolean mayImportModule(/*@NotNull*/ String namespace) { if (namespace.equals(moduleNamespace)) { return false; } if (importers == null) { return true; } for (QueryModule importer : importers) { if (!importer.mayImportModule(namespace)) { return false; } } return true; } /** * Ask whether expressions compiled under this static context are schema-aware. * They must be schema-aware if the expression is to handle typed (validated) nodes * * @return true if expressions are schema-aware */ public boolean isSchemaAware() { return executable.isSchemaAware(); } /** * Construct a RetainedStaticContext, which extracts information from this StaticContext * to provide the subset of static context information that is potentially needed * during expression evaluation * * @return a RetainedStaticContext object: either a newly created one, or one that is * reused from a previous invocation. */ public RetainedStaticContext makeRetainedStaticContext() { // The only part of the RetainedStaticContext that can change as the query module is parsed is the // "activeNamespaces", that is, namespaces declared on direct element constructors. If this is empty, // we can reuse the top-level static context on each request. if (activeNamespaces.empty()) { if (moduleStaticContext == null) { moduleStaticContext = new RetainedStaticContext(this); } return moduleStaticContext; } else { return new RetainedStaticContext(this); } } /** * 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 */ public void setPreserveNamespaces(boolean inherit) { preserveNamespaces = inherit; } /** * Get the namespace copy mode * * @return true if namespaces are preserved, false if not */ public boolean isPreserveNamespaces() { return preserveNamespaces; } /** * Set the construction mode for this module * * @param mode one of {@link net.sf.saxon.lib.Validation#STRIP}, {@link net.sf.saxon.lib.Validation#PRESERVE} */ public void setConstructionMode(int mode) { constructionMode = mode; } /** * Get the current construction mode * * @return one of {@link net.sf.saxon.lib.Validation#STRIP}, {@link net.sf.saxon.lib.Validation#PRESERVE} */ public int getConstructionMode() { return constructionMode; } /** * Set the policy for preserving boundary space * * @param preserve true if boundary space is to be preserved, false if it is to be stripped */ 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 */ 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 */ 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 */ public boolean isEmptyLeast() { return defaultEmptyLeast; } /** * Get the function library object that holds details of global functions * * @return the library of global functions */ public XQueryFunctionLibrary getGlobalFunctionLibrary() { return globalFunctionLibrary; } /** * Get the function library object that holds details of imported functions * * @return the library of imported functions */ /*@NotNull*/ public ImportedFunctionLibrary getImportedFunctionLibrary() { return (ImportedFunctionLibrary) functionLibraryList.get(importedFunctionLibraryNr); } /** * Register that this module imports a particular module namespace *

This method is intended for internal use.

* * @param uri the URI of the imported namespace. */ public void addImportedNamespace(String uri) { if (importedModuleNamespaces == null) { importedModuleNamespaces = new HashSet(5); } importedModuleNamespaces.add(uri); getImportedFunctionLibrary().addImportedNamespace(uri); } /** * Ask whether this module directly imports a particular namespace *

This method is intended for internal use.

* * @param uri the URI of the possibly-imported namespace. * @return true if the schema for the namespace has been imported */ public boolean importsNamespace(String uri) { return importedModuleNamespaces != null && importedModuleNamespaces.contains(uri); } /** * Get the QueryModule for the top-level module. This will normally be a main module, * but in the case of saxon:import-query it will be the library module that is imported into * the stylesheet * * @return the StaticQueryContext object associated with the top level module */ public QueryModule getTopLevelModule() { return topModule; } /** * Get the Executable, an object representing the compiled query and its environment. *

* This method is intended for internal use only. * * @return the Executable */ /*@Nullable*/ public Executable getExecutable() { return executable; } /** * Set the executable. *

* This method is intended for internal use only. * * @param executable the Executable */ public void setExecutable(Executable executable) { this.executable = executable; // if (!executable.isSchemaAware()) { // constructionMode = Validation.STRIP; // } } /** * Get the StaticQueryContext object containing options set up by the user * * @return the user-created StaticQueryContext object */ /*@Nullable*/ public StaticQueryContext getUserQueryContext() { return userQueryContext; } /** * Get the LocationMap, an data structure used to identify the location of compiled expressions within * the query source text. *

* This method is intended for internal use only. * * @return the LocationMap */ public Location getContainingLocation() { return moduleLocation; } /** * Set the namespace for a library module. *

* This method is for internal use only. * * @param uri the module namespace URI of the library module. Null is allowed only * for a main module, not for a library module. */ public void setModuleNamespace(/*@Nullable*/ String uri) { moduleNamespace = uri; } /** * Get the namespace of the current library module. *

* This method is intended primarily for internal use. * * @return the module namespace, or null if this is a main module */ /*@Nullable*/ public String getModuleNamespace() { return moduleNamespace; } /** * Set the location URI for a module * * @param uri the location URI */ public void setLocationURI(URI uri) { locationURI = uri; moduleLocation = new ExplicitLocation(locationURI.toString(), 1, -1); } /** * Get the location URI for a module * * @return the location URI */ /*@Nullable*/ public URI getLocationURI() { return locationURI; } /** * Get the System ID for a module * * @return the location URI */ /*@Nullable*/ public String getSystemId() { return (locationURI == null ? null : locationURI.toString()); } /** * Set the base URI for a module * * @param uri the base URI */ public void setBaseURI(String uri) { baseURI = uri; } /** * Get the base URI for a module * * @return the base URI */ public String getStaticBaseURI() { return baseURI; } /** * Get the stack frame map for global variables. *

* This method is intended for internal use. * * @return the stack frame map (a SlotManager) for global variables. */ public SlotManager getGlobalStackFrameMap() { return getPackageData().getGlobalSlotManager(); } /** * Declare a global variable. A variable must normally be declared before an expression referring * to it is compiled, but there are exceptions where a set of modules in the same namespace * import each other cyclically. Global variables are normally declared in the Query Prolog, but * they can also be predeclared using the Java API. All global variables are held in the QueryModule * for the main module. The fact that a global variable is present therefore does not mean that it * is visible: there are two additional conditions (a) the module namespace must be imported into the * module where the reference appears, and (b) the declaration must not be in the same module and textually * after the reference. *

*

Note that the same VariableDeclaration object cannot be used with more than one query. This is because * the VariableDeclaration is modified internally to hold a list of references to all the places where * the variable is used.

* * @param var the Variable declaration being declared * @throws XPathException if a static error is detected */ public void declareVariable(/*@NotNull*/ GlobalVariable var) throws XPathException { StructuredQName key = var.getVariableQName(); if (variables.get(key) != null) { GlobalVariable old = variables.get(key); if (old == var || old.getUltimateOriginalVariable() == var.getUltimateOriginalVariable()) { // do nothing } else { String oldloc = " (see line " + old.getLineNumber(); String oldSysId = old.getSystemId(); if (oldSysId != null && !oldSysId.equals(var.getSystemId())) { oldloc += " in module " + old.getSystemId(); } oldloc += ")"; XPathException err = new XPathException("Duplicate definition of global variable " + var.getVariableQName().getDisplayName() + oldloc); err.setErrorCode("XQST0049"); err.setIsStaticError(true); err.setLocation(var); throw err; } } variables.put(key, var); getPackageData().addGlobalVariable(var); final HashMap libVars = getTopLevelModule().libraryVariables; GlobalVariable old = libVars.get(key); if (old == null || old == var) { // do nothing } else { XPathException err = new XPathException("Duplicate definition of global variable " + var.getVariableQName().getDisplayName() + " (see line " + old.getLineNumber() + " in module " + old.getSystemId() + ')'); err.setErrorCode("XQST0049"); err.setIsStaticError(true); err.setLocation(var); throw err; } if (!isMainModule()) { libVars.put(key, var); } } /** * Get all global variables declared in or imported into this module * * @return a collection of global variables */ public Iterable getGlobalVariables() { return libraryVariables.values(); } /** * Fixup all references to global variables. *

* This method is for internal use by the Query Parser only. * * @param globalVariableMap a SlotManager that holds details of the assignment of slots to global variables. * @return a list containing the global variable definitions. * @throws XPathException if compiling a global variable definition fails */ public List fixupGlobalVariables(SlotManager globalVariableMap) throws XPathException { List varDefinitions = new ArrayList(20); List> iters = new ArrayList>(); iters.add(variables.values().iterator()); iters.add(libraryVariables.values().iterator()); for (Iterator iter : iters) { while (iter.hasNext()) { GlobalVariable var = iter.next(); if (!varDefinitions.contains(var)) { int slot = globalVariableMap.allocateSlotNumber(var.getVariableQName()); var.compile(getExecutable(), slot); varDefinitions.add(var); } } } return varDefinitions; } /** * Look for module cycles. This is a restriction introduced in the PR specification because of * difficulties in defining the formal semantics. *

*

[Definition: A module M1 directly depends on another module M2 (different from M1) if a * variable or function declared in M1 depends on a variable or function declared in M2.] * It is a static error [err:XQST0093] to import a module M1 if there exists a sequence * of modules M1 ... Mi ... M1 such that each module directly depends on the next module * in the sequence (informally, if M1 depends on itself through some chain of module dependencies.)

* * @param referees a Stack containing the chain of module import references leading to this * module * @param lineNumber used for diagnostics * @throws net.sf.saxon.trans.XPathException * if cycles are found */ public void lookForModuleCycles(/*@NotNull*/ Stack referees, int lineNumber) throws XPathException { if (referees.contains(this)) { int s = referees.indexOf(this); referees.push(this); String message = "Circular dependency between modules. "; for (int i = s; i < referees.size() - 1; i++) { QueryModule next = referees.get(i + 1); if (i == s) { message += "Module " + getSystemId() + " references module " + next.getSystemId(); } else { message += ", which references module " + next.getSystemId(); } } message += '.'; XPathException err = new XPathException(message); err.setErrorCode("XQST0093"); err.setIsStaticError(true); ExplicitLocation loc = new ExplicitLocation(getSystemId(), lineNumber, -1); err.setLocator(loc); throw err; } else { referees.push(this); Iterator viter = getModuleVariables(); while (viter.hasNext()) { GlobalVariable gv = viter.next(); //GlobalVariable gvc = gv.getCompiledVariable(); // will be null if the global variable is unreferenced Expression select = gv.getSelectExpression(); if (select != null) { List list = new ArrayList(10); ExpressionTool.gatherReferencedVariables(select, list); for (Binding b : list) { if (b instanceof GlobalVariable) { String uri = ((GlobalVariable) b).getSystemId(); StructuredQName qName = b.getVariableQName(); boolean synthetic = qName.hasURI(NamespaceConstant.SAXON_GENERATED_VARIABLE); if (!synthetic && uri != null && !uri.equals(getSystemId())) { QueryModule sqc = executable.getQueryModuleWithSystemId(uri, topModule); if (sqc != null) { sqc.lookForModuleCycles(referees, ((GlobalVariable) b).getLineNumber()); } } } } List fList = new ArrayList(5); ExpressionTool.gatherCalledFunctions(select, fList); for (UserFunction f : fList) { String uri = f.getSystemId(); if (uri != null && !uri.equals(getSystemId())) { QueryModule sqc = executable.getQueryModuleWithSystemId(uri, topModule); if (sqc != null) { sqc.lookForModuleCycles(referees, f.getLineNumber()); } } } } } Iterator fiter = getLocalFunctionLibrary().getFunctionDefinitions(); while (fiter.hasNext()) { XQueryFunction gf = fiter.next(); Expression body = gf.getUserFunction().getBody(); if (body != null) { List vList = new ArrayList(10); ExpressionTool.gatherReferencedVariables(body, vList); for (Binding b : vList) { if (b instanceof GlobalVariable) { String uri = ((GlobalVariable) b).getSystemId(); StructuredQName qName = b.getVariableQName(); boolean synthetic = qName.hasURI(NamespaceConstant.SAXON) && "gg".equals(qName.getPrefix()); if (!synthetic && uri != null && !uri.equals(getSystemId())) { QueryModule sqc = executable.getQueryModuleWithSystemId(uri, topModule); if (sqc != null) { sqc.lookForModuleCycles(referees, ((GlobalVariable) b).getLineNumber()); } } } } List fList = new ArrayList(10); ExpressionTool.gatherCalledFunctions(body, fList); for (UserFunction f : fList) { String uri = f.getSystemId(); if (uri != null && !uri.equals(getSystemId())) { QueryModule sqc = executable.getQueryModuleWithSystemId(uri, topModule); if (sqc != null) { sqc.lookForModuleCycles(referees, f.getLineNumber()); } } } } } referees.pop(); } } /** * Get global variables declared in this module * * @return an Iterator whose items are GlobalVariable objects */ public Iterator getModuleVariables() { return variables.values().iterator(); } /** * Check for circular definitions of global variables. *

This method is intended for internal use

* * @param compiledVars a list of {@link GlobalVariable} objects to be checked * @param globalFunctionLibrary the library of global functions * @throws net.sf.saxon.trans.XPathException * if a circularity is found */ public void checkForCircularities(/*@NotNull*/ List compiledVars, /*@NotNull*/ XQueryFunctionLibrary globalFunctionLibrary) throws XPathException { Iterator iter = compiledVars.iterator(); Stack stack = null; while (iter.hasNext()) { if (stack == null) { stack = new Stack(); } GlobalVariable gv = iter.next(); if (gv != null) { gv.lookForCycles(stack, globalFunctionLibrary); } } } /** * Perform type checking on global variables. *

This method is intended for internal use

* * @param compiledVars a list of {@link GlobalVariable} objects to be checked * @throws net.sf.saxon.trans.XPathException * if a type error occurs */ public void typeCheckGlobalVariables(/*@NotNull*/ List compiledVars) throws XPathException { ExpressionVisitor visitor = ExpressionVisitor.make(this); for (GlobalVariable compiledVar : compiledVars) { compiledVar.typeCheck(visitor); } if (isMainModule()) { GlobalContextRequirement gcr = executable.getGlobalContextRequirement(); if (gcr != null && gcr.getDefaultValue() != null) { ContextItemStaticInfo info = new ContextItemStaticInfo(AnyItemType.getInstance(), true); gcr.setDefaultValue(gcr.getDefaultValue().typeCheck(visitor, info)); } } } /** * Bind a variable used in a query to the expression in which it is declared. *

* This method is provided for use by the XQuery parser, and it should not be called by the user of * the API, or overridden, unless variables are to be declared using a mechanism other than the * declareVariable method of this class. * * @param qName the name of the variable to be bound * @return a VariableReference object representing a reference to a variable on the abstract syntac rtee of * the query. */ /*@NotNull*/ public Expression bindVariable(/*@NotNull*/ StructuredQName qName) throws XPathException { GlobalVariable var = variables.get(qName); if (var == null) { String uri = qName.getURI(); if ((uri.equals("") && isMainModule()) || uri.equals(moduleNamespace) || importsNamespace(uri)) { QueryModule main = getTopLevelModule(); var = main.libraryVariables.get(qName); if (var == null) { // If the namespace has been imported there's the possibility that // the variable declaration hasn't yet been read, because of the limited provision // for cyclic imports. In XQuery 3.0 forwards references are more generally allowed. if (getLanguageVersion() >= 30) { UndeclaredVariable uvar = undeclaredVariables.get(qName); if (uvar != null) { // second or subsequent reference to the as-yet-undeclared variable GlobalVariableReference ref = new GlobalVariableReference(qName); uvar.registerReference(ref); return ref; } else { // first reference to the as-yet-undeclared variable uvar = new UndeclaredVariable(); uvar.setPackageData(main.getPackageData()); uvar.setVariableQName(qName); GlobalVariableReference ref = new GlobalVariableReference(qName); uvar.registerReference(ref); undeclaredVariables.put(qName, uvar); return ref; } } else { XPathException err = new XPathException("Variable $" + qName.getDisplayName() + " has not been declared"); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } } else { if (var.isPrivate()) { XPathException err = new XPathException("Variable $" + qName.getDisplayName() + " is private"); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } checkImportedType(var.getRequiredType(), var); } } else { // If the namespace hasn't been imported then we might as well throw the error right away XPathException err = new XPathException("Variable $" + qName.getDisplayName() + " has not been declared"); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } } else { if (var.isPrivate() && (var.getSystemId() == null || !var.getSystemId().equals(getSystemId()))) { String message = "Variable $" + qName.getDisplayName() + " is private"; if (var.getSystemId() == null) { message += " (no base URI known)"; } XPathException err = new XPathException(message, "XPST0008"); err.setIsStaticError(true); throw err; } } GlobalVariableReference vref = new GlobalVariableReference(qName); var.registerReference(vref); return vref; } /** * Get the function library containing all the in-scope functions available in this static * context (that is, the functions available in this query module). *

* This method is provided for use by advanced applications. * The details of the interface are subject to change. * * @return the FunctionLibrary used. For XQuery, this will always be a FunctionLibraryList. * @see net.sf.saxon.functions.FunctionLibraryList */ public FunctionLibrary getFunctionLibrary() { return functionLibraryList; } /** * Get the functions declared locally within this module * * @return a FunctionLibrary object containing the function declarations */ /*@NotNull*/ public XQueryFunctionLibrary getLocalFunctionLibrary() { return (XQueryFunctionLibrary) functionLibraryList.get(localFunctionLibraryNr); } /** * Register a user-defined XQuery function. *

* This method is intended for internal use only. * * @param function the function being declared * @throws net.sf.saxon.trans.XPathException * if an error occurs, for example * a duplicate function name */ public void declareFunction(/*@NotNull*/ XQueryFunction function) throws XPathException { Configuration config = getConfiguration(); if (function.getNumberOfArguments() == 1) { StructuredQName name = function.getFunctionName(); SchemaType t = config.getSchemaType(name); if (t != null && t.isAtomicType()) { XPathException err = new XPathException("Function name " + function.getDisplayName() + " clashes with the name of the constructor function for an atomic type"); err.setErrorCode("XQST0034"); err.setIsStaticError(true); throw err; } } XQueryFunctionLibrary local = getLocalFunctionLibrary(); local.declareFunction(function); //if (!function.isPrivate()) { QueryModule main = getTopLevelModule(); main.globalFunctionLibrary.declareFunction(function); //} } /** * Bind function calls that could not be bound when first encountered. These * will either be forwards references to functions declared later in the same query module, * or in modules that are being imported recursively, or errors. *

* This method is for internal use only. * * @throws net.sf.saxon.trans.XPathException * if a function call refers to a function that has * not been declared */ public void bindUnboundFunctionCalls() throws XPathException { UnboundFunctionLibrary lib = (UnboundFunctionLibrary) functionLibraryList.get(unboundFunctionLibraryNr); lib.bindUnboundFunctionReferences(functionLibraryList, getConfiguration()); } /** * Fixup all references to global functions. This method is called * on completion of query parsing. Each XQueryFunction is required to * bind all references to that function to the object representing the run-time * executable code of the function. *

* This method is for internal use only. It is called only on the StaticQueryContext for the main * query body (not for library modules). * * @throws net.sf.saxon.trans.XPathException * if an error occurs */ public void fixupGlobalFunctions() throws XPathException { globalFunctionLibrary.fixupGlobalFunctions(this); } /** * Optimize the body of all global functions. *

* This method is for internal use only. It is called only on the StaticQueryContext for the main * query body (not for library modules). * * @throws net.sf.saxon.trans.XPathException * if an error occurs during optimization */ public void optimizeGlobalFunctions() throws XPathException { globalFunctionLibrary.optimizeGlobalFunctions(); } /** * Output "explain" information about each declared function. *

* This method is intended primarily for internal use. * * @param out the expression presenter used to display the output */ public void explainGlobalFunctions(ExpressionPresenter out) throws XPathException{ globalFunctionLibrary.explainGlobalFunctions(out); } /** * Get the function with a given name and arity. This method is provided so that XQuery functions * can be called directly from a Java application. Note that there is no type checking or conversion * of arguments when this is done: the arguments must be provided in exactly the form that the function * signature declares them. * * @param uri the uri of the function name * @param localName the local part of the function name * @param arity the number of arguments. * @return the user-defined function, or null if no function with the given name and arity can be located * @since 8.4 */ public UserFunction getUserDefinedFunction(String uri, String localName, int arity) { return globalFunctionLibrary.getUserDefinedFunction(uri, localName, arity); } /** * Bind unbound variables (these are typically variables that reference another module * participating in a same-namespace cycle, since local forwards references are not allowed) * * @throws net.sf.saxon.trans.XPathException * if an error occurs, for example if the * variable reference cannot be resolved or if the variable is private */ public void bindUnboundVariables() throws XPathException { for (UndeclaredVariable uv : undeclaredVariables.values()) { StructuredQName qName = uv.getVariableQName(); GlobalVariable var = variables.get(qName); if (var == null) { String uri = qName.getURI(); if (importsNamespace(uri)) { QueryModule main = getTopLevelModule(); var = main.libraryVariables.get(qName); } } if (var == null) { XPathException err = new XPathException("Unresolved reference to variable $" + uv.getVariableQName().getDisplayName()); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } else if (var.isPrivate() && !var.getSystemId().equals(getSystemId())) { XPathException err = new XPathException("Cannot reference a private variable in a different module"); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } else { checkImportedType(var.getRequiredType(), var); uv.transferReferences(var); } } } /** * Add an imported schema to this static context. A query module can reference * types in a schema provided two conditions are satisfied: the schema containing those * types has been loaded into the Configuration, and the target namespace has been imported * by this query module. This method achieves the second of these conditions. It does not * cause the schema to be loaded. *

* * @param targetNamespace The target namespace of the schema to be added * @param baseURI The base URI against which the locationURIs are to be absolutized * @param locationURIs a list of strings containing the absolutized URIs of the "location hints" supplied * for this schema * @since 8.4 */ public void addImportedSchema(String targetNamespace, String baseURI, /*@NotNull*/ List locationURIs) { if (importedSchemata == null) { importedSchemata = new HashSet(5); } importedSchemata.add(targetNamespace); HashMap> loadedSchemata = getTopLevelModule().loadedSchemata; if (loadedSchemata == null) { loadedSchemata = new HashMap>(5); getTopLevelModule().loadedSchemata = loadedSchemata; } HashSet entries = loadedSchemata.get(targetNamespace); if (entries == null) { entries = new HashSet(locationURIs.size()); loadedSchemata.put(targetNamespace, entries); } for (String relative : locationURIs) { try { URI abs = ResolveURI.makeAbsolute(relative, baseURI); entries.add(abs.toString()); } catch (URISyntaxException e) { // ignore the URI if it's not valid } } } /** * Get the schema for a given namespace, if it has been imported * * @param namespace The namespace of the required schema. Supply "" for * a no-namespace schema. * @return The schema if found, or null if not found. * @since 8.4 */ public boolean isImportedSchema(String namespace) { return importedSchemata != null && importedSchemata.contains(namespace); } /** * Get the set of imported schemas * * @return a Set, the set of URIs representing the names of imported schemas */ /*@Nullable*/ public Set getImportedSchemaNamespaces() { if (importedSchemata == null) { return Collections.emptySet(); } else { return importedSchemata; } } /** * Report a static error in the query (via the registered ErrorListener) * * @param err the error to be signalled */ public void reportStaticError(/*@NotNull*/ XPathException err) { if (!err.hasBeenReported()) { if (userQueryContext == null) { config.getErrorListener().fatalError(err); } else { userQueryContext.getErrorListener().fatalError(err); } err.setHasBeenReported(true); } } /** * Check that all the types used in the signature of an imported function * are available in the module of the caller of the function * * @param fd the declaration of the imported function * @throws XPathException if an error is found */ public void checkImportedFunctionSignature(/*@NotNull*/ XQueryFunction fd) throws XPathException { checkImportedType(fd.getResultType(), fd); for (int a = 0; a < fd.getNumberOfArguments(); a++) { SequenceType argType = fd.getArgumentTypes()[a]; checkImportedType(argType, fd); } } /** * Check that a SequenceType used in the definition of an imported variable or function * is available in the importing module * * @param importedType the type that is to be checked * @param declaration the containing query or function definition * @throws net.sf.saxon.trans.XPathException * if an error is fonnd. */ public void checkImportedType(/*@NotNull*/ SequenceType importedType, /*@NotNull*/ final Declaration declaration) throws XPathException { ItemType type = importedType.getPrimaryType(); type.visitNamedSchemaComponents(new SchemaComponentVisitor() { public void visitSchemaComponent(/*@NotNull*/ SchemaComponent component) throws XPathException { if (component instanceof SchemaDeclaration) { StructuredQName f = ((SchemaDeclaration) component).getComponentName(); checkSchemaNamespaceImported(f, declaration); } else if (component instanceof SchemaType) { StructuredQName f = ((SchemaType) component).getStructuredQName(); checkSchemaNamespaceImported(f, declaration); } } }); } /** * Construct a dynamic context for early evaluation of constant subexpressions * * @return a dynamic context object */ /*@NotNull*/ public XPathContext makeEarlyEvaluationContext() { return new EarlyEvaluationContext(getConfiguration()); } /** * 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 */ /*@Nullable*/ public String getDefaultCollationName() { if (defaultCollationName == null) { defaultCollationName = NamespaceConstant.CODEPOINT_COLLATION_URI; } return defaultCollationName; } /** * Set the name of the default collation * @param collation the URI of the default collation */ public void setDefaultCollationName(String collation) { defaultCollationName = collation; } /** * Register a namespace that is explicitly declared in the prolog of the query module. * * @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. * @throws net.sf.saxon.trans.XPathException * if the declaration is invalid */ public void declarePrologNamespace(/*@Nullable*/ String prefix, /*@Nullable*/ String uri) throws XPathException { if (prefix == null) { throw new NullPointerException("Null prefix supplied to declarePrologNamespace()"); } if (uri == null) { throw new NullPointerException("Null namespace URI supplied to declarePrologNamespace()"); } if ((prefix.equals("xml") != uri.equals(NamespaceConstant.XML))) { XPathException err = new XPathException("Invalid declaration of the XML namespace"); err.setErrorCode("XQST0070"); err.setIsStaticError(true); throw err; } if (explicitPrologNamespaces.get(prefix) != null) { XPathException err = new XPathException("Duplicate declaration of namespace prefix \"" + prefix + '"'); err.setErrorCode("XQST0033"); err.setIsStaticError(true); throw err; } else { explicitPrologNamespaces.put(prefix, uri); } } /** * Declare an active namespace, that is, a namespace which as well as affecting the static * context of the query, will also be copied to the result tree when element constructors * are evaluated. When searching for a prefix-URI binding, active namespaces are searched * first, then passive namespaces. Active namespaces are later undeclared (in reverse sequence) * using {@link #undeclareNamespace()}. *

* This method is intended for internal use only. * * @param prefix the namespace prefix * @param uri the namespace URI */ public void declareActiveNamespace(/*@Nullable*/ String prefix, /*@Nullable*/ String uri) { if (prefix == null) { throw new NullPointerException("Null prefix supplied to declareActiveNamespace()"); } if (uri == null) { throw new NullPointerException("Null namespace URI supplied to declareActiveNamespace()"); } ActiveNamespace entry = new ActiveNamespace(); entry.prefix = prefix; entry.uri = uri; activeNamespaces.push(entry); // if (prefix.length() == 0) { // defaultElementNamespace = uri; // } } /** * Undeclare the most recently-declared active namespace. This method is called * when a namespace declaration goes out of scope (while processing an element end tag). * It is NOT called when an XML 1.1-style namespace undeclaration is encountered. *

* This method is intended for internal use only. * * @see #declareActiveNamespace(String, String) */ public void undeclareNamespace() { activeNamespaces.pop(); } /** * Return a NamespaceResolver which is "live" in the sense that, as the parse proceeeds, * it always uses the namespaces declarations in scope at the relevant time * @return a live NamespaceResolver */ public NamespaceResolver getLiveNamespaceResolver() { return new NamespaceResolver() { /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". The default * namespace is a property of the NamespaceResolver; in general it corresponds to * the "default namespace for elements and types", but that cannot be assumed. * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ public String getURIForPrefix(String prefix, boolean useDefault) { return checkURIForPrefix(prefix); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate * * @return an iterator over all the prefixes for which a namespace binding exists, including * the zero-length string to represent the null/absent prefix if it is bound */ public Iterator iteratePrefixes() { return getNamespaceResolver().iteratePrefixes(); } }; } /** * Get the URI for a prefix if there is one, return null if not. * This method is used by the XQuery parser to resolve namespace prefixes. *

* This method is intended primarily for internal use. * * @param prefix The prefix. Supply "" to obtain the default namespace for elements and types. * @return the corresponding namespace URI, or null if the prefix has not * been declared. If the prefix is "" and the default namespace is the non-namespace, * return "". */ /*@Nullable*/ public String checkURIForPrefix(/*@NotNull*/ String prefix) { // Search the active namespaces first, then the passive ones. if (activeNamespaces != null) { for (int i = activeNamespaces.size() - 1; i >= 0; i--) { if ((activeNamespaces.get(i)).prefix.equals(prefix)) { String uri = (activeNamespaces.get(i)).uri; if (uri.equals("") && !prefix.equals("")) { // the namespace is undeclared return null; } return uri; } } } if (prefix.isEmpty()) { return defaultElementNamespace; } String uri = explicitPrologNamespaces.get(prefix); if (uri != null) { // A zero-length URI means the prefix was undeclared in the prolog, and we mustn't look elsewhere return (uri.isEmpty() ? null : uri); } if (userQueryContext != null) { uri = userQueryContext.getNamespaceForPrefix(prefix); if (uri != null) { return uri; } NamespaceResolver externalResolver = userQueryContext.getExternalNamespaceResolver(); if (externalResolver != null) { return externalResolver.getURIForPrefix(prefix, true); } } return null; } /** * Get the default XPath namespace for elements and types. Note that this is not necessarily * the default namespace declared in the query prolog; within an expression, it may change in response * to namespace declarations on element constructors. * * @return the default namespace, or {@link NamespaceConstant#NULL} for the non-namespace */ /*@Nullable*/ public String getDefaultElementNamespace() { return checkURIForPrefix(""); } /** * Set the default element namespace as declared in the query prolog * * @param uri the default namespace for elements and types */ public void setDefaultElementNamespace(String uri) { defaultElementNamespace = uri; } /** * Get the default function namespace * * @return the default namespace for function names */ public String getDefaultFunctionNamespace() { return defaultFunctionNamespace; } /** * Set the default function namespace * * @param uri the default namespace for functions */ public void setDefaultFunctionNamespace(String uri) { defaultFunctionNamespace = uri; } /** * Set the revalidation mode. This is used only if XQuery Updates are in use, in other cases * the value is ignored. * * @param mode the revalidation mode. This must be one of {@link Validation#STRICT}, * {@link Validation#LAX}, or {@link Validation#SKIP} */ public void setRevalidationMode(int mode) { if (mode == Validation.STRICT || mode == Validation.LAX || mode == Validation.SKIP) { revalidationMode = mode; } else { throw new IllegalArgumentException("Invalid mode " + mode); } } /** * Get the revalidation mode. This is used only if XQuery Updates are in use, in other cases * the value is ignored. * * @return the revalidation mode. This will be one of {@link Validation#STRICT}, * {@link Validation#LAX}, or {@link Validation#SKIP} */ public int getRevalidationMode() { return revalidationMode; } /** * Get an array containing the namespace codes of all active namespaces. *

* This method is for internal use only. * * @return an array of namespace bindings (prefix/uri pairs). */ /*@NotNull*/ public NamespaceBinding[] getActiveNamespaceCodes() { if (activeNamespaces == null) { return NamespaceBinding.EMPTY_ARRAY; } NamespaceBinding[] nsBindings = new NamespaceBinding[activeNamespaces.size()]; int used = 0; HashSet prefixes = new HashSet(10); for (int n = activeNamespaces.size() - 1; n >= 0; n--) { ActiveNamespace an = activeNamespaces.get(n); if (!prefixes.contains(an.prefix)) { prefixes.add(an.prefix); nsBindings[used++] = new NamespaceBinding(an.prefix, an.uri); } } if (used < nsBindings.length) { NamespaceBinding[] nb2 = new NamespaceBinding[used]; System.arraycopy(nsBindings, 0, nb2, 0, used); nsBindings = nb2; } return nsBindings; } /** * Get a copy of the Namespace Context. This method is used internally * by the query parser when a construct is encountered that needs * to save the namespace context for use at run-time. Note that unlike other implementations of * StaticContext, the state of the QueryModule changes as the query is parsed, with different namespaces * in scope at different times. It's therefore necessary to compute the whole namespace context each time. *

* This method is for internal use only. */ /*@NotNull*/ public NamespaceResolver getNamespaceResolver() { List externalNamespaceCodes = null; NamespaceResolver externalResolver = userQueryContext.getExternalNamespaceResolver(); if (externalResolver != null) { externalNamespaceCodes = new ArrayList(); Iterator iter = externalResolver.iteratePrefixes(); while (iter.hasNext()) { String prefix = (String) iter.next(); String uri = externalResolver.getURIForPrefix(prefix, true); NamespaceBinding nscode = new NamespaceBinding(prefix, uri); externalNamespaceCodes.add(nscode); } } HashMap userDeclaredNamespaces = userQueryContext.getUserDeclaredNamespaces(); List nsBindings = new ArrayList(); for (Map.Entry e : userDeclaredNamespaces.entrySet()) { nsBindings.add(new NamespaceBinding(e.getKey(), e.getValue())); } for (Map.Entry e : explicitPrologNamespaces.entrySet()) { nsBindings.add(new NamespaceBinding(e.getKey(), e.getValue())); } if (defaultElementNamespace.length() != 0) { nsBindings.add(new NamespaceBinding("", defaultElementNamespace)); } nsBindings.addAll(Arrays.asList(getActiveNamespaceCodes())); if (externalNamespaceCodes != null) { for (NamespaceBinding externalNamespaceCode : externalNamespaceCodes) { nsBindings.add(externalNamespaceCode); } } return new SavedNamespaceContext(nsBindings); } /** * 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. Note that this is the same for all modules. * @since 9.3 */ public ItemType getRequiredContextItemType() { return requiredContextItemType; } /** * Get a DecimalFormatManager to resolve the names of decimal formats used in calls * to the format-number() function. * * @return the decimal format manager for this static context, or null if named decimal * formats are not supported in this environment. */ /*@Nullable*/ public DecimalFormatManager getDecimalFormatManager() { if (decimalFormatManager == null) { decimalFormatManager = new DecimalFormatManager(Configuration.XQUERY, languageVersion); } return decimalFormatManager; } /** * Issue a compile-time warning. This method is used during XQuery expression compilation to * output warning conditions. *

* This method is intended for internal use only. */ public void issueWarning(String s, Location locator) { XPathException err = new XPathException(s); err.setLocator(locator); if (userQueryContext != null) { userQueryContext.getErrorListener().warning(err); } else { getConfiguration().getErrorListener().warning(err); } } /** * Determine whether Backwards Compatible Mode is used * * @return false; XPath 1.0 compatibility mode is not supported in XQuery * @since 8.4 */ public boolean isInBackwardsCompatibleMode() { return false; } /** * Ask whether the query module is allowed to be updating * * @return true if the query module is allowed to use the XQuery Update facility * @since 9.1 */ public boolean isUpdating() { return isUpdating; } /** * Get the language version supported * * @return the language version (currently "1.0" or "3.0" or "3.1") * @since 9.2; changed in 9.3 to return a DecimalValue instead of a String; changed in 9.7 to return an * int (30 means "3.0", and so on) */ public int getLanguageVersion() { return languageVersion; } /** * Get the XPath language level supported * * @return 20 (=2.0) if XQuery 1.0 is enabled, otherwise the XQuery version */ public int getXPathVersion() { return languageVersion == 10 ? 20 : languageVersion; } /** * Get the CodeInjector if one is in use * * @return the code injector if there is one */ public CodeInjector getCodeInjector() { return codeInjector; } /** * Check that the namespace of a given name is the namespace of an imported schema * * @param componentName the "given name" * @param declaration the declaration of the variable or function that has this given name * @throws net.sf.saxon.trans.XPathException * (error XQST0036) if the namespace is not present in a schema * imported by the importing query module */ private void checkSchemaNamespaceImported(StructuredQName componentName, /*@NotNull*/ Declaration declaration) throws XPathException { String uri = componentName.getURI(); if (!uri.equals(NamespaceConstant.SCHEMA) && !uri.equals(NamespaceConstant.ANONYMOUS) && !uri.equals(NamespaceConstant.JAVA_TYPE) && !isImportedSchema(uri)) { String msg = "Schema component " + componentName.getDisplayName() + " used in "; if (declaration instanceof GlobalVariable) { msg += "declaration of imported variable " + ((GlobalVariable) declaration).getVariableQName().getDisplayName(); } else { msg += "signature of imported function " + ((XQueryFunction) declaration).getDisplayName(); } msg += " is not declared in any schema imported by "; String module = getModuleNamespace(); if (module == null) { msg += "the main query module"; } else { msg += "query module " + module; } XPathException err = new XPathException(msg); err.setErrorCode("XQST0036"); err.setIsStaticError(true); err.setLocator(declaration); throw err; } } /** * Get the KeyManager, containing definitions of keys available for use. * * @return the KeyManager. This is used to resolve key names, both explicit calls * on key() used in XSLT, and system-generated calls on key() which may * also appear in XQuery and XPath */ public KeyManager getKeyManager() { KeyManager mgr = executable.getKeyManager(); packageData.setKeyManager(mgr); return mgr; } /** * Inner class containing information about an active namespace entry */ private static class ActiveNamespace { /*@Nullable*/ public String prefix; /*@Nullable*/ public String uri; } }