/lib/saxonB/net/sf/saxon/query/QueryParser.java
Java | 3715 lines | 2775 code | 279 blank | 661 comment | 744 complexity | f0fe8568f3211e519f536f98bb54b80a MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- package net.sf.saxon.query;
-
- import net.sf.saxon.Configuration;
- import net.sf.saxon.trans.Err;
- import net.sf.saxon.Platform;
- import net.sf.saxon.charcode.UTF16;
- import net.sf.saxon.event.PipelineConfiguration;
- import net.sf.saxon.expr.*;
- import net.sf.saxon.functions.*;
- import net.sf.saxon.instruct.*;
- import net.sf.saxon.om.*;
- import net.sf.saxon.pattern.NodeTest;
- import net.sf.saxon.sort.*;
- import net.sf.saxon.style.AttributeValueTemplate;
- import net.sf.saxon.sxpath.IndependentContext;
- import net.sf.saxon.trace.Location;
- import net.sf.saxon.trans.XPathException;
- import net.sf.saxon.type.*;
- import net.sf.saxon.value.*;
-
- import javax.xml.transform.OutputKeys;
- import javax.xml.transform.TransformerConfigurationException;
- import javax.xml.transform.stream.StreamSource;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.util.*;
- import java.util.regex.Pattern;
- import java.io.IOException;
-
- /**
- * This class defines extensions to the XPath parser to handle the additional
- * syntax supported in XQuery
- */
- public class QueryParser extends ExpressionParser {
-
- private boolean memoFunction = false;
- private boolean disableCycleChecks = false;
-
- private int errorCount = 0;
- private XPathException firstError = null;
-
- protected Executable executable;
-
- private boolean foundCopyNamespaces = false;
- private boolean foundBoundarySpaceDeclaration = false;
- private boolean foundOrderingDeclaration = false;
- private boolean foundEmptyOrderingDeclaration = false;
- private boolean foundDefaultCollation = false;
- private boolean foundConstructionDeclaration = false;
- private boolean foundDefaultFunctionNamespace = false;
- private boolean foundDefaultElementNamespace = false;
- private boolean foundBaseURIDeclaration = false;
- private boolean preambleProcessed = false;
-
- public Set importedModules = new HashSet(5);
- List namespacesToBeSealed = new ArrayList(10);
- List schemaImports = new ArrayList(5);
- List moduleImports = new ArrayList(5);
-
- private Expression defaultValue = null;
-
- /**
- * Constructor for internal use: this class should be instantiated via the QueryModule
- */
-
- public QueryParser() {
- }
-
- /**
- * Create an XQueryExpression
- * @param query the source text of the query
- * @param staticContext the static context of the query
- * @param config the Saxon configuration
- * @return the compiled XQuery expression
- */
-
- public XQueryExpression makeXQueryExpression(String query,
- QueryModule staticContext,
- Configuration config) throws XPathException {
- try {
- if (config.getXMLVersion() == Configuration.XML10) {
- query = normalizeLineEndings10(query);
- } else {
- query = normalizeLineEndings11(query);
- }
- Executable exec = staticContext.getExecutable();
- if (exec == null) {
- exec = new Executable(config);
- exec.setHostLanguage(Configuration.XQUERY);
- staticContext.setExecutable(exec);
- }
-
- Properties outputProps = new Properties();
- outputProps.setProperty(OutputKeys.METHOD, "xml");
- outputProps.setProperty(OutputKeys.INDENT, "yes");
- exec.setDefaultOutputProperties(outputProps);
-
- exec.setLocationMap(new LocationMap());
- exec.setFunctionLibrary(new ExecutableFunctionLibrary(config));
- // this will be changed later
- setExecutable(exec);
-
- Expression exp = parseQuery(query, 0, Token.EOF, staticContext);
- int loc = env.getLocationMap().allocateLocationId(env.getSystemId(), 1);
- exp.setContainer(new TemporaryContainer(staticContext.getLocationMap(), loc));
- //staticContext.bindUnboundFunctionCalls();
- exec.fixupQueryModules(staticContext);
-
- // Check for cyclic dependencies among the modules
-
- if (!disableCycleChecks) {
- Iterator miter = exec.getQueryLibraryModules();
- while (miter.hasNext()) {
- QueryModule module = (QueryModule)miter.next();
- module.lookForModuleCycles(new Stack(), 1);
- }
- }
-
- // Make the XQueryexpression object
-
- XQueryExpression queryExp = new XQueryExpression(exp, exec, staticContext, config);
- //exp = queryExp.getExpression();
-
- // Make the function library that's available at run-time (e.g. for saxon:evaluate()). This includes
- // all user-defined functions regardless of which module they are in
-
- FunctionLibrary userlib = exec.getFunctionLibrary();
- FunctionLibraryList lib = new FunctionLibraryList();
- lib.addFunctionLibrary(
- SystemFunctionLibrary.getSystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY));
- lib.addFunctionLibrary(config.getVendorFunctionLibrary());
- lib.addFunctionLibrary(new ConstructorFunctionLibrary(config));
- if (config.isAllowExternalFunctions()) {
- Configuration.getPlatform().addFunctionLibraries(lib, config, Configuration.XQUERY);
- }
- lib.addFunctionLibrary(userlib);
- exec.setFunctionLibrary(lib);
-
- return queryExp;
- } catch (XPathException e) {
- if (!e.hasBeenReported()) {
- reportError(e);
- }
- throw e;
- }
- }
-
- /**
- * Normalize line endings in the source query, according to the XML 1.1 rules.
- * @param in the input query
- * @return the query with line endings normalized
- */
-
- private static String normalizeLineEndings11(String in) {
- if (in.indexOf((char)0xa) < 0 && in.indexOf((char)0x85) < 0 && in.indexOf((char)0x2028) < 0) {
- return in;
- }
- FastStringBuffer sb = new FastStringBuffer(in.length());
- for (int i = 0; i < in.length(); i++) {
- char ch = in.charAt(i);
- switch (ch) {
- case 0x85:
- case 0x2028:
- sb.append((char)0xa);
- break;
- case 0xd:
- if (i < in.length() - 1 && (in.charAt(i + 1) == (char)0xa || in.charAt(i + 1) == (char)0x85)) {
- sb.append((char)0xa);
- i++;
- } else {
- sb.append((char)0xa);
- }
- break;
- default:
- sb.append(ch);
- }
- }
- return sb.toString();
- }
-
- /**
- * Normalize line endings in the source query, according to the XML 1.0 rules.
- * @param in the input query
- * @return the query text with line endings normalized
- */
-
- private static String normalizeLineEndings10(String in) {
- if (in.indexOf((char)0xa) < 0) {
- return in;
- }
- FastStringBuffer sb = new FastStringBuffer(in.length());
- for (int i = 0; i < in.length(); i++) {
- char ch = in.charAt(i);
- switch (ch) {
- case 0xd:
- if (i < in.length() - 1 && in.charAt(i + 1) == (char)0xa) {
- sb.append((char)0xa);
- i++;
- } else {
- sb.append((char)0xa);
- }
- break;
- default:
- sb.append(ch);
- }
- }
- return sb.toString();
- }
-
-
- /**
- * Get the executable containing this expression.
- * @return the executable
- */
-
- public Executable getExecutable() {
- return executable;
- }
-
- /**
- * Set the executable used for this query expression
- * @param exec the executable
- */
-
- public void setExecutable(Executable exec) {
- executable = exec;
- }
-
- /**
- * Disable checks for certain kinds of cycle. This is equivalent to
- * <p><code>declare option saxon:allow-cycles "true"</code></p>
- * @param disable true if checks for import cycles are to be suppressed, that is,
- * if cycles should be allowed
- */
-
- public void setDisableCycleChecks(boolean disable) {
- disableCycleChecks = disable;
- }
-
-
- /**
- * Parse a top-level Query.
- * Prolog? Expression
- *
- * @param queryString The text of the query
- * @param start Offset of the start of the query
- * @param terminator Token expected to follow the query (usually Token.EOF)
- * @param env The static context
- * @return the Expression object that results from parsing
- * @throws net.sf.saxon.trans.XPathException
- * if the expression contains a syntax error
- */
-
- private Expression parseQuery(String queryString,
- int start,
- int terminator,
- QueryModule env) throws XPathException {
- this.env = env;
- nameChecker = env.getConfiguration().getNameChecker();
- language = XQUERY;
- t = new Tokenizer();
- try {
- t.tokenize(queryString, start, -1, 1);
- } catch (XPathException err) {
- grumble(err.getMessage());
- }
- parseVersionDeclaration();
- parseProlog();
- processPreamble();
-
- Expression exp = parseExpression();
-
- // Diagnostic code - show the expression before any optimizations
- // ExpressionPresenter ep = ExpressionPresenter.make(env.getConfiguration());
- // exp.explain(ep);
- // ep.close();
- // End of diagnostic code
-
- if (t.currentToken != terminator) {
- grumble("Unexpected token " + currentTokenDisplay() + " beyond end of query");
- }
- setLocation(exp);
- if (errorCount == 0) {
- return exp;
- } else {
- XPathException err = new XPathException("One or more static errors were reported during query analysis");
- err.setHasBeenReported();
- err.setErrorCode(firstError.getErrorCodeLocalPart()); // largely for the XQTS test driver
- throw err;
- }
- }
-
- /**
- * Parse a library module.
- * Prolog? Expression
- *
- * @param queryString The text of the library module.
- * @param env The static context. The result of parsing
- * a library module is that the static context is populated with a set of function
- * declarations and variable declarations. Each library module must have its own
- * static context objext.
- * @throws XPathException if the expression contains a syntax error
- */
-
- public final void parseLibraryModule(String queryString, QueryModule env)
- throws XPathException {
- this.env = env;
- nameChecker = env.getConfiguration().getNameChecker();
- executable = env.getExecutable();
- t = new Tokenizer();
- try {
- t.tokenize(queryString, 0, -1, 1);
- } catch (XPathException err) {
- grumble(err.getMessage());
- }
- parseVersionDeclaration();
- parseModuleDeclaration();
- parseProlog();
- processPreamble();
- if (t.currentToken != Token.EOF) {
- grumble("Unrecognized content found after the variable and function declarations in a library module");
- }
- if (errorCount != 0) {
- XPathException err = new XPathException("Static errors were reported in the imported library module");
- err.setErrorCode(firstError.getErrorCodeLocalPart());
- throw err;
- }
- }
-
- /**
- * Report a static error
- *
- * @param message the error message
- * @throws XPathException always thrown: an exception containing the
- * supplied message
- */
-
- protected void grumble(String message, String errorCode) throws XPathException {
- String s = t.recentText();
- ExpressionLocation loc = makeLocator();
- String prefix = getLanguage() +
- ("XPST0003".equals(errorCode) ? " syntax error " : " static error ") +
- (message.startsWith("...") ? "near" : "in") +
- " #" + s + "#:\n ";
- XPathException exception = new XPathException(prefix + message);
- exception.setErrorCode(errorCode);
- exception.setLocator(loc);
- reportError(exception);
- }
-
- private void reportError(XPathException exception) throws XPathException {
- errorCount++;
- if (firstError == null) {
- firstError = exception;
- }
- ((QueryModule)env).reportFatalError(exception);
- throw exception;
- }
-
- /**
- * Make a Locator object representing the current parsing location
- *
- * @return a Locator
- */
- private ExpressionLocation makeLocator() {
- int line = t.getLineNumber();
- int column = t.getColumnNumber();
-
- ExpressionLocation loc = new ExpressionLocation();
- loc.setSystemId(env.getSystemId());
- loc.setLineNumber(line);
- loc.setColumnNumber(column);
- return loc;
- }
-
- private static Pattern encNamePattern = Pattern.compile("^[A-Za-z]([A-Za-z0-9._\\x2D])*$");
-
- /**
- * Parse the version declaration if present.
- *
- * @throws XPathException in the event of a syntax error.
- */
- private void parseVersionDeclaration() throws XPathException {
- if (t.currentToken == Token.XQUERY_VERSION) {
- nextToken();
- expect(Token.STRING_LITERAL);
- if (!("1.0".equals(t.currentTokenValue))) {
- grumble("XQuery version must be 1.0", "XQST0031");
- }
- nextToken();
- if ("encoding".equals(t.currentTokenValue)) {
- nextToken();
- expect(Token.STRING_LITERAL);
- if (!encNamePattern.matcher(t.currentTokenValue).matches()) {
- grumble("Encoding name contains invalid characters", "XQST0087");
- }
- // we ignore the encoding now: it was handled earlier, while decoding the byte stream
- nextToken();
- }
- expect(Token.SEMICOLON);
- nextToken();
- }
- }
-
- /**
- * In a library module, parse the module declaration
- * Syntax: <"module" "namespace"> prefix "=" uri ";"
- *
- * @throws XPathException in the event of a syntax error.
- */
-
- private void parseModuleDeclaration() throws XPathException {
- expect(Token.MODULE_NAMESPACE);
- nextToken();
- expect(Token.NAME);
- String prefix = t.currentTokenValue;
- nextToken();
- expect(Token.EQUALS);
- nextToken();
- expect(Token.STRING_LITERAL);
- String uri = URILiteral(t.currentTokenValue);
- checkProhibitedPrefixes(prefix, uri);
- if (uri.length()==0) {
- grumble("Module namespace cannot be \"\"", "XQST0088");
- uri = "http://saxon.fallback.namespace/"; // for error recovery
- }
- nextToken();
- expect(Token.SEMICOLON);
- nextToken();
- try {
- ((QueryModule)env).declarePrologNamespace(prefix, uri);
- } catch (XPathException err) {
- err.setLocator(makeLocator());
- reportError(err);
- }
- ((QueryModule)env).setModuleNamespace(uri);
- }
-
- /**
- * Parse the query prolog. This method, and its subordinate methods which handle
- * individual declarations in the prolog, cause the static context to be updated
- * with relevant context information. On exit, t.currentToken is the first token
- * that is not recognized as being part of the prolog.
- *
- * @throws XPathException in the event of a syntax error.
- */
-
- private void parseProlog() throws XPathException {
- //boolean allowSetters = true;
- boolean allowModuleDecl = true;
- boolean allowDeclarations = true;
-
- while (true) {
- try {
- if (t.currentToken == Token.MODULE_NAMESPACE) {
- String uri = ((QueryModule)env).getModuleNamespace();
- if (uri == null) {
- grumble("Module declaration must not be used in a main module");
- } else {
- grumble("Module declaration appears more than once");
- }
- if (!allowModuleDecl) {
- grumble("Module declaration must precede other declarations in the query prolog");
- }
- }
- allowModuleDecl = false;
- switch (t.currentToken) {
- case Token.DECLARE_NAMESPACE:
- if (!allowDeclarations) {
- grumble("Namespace declarations cannot follow variables, functions, or options");
- }
- //allowSetters = false;
- parseNamespaceDeclaration();
- break;
- case Token.DECLARE_DEFAULT:
- nextToken();
- expect(Token.NAME);
- if (t.currentTokenValue.equals("element")) {
- if (!allowDeclarations) {
- grumble("Namespace declarations cannot follow variables, functions, or options");
- }
- //allowSetters = false;
- parseDefaultElementNamespace();
- } else if (t.currentTokenValue.equals("function")) {
- if (!allowDeclarations) {
- grumble("Namespace declarations cannot follow variables, functions, or options");
- }
- //allowSetters = false;
- parseDefaultFunctionNamespace();
- } else if (t.currentTokenValue.equals("collation")) {
- if (!allowDeclarations) {
- grumble("Collation declarations must appear earlier in the prolog");
- }
- parseDefaultCollation();
- } else if (t.currentTokenValue.equals("order")) {
- if (!allowDeclarations) {
- grumble("Order declarations must appear earlier in the prolog");
- }
- parseDefaultOrder();
- } else {
- grumble("After 'declare default', expected 'element', 'function', or 'collation'");
- }
- break;
- case Token.DECLARE_BOUNDARY_SPACE:
- if (!allowDeclarations) {
- grumble("'declare boundary-space' must appear earlier in the query prolog");
- }
- parseBoundarySpaceDeclaration();
- break;
- case Token.DECLARE_ORDERING:
- if (!allowDeclarations) {
- grumble("'declare ordering' must appear earlier in the query prolog");
- }
- parseOrderingDeclaration();
- break;
- case Token.DECLARE_COPY_NAMESPACES:
- if (!allowDeclarations) {
- grumble("'declare copy-namespaces' must appear earlier in the query prolog");
- }
- parseCopyNamespacesDeclaration();
- break;
- case Token.DECLARE_BASEURI:
- if (!allowDeclarations) {
- grumble("'declare base-uri' must appear earlier in the query prolog");
- }
- parseBaseURIDeclaration();
- break;
- case Token.IMPORT_SCHEMA:
- //allowSetters = false;
- if (!allowDeclarations) {
- grumble("Import schema must appear earlier in the prolog");
- }
- parseSchemaImport();
- break;
- case Token.IMPORT_MODULE:
- //allowSetters = false;
- if (!allowDeclarations) {
- grumble("Import module must appear earlier in the prolog");
- }
- parseModuleImport();
- break;
- case Token.DECLARE_VARIABLE:
- //allowSetters = false;
- if (allowDeclarations) {
- sealNamespaces(namespacesToBeSealed, env.getConfiguration());
- allowDeclarations = false;
- }
- processPreamble();
- parseVariableDeclaration();
- break;
- case Token.DECLARE_FUNCTION:
- if (allowDeclarations) {
- sealNamespaces(namespacesToBeSealed, env.getConfiguration());
- allowDeclarations = false;
- }
- processPreamble();
- parseFunctionDeclaration(false);
- break;
- case Token.DECLARE_UPDATING:
- nextToken();
- if (!isKeyword("function")) {
- grumble("expected 'function' after 'declare updating");
- }
- if (allowDeclarations) {
- sealNamespaces(namespacesToBeSealed, env.getConfiguration());
- allowDeclarations = false;
- }
- processPreamble();
- parseUpdatingFunctionDeclaration();
- break;
- case Token.DECLARE_OPTION:
- if (allowDeclarations) {
- sealNamespaces(namespacesToBeSealed, env.getConfiguration());
- allowDeclarations = false;
- }
- parseOptionDeclaration();
- break;
- case Token.DECLARE_CONSTRUCTION:
- if (!allowDeclarations) {
- grumble("'declare construction' must appear earlier in the query prolog");
- }
- parseConstructionDeclaration();
- break;
- case Token.DECLARE_REVALIDATION:
- if (!allowDeclarations) {
- grumble("'declare revalidation' must appear earlier in the query prolog");
- }
- parseRevalidationDeclaration();
- break;
- default:
- return;
- }
- expect(Token.SEMICOLON);
- nextToken();
- } catch (XPathException err) {
- if (err.getLocator() == null) {
- err.setLocator(makeLocator());
- }
- if (!err.hasBeenReported()) {
- errorCount++;
- if (firstError == null) {
- firstError = err;
- }
- ((QueryModule)env).reportFatalError(err);
- }
- // we've reported an error, attempt to recover by skipping to the
- // next semicolon
- while (t.currentToken != Token.SEMICOLON) {
- nextToken();
- if (t.currentToken == Token.EOF) {
- return;
- } else if (t.currentToken == Token.RCURLY) {
- t.lookAhead();
- } else if (t.currentToken == Token.TAG) {
- parsePseudoXML(true);
- }
- }
- nextToken();
- }
- }
- }
-
- private void sealNamespaces(List namespacesToBeSealed, Configuration config) {
- for (Iterator iter = namespacesToBeSealed.iterator(); iter.hasNext();) {
- String ns = (String)iter.next();
- config.sealNamespace(ns);
- }
- }
-
- /**
- * Method called once the setters have been read to do tidying up that can't be done until we've got
- * to the end
- *
- * @throws XPathException
- */
-
- private void processPreamble() throws XPathException {
- if (preambleProcessed) {
- return;
- }
- preambleProcessed = true;
- if (foundDefaultCollation) {
- String collationName = env.getDefaultCollationName();
- URI collationURI;
- try {
- collationURI = new URI(collationName);
- if (!collationURI.isAbsolute()) {
- URI base = new URI(env.getBaseURI());
- collationURI = base.resolve(collationURI);
- collationName = collationURI.toString();
- }
- } catch (URISyntaxException err) {
- grumble("Default collation name '" + collationName + "' is not a valid URI");
- collationName = NamespaceConstant.CODEPOINT_COLLATION_URI;
- }
- if (env.getCollation(collationName) == null) {
- grumble("Default collation name '" + collationName + "' is not a recognized collation", "XQST0038");
- collationName = NamespaceConstant.CODEPOINT_COLLATION_URI;
- }
- ((QueryModule)env).setDefaultCollationName(collationName);
- }
- for (Iterator iter = schemaImports.iterator(); iter.hasNext();) {
- Import imp = (Import)iter.next();
- applySchemaImport(imp);
- }
- for (Iterator iter = moduleImports.iterator(); iter.hasNext();) {
- Import imp = (Import)iter.next();
-
- // Check that this import would not create a cycle involving a change of namespace
- if (!disableCycleChecks) {
- if (!imp.namespaceURI.equals(((QueryModule)env).getModuleNamespace())) {
- QueryModule parent = (QueryModule)env;
- if (!parent.mayImportModule(imp.namespaceURI)) {
- XPathException err = new XPathException(
- "A module cannot import itself directly or indirectly, unless all modules in the cycle are in the same namespace");
- err.setErrorCode("XQST0073");
- err.setIsStaticError(true);
- throw err;
- }
- }
- }
-
- applyModuleImport(imp);
- }
- }
-
- private void parseDefaultCollation() throws XPathException {
- // <"default" "collation"> StringLiteral
- if (foundDefaultCollation) {
- grumble("default collation appears more than once", "XQST0038");
- }
- foundDefaultCollation = true;
- nextToken();
- expect(Token.STRING_LITERAL);
- String uri = URILiteral(t.currentTokenValue);
- ((QueryModule)env).setDefaultCollationName(uri);
- nextToken();
- }
-
- /**
- * parse "declare default order empty (least|greatest)"
- */
- private void parseDefaultOrder() throws XPathException {
- if (foundEmptyOrderingDeclaration) {
- grumble("empty ordering declaration appears more than once", "XQST0069");
- }
- foundEmptyOrderingDeclaration = true;
- nextToken();
- if (!isKeyword("empty")) {
- grumble("After 'declare default order', expected keyword 'empty'");
- }
- nextToken();
- if (isKeyword("least")) {
- ((QueryModule)env).setEmptyLeast(true);
- } else if (isKeyword("greatest")) {
- ((QueryModule)env).setEmptyLeast(false);
- } else {
- grumble("After 'declare default order empty', expected keyword 'least' or 'greatest'");
- }
- nextToken();
- }
-
- /**
- * Parse the "declare xmlspace" declaration.
- * Syntax: <"declare" "boundary-space"> ("preserve" | "strip")
- *
- * @throws XPathException
- */
-
- private void parseBoundarySpaceDeclaration() throws XPathException {
- if (foundBoundarySpaceDeclaration) {
- grumble("'declare boundary-space' appears more than once", "XQST0068");
- }
- foundBoundarySpaceDeclaration = true;
- nextToken();
- expect(Token.NAME);
- if ("preserve".equals(t.currentTokenValue)) {
- ((QueryModule)env).setPreserveBoundarySpace(true);
- } else if ("strip".equals(t.currentTokenValue)) {
- ((QueryModule)env).setPreserveBoundarySpace(false);
- } else {
- grumble("boundary-space must be 'preserve' or 'strip'");
- }
- nextToken();
- }
-
- /**
- * Parse the "declare ordering" declaration.
- * Syntax: <"declare" "ordering"> ("ordered" | "unordered")
- *
- * @throws XPathException
- */
-
- private void parseOrderingDeclaration() throws XPathException {
- if (foundOrderingDeclaration) {
- grumble("ordering mode declaration appears more than once", "XQST0065");
- }
- foundOrderingDeclaration = true;
- nextToken();
- expect(Token.NAME);
- if ("ordered".equals(t.currentTokenValue)) {
- // no action
- } else if ("unordered".equals(t.currentTokenValue)) {
- // no action
- } else {
- grumble("ordering mode must be 'ordered' or 'unordered'");
- }
- nextToken();
- }
-
- /**
- * Parse the "declare copy-namespaces" declaration.
- * Syntax: <"declare" "copy-namespaces"> ("preserve" | "no-preserve") "," ("inherit" | "no-inherit")
- *
- * @throws XPathException
- */
-
- private void parseCopyNamespacesDeclaration() throws XPathException {
- if (foundCopyNamespaces) {
- grumble("declare inherit-namespaces appears more than once", "XQST0055");
- }
- foundCopyNamespaces = true;
- nextToken();
- expect(Token.NAME);
- if ("preserve".equals(t.currentTokenValue)) {
- ((QueryModule)env).setPreserveNamespaces(true);
- } else if ("no-preserve".equals(t.currentTokenValue)) {
- ((QueryModule)env).setPreserveNamespaces(false);
- } else {
- grumble("copy-namespaces must be followed by 'preserve' or 'no-preserve'");
- }
- nextToken();
- expect(Token.COMMA);
- nextToken();
- expect(Token.NAME);
- if ("inherit".equals(t.currentTokenValue)) {
- ((QueryModule)env).setInheritNamespaces(true);
- } else if ("no-inherit".equals(t.currentTokenValue)) {
- ((QueryModule)env).setInheritNamespaces(false);
- } else {
- grumble("After the comma in the copy-namespaces declaration, expected 'inherit' or 'no-inherit'");
- }
- nextToken();
- }
-
-
- /**
- * Parse the "declare construction" declaration.
- * Syntax: <"declare" "construction"> ("preserve" | "strip")
- *
- * @throws XPathException
- */
-
- private void parseConstructionDeclaration() throws XPathException {
- if (foundConstructionDeclaration) {
- grumble("declare construction appears more than once", "XQST0067");
- }
- foundConstructionDeclaration = true;
- nextToken();
- expect(Token.NAME);
- int val;
- if ("preserve".equals(t.currentTokenValue)) {
- val = Validation.PRESERVE;
- } else if ("strip".equals(t.currentTokenValue)) {
- val = Validation.STRIP;
- } else {
- grumble("construction mode must be 'preserve' or 'strip'");
- val = Validation.STRIP;
- }
- ((QueryModule)env).setConstructionMode(val);
- nextToken();
- }
-
- /**
- * Parse the "declare revalidation" declaration.
- * Syntax: not allowed unless XQuery update is in use
- *
- * @throws XPathException
- */
-
- protected void parseRevalidationDeclaration() throws XPathException {
- grumble("declare revalidation is allowed only in XQuery Update");
- }
-
- /**
- * Parse (and process) the schema import declaration.
- * SchemaImport ::= "import" "schema" SchemaPrefix? URILiteral ("at" URILiteral ("," URILiteral)*)?
- * SchemaPrefix ::= ("namespace" NCName "=") | ("default" "element" "namespace")
- */
-
- private void parseSchemaImport() throws XPathException {
- if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) {
- grumble("To import a schema, you need the schema-aware version of Saxon", "XQST0009");
- }
- Import sImport = new Import();
- String prefix = null;
- sImport.namespaceURI = null;
- sImport.locationURIs = new ArrayList(5);
- nextToken();
- if (isKeyword("namespace")) {
- t.setState(Tokenizer.DEFAULT_STATE);
- nextToken();
- expect(Token.NAME);
- prefix = t.currentTokenValue;
- nextToken();
- expect(Token.EQUALS);
- nextToken();
- } else if (isKeyword("default")) {
- nextToken();
- if (!isKeyword("element")) {
- grumble("In 'import schema', expected 'element namespace'");
- }
- nextToken();
- if (!isKeyword("namespace")) {
- grumble("In 'import schema', expected keyword 'namespace'");
- }
- nextToken();
- prefix = "";
- }
- if (t.currentToken == Token.STRING_LITERAL) {
- String uri = URILiteral(t.currentTokenValue);
- checkProhibitedPrefixes(prefix, uri);
- sImport.namespaceURI = uri;
- nextToken();
- if (isKeyword("at")) {
- nextToken();
- expect(Token.STRING_LITERAL);
- sImport.locationURIs.add(URILiteral(t.currentTokenValue));
- nextToken();
- while (t.currentToken == Token.COMMA) {
- nextToken();
- expect(Token.STRING_LITERAL);
- sImport.locationURIs.add(URILiteral(t.currentTokenValue));
- nextToken();
- }
- } else if (t.currentToken != Token.SEMICOLON) {
- grumble("After the target namespace URI, expected 'at' or ';'");
- }
- } else {
- grumble("After 'import schema', expected 'namespace', 'default', or a string-literal");
- }
- if (prefix != null) {
- try {
- if (prefix.length() == 0) {
- ((QueryModule)env).setDefaultElementNamespace(sImport.namespaceURI);
- } else {
- if (sImport.namespaceURI == null || "".equals(sImport.namespaceURI)) {
- grumble("A prefix cannot be bound to the null namespace", "XQST0057");
- }
- ((QueryModule)env).declarePrologNamespace(prefix, sImport.namespaceURI);
- }
- } catch (XPathException err) {
- err.setLocator(makeLocator());
- reportError(err);
- }
- }
- for (Iterator iter = schemaImports.iterator(); iter.hasNext();) {
- Import imp = (Import)iter.next();
- if (imp.namespaceURI.equals(sImport.namespaceURI)) {
- grumble("Schema namespace '" + sImport.namespaceURI + "' is imported more than once", "XQST0058");
- break;
- }
- }
-
- schemaImports.add(sImport);
-
- }
-
- private void applySchemaImport(Import sImport) throws XPathException {
-
- // Do the importing
-
- Configuration config = env.getConfiguration();
- if (!config.isSchemaAvailable(sImport.namespaceURI)) {
- if (!sImport.locationURIs.isEmpty()) {
- try {
- PipelineConfiguration pipe = config.makePipelineConfiguration();
- config.readMultipleSchemas(pipe, env.getBaseURI(), sImport.locationURIs, sImport.namespaceURI);
- namespacesToBeSealed.add(sImport.namespaceURI);
- } catch (TransformerConfigurationException err) {
- grumble("Error in schema. " + err.getMessage(), "XQST0059");
- }
- } else {
- grumble("Unable to locate requested schema", "XQST0059");
- }
- }
- ((QueryModule)env).addImportedSchema(sImport.namespaceURI, env.getBaseURI(), sImport.locationURIs);
- }
-
- /**
- * Parse (and expand) the module import declaration.
- * Syntax: <"import" "module" ("namespace" NCName "=")? uri ("at" uri ("," uri)*)? ";"
- */
-
- private void parseModuleImport() throws XPathException {
- QueryModule thisModule = (QueryModule)env;
- Import mImport = new Import();
- String prefix = null;
- mImport.namespaceURI = null;
- mImport.locationURIs = new ArrayList(5);
- nextToken();
- if (t.currentToken == Token.NAME && t.currentTokenValue.equals("namespace")) {
- t.setState(Tokenizer.DEFAULT_STATE);
- nextToken();
- expect(Token.NAME);
- prefix = t.currentTokenValue;
- nextToken();
- expect(Token.EQUALS);
- nextToken();
- }
- if (t.currentToken == Token.STRING_LITERAL) {
- String uri = URILiteral(t.currentTokenValue);
- checkProhibitedPrefixes(prefix, uri);
- mImport.namespaceURI = uri;
- if (mImport.namespaceURI.length() == 0) {
- grumble("Imported module namespace cannot be \"\"", "XQST0088");
- mImport.namespaceURI = "http://saxon.fallback.namespace/line" + t.getLineNumber(); // for error recovery
- }
- if (importedModules.contains(mImport.namespaceURI)) {
- grumble("Two 'import module' declarations specify the same module namespace", "XQST0047");
- }
- importedModules.add(mImport.namespaceURI);
- ((QueryModule)env).addImportedNamespace(mImport.namespaceURI);
- nextToken();
- if (isKeyword("at")) {
- do {
- nextToken();
- expect(Token.STRING_LITERAL);
- mImport.locationURIs.add(URILiteral(t.currentTokenValue));
- nextToken();
- } while (t.currentToken == Token.COMMA);
- }
- } else {
- grumble("After 'import module', expected 'namespace' or a string-literal");
- }
- if (prefix != null) {
- try {
- thisModule.declarePrologNamespace(prefix, mImport.namespaceURI);
- } catch (XPathException err) {
- err.setLocator(makeLocator());
- reportError(err);
- }
- }
-
- // // Check that this import would not create a cycle involving a change of namespace
- // if (!disableCycleChecks) {
- // if (!mImport.namespaceURI.equals(((QueryModule)env).getModuleNamespace())) {
- // QueryModule parent = (QueryModule)env;
- // if (!parent.mayImport(mImport.namespaceURI)) {
- // StaticError err = new StaticError("A module cannot import itself directly or indirectly, unless all modules in the cycle are in the same namespace");
- // err.setErrorCode("XQST0073");
- // throw err;
- // }
- // }
- // }
-
- moduleImports.add(mImport);
- }
-
- public void applyModuleImport(Import mImport) throws XPathException {
- boolean foundOne = false;
-
- // resolve the location URIs against the base URI
- Platform platform = Configuration.getPlatform();
- for (int i=0; i<mImport.locationURIs.size(); i++) {
- try {
- String uri = (String)mImport.locationURIs.get(i);
- URI abs = platform.makeAbsolute(uri, env.getBaseURI());
- mImport.locationURIs.set(i, abs);
- } catch (URISyntaxException e) {
- grumble("Invalid URI " + mImport.locationURIs.get(i) + ": " + e.getMessage());
- }
- }
-
- // If any of the modules are already loaded, don't re-read them; but do check that none of them
- // references the current module namespace directly or indirectly
- List existingModules = executable.getQueryLibraryModules(mImport.namespaceURI);
- if (existingModules != null) {
- //System.err.println("Number of existing modules: " + existingModules.size());
- for (int m = 0; m < existingModules.size(); m++) {
- QueryModule importedModule = (QueryModule)existingModules.get(m);
- //System.err.println("Existing module location URI = " + importedModule.getLocationURI());
- if (!importedModule.getLocationURI().equals(((QueryModule)env).getLocationURI())) {
- //QueryReader.importModuleContents(importedModule, (QueryModule)env);
- foundOne = true;
- }
- if (!disableCycleChecks &&
- ((QueryModule)env).getModuleNamespace() != null &&
- !((QueryModule)env).getModuleNamespace().equals(importedModule.getModuleNamespace()) &&
- importedModule.importsNamespaceIndirectly(((QueryModule)env).getModuleNamespace())) {
- grumble("A cycle exists among the module imports, involving namespaces " +
- ((QueryModule)env).getModuleNamespace() + " and " +
- importedModule.getModuleNamespace());
- }
- for (int h = mImport.locationURIs.size() - 1; h >= 0; h--) {
- if (mImport.locationURIs.get(h).equals(importedModule.getLocationURI())) {
- mImport.locationURIs.remove(h);
- }
- }
- }
- }
-
- // If we've found at least one module, and there are no location URIs left, call it a day.
-
- if (mImport.locationURIs.isEmpty() && foundOne) {
- return;
- }
-
- // Call the module URI resolver to find the remaining modules
-
- ModuleURIResolver resolver = ((QueryModule)env).getUserQueryContext().getModuleURIResolver();
-
- String[] hints = new String[mImport.locationURIs.size()];
- for (int h=0; h<hints.length; h++) {
- hints[h] = mImport.locationURIs.get(h).toString();
- }
- StreamSource[] sources = null;
- if (resolver != null) {
- sources = resolver.resolve(mImport.namespaceURI, env.getBaseURI(), hints);
- }
- if (sources == null) {
- if (hints.length == 0) {
- if (existingModules == null) {
- grumble("Cannot locate module for namespace " + mImport.namespaceURI, "XQST0059");
- }
- }
- resolver = env.getConfiguration().getStandardModuleURIResolver();
- sources = resolver.resolve(mImport.namespaceURI, env.getBaseURI(), hints);
- }
-
- for (int m = 0; m < sources.length; m++) {
- StreamSource ss = sources[m];
- String baseURI = ss.getSystemId();
- if (baseURI == null) {
- if (m < hints.length) {
- baseURI = hints[m];
- ss.setSystemId(hints[m]);
- } else {
- grumble("No base URI available for imported module", "XQST0059");
- }
- }
- // Although the module hadn't been loaded when we started, it might have been loaded since, as
- // a result of a reference from another imported module. Note, we are careful here to use URI.equals()
- // rather that String.equals() to compare URIs, as this gives a slightly more intelligent comparison,
- // for example the scheme name is case-independent, and file:///x/y/z matches file:/x/y/z.
- // TODO: use similar logic when loading schema modules
- existingModules = executable.getQueryLibraryModules(mImport.namespaceURI);
- boolean loaded = false;
- if (existingModules != null && m < hints.length) {
- for (int e=0; e<existingModules.size(); e++) {
- if (((QueryModule)existingModules.get(e)).getLocationURI().equals(mImport.locationURIs.get(m))) {
- loaded = true;
- break;
- }
- }
- }
- if (loaded) {
- break;
- }
-
- try {
- String queryText = QueryReader.readSourceQuery(ss, nameChecker);
- try {
- if (ss.getInputStream() != null) {
- ss.getInputStream().close();
- } else if (ss.getReader() != null) {
- ss.getReader().close();
- }
- } catch (IOException e) {
- throw new XPathException("Failure while closing file for imported query module");
- }
- QueryModule.makeQueryModule(
- baseURI, executable, (QueryModule)env, queryText, mImport.namespaceURI,
- disableCycleChecks);
- } catch (XPathException err) {
- err.maybeSetLocation(makeLocator());
- reportError(err);
- }
- }
- }
-
- /**
- * Parse the Base URI declaration.
- * Syntax: <"declare" "base-uri"> uri-literal
- *
- * @throws XPathException
- */
-
- private void parseBaseURIDeclaration() throws XPathException {
- if (foundBaseURIDeclaration) {
- grumble("Base URI Declaration may only appear once", "XQST0032");
- }
- foundBaseURIDeclaration = true;
- nextToken();
- expect(Token.STRING_LITERAL);
- String uri = URILiteral(t.currentTokenValue);
- try {
- // if the supplied URI is relative, try to resolve it
- URI baseURI = new URI(uri);
- if (!baseURI.isAbsolute()) {
- String oldBase = env.getBaseURI();
- URI oldBaseURI = new URI(oldBase);
- uri = oldBaseURI.resolve(uri).toString();
- }
- ((QueryModule)env).setBaseURI(uri);
- } catch (URISyntaxException err) {
- // The spec says this "is not intrinsically an error", but can cause a failure later
- ((QueryModule)env).setBaseURI(uri);
- }
- nextToken();
- }
-
- /**
- * Parse the "default function namespace" declaration.
- * Syntax: <"declare" "default" "function" "namespace"> StringLiteral
- *
- * @throws XPathException to indicate a syntax error
- */
-
- private void parseDefaultFunctionNamespace() throws XPathException {
- if (foundDefaultFunctionNamespace) {
- grumble("default function namespace appears more than once", "XQST0066");
- }
- foundDefaultFunctionNamespace = true;
- nextToken();
- expect(Token.NAME);
- if (!"namespace".equals(t.currentTokenValue)) {
- grumble("After 'declare default function', expected 'namespace'");
- }
- nextToken();
- expect(Token.STRING_LITERAL);
- String uri = URILiteral(t.currentTokenValue);
- ((QueryModule)env).setDefaultFunctionNamespace(uri);
- nextToken();
- }
-
- /**
- * Parse the "default element namespace" declaration.
- * Syntax: <"declare" "default" "element" "namespace"> StringLiteral
- *
- * @throws XPathException to indicate a syntax error
- */
-
- private void parseDefaultElementNamespace() throws XPathException {
- if (foundDefaultElementNamespace) {
- grumble("default element namespace appears more than once", "XQST0066");
- }
- foundDefaultElementNamespace = true;
- nextToken();
- expect(Token.NAME);
- if (!"namespace".equals(t.currentTokenValue)) {
- grumble("After 'declare default element', expected 'namespace'");
- }
- nextToken();
- expec…
Large files files are truncated, but you can click here to view the full file