/** * Try to precompile the arguments to the function. This method is shared by the implementations * of the three XPath functions matches(), replace(), and tokenize(). * * @param args the supplied arguments to the function, as an array * @param patternArg the position of the argument containing the regular expression * @param flagsArg the position of the argument containing the flags * @return the compiled regular expression, or null indicating that the information is not * available statically so it cannot be precompiled * @throws XPathException if any failure occurs, in particular, if the regular expression is * invalid */ public static RegularExpression tryToCompile( Expression[] args, int patternArg, int flagsArg, StaticContext env) throws XPathException { if (patternArg > args.length - 1) { // too few arguments were supplied; the error will be reported in due course return null; } CharSequence flagstr = null; if (args.length - 1 < flagsArg) { flagstr = ""; } else if (args[flagsArg] instanceof StringValue) { flagstr = ((StringValue) args[flagsArg]).getStringValueCS(); } if (args[patternArg] instanceof StringValue && flagstr != null) { try { Platform platform = env.getConfiguration().getPlatform(); CharSequence in = ((StringValue) args[patternArg]).getStringValueCS(); RegularExpression regexp = platform.compileRegularExpression(in, true, flagstr); return regexp; } catch (XPathException err) { StaticError e2 = new StaticError(err.getMessage()); e2.setErrorCode("FORX0002"); throw e2; } } else { return null; } }
/** * Set the expression defining the value of the attribute. If this is a constant, and if * validation against a schema type was requested, the validation is done immediately. * * @param select The expression defining the content of the attribute * @param config * @throws StaticError if the expression is a constant, and validation is requested, and the * constant doesn't match the required type. */ public void setSelect(Expression select, Configuration config) throws StaticError { super.setSelect(select, config); // Attempt early validation if possible if (select instanceof AtomicValue && schemaType != null && !schemaType.isNamespaceSensitive()) { CharSequence value = ((AtomicValue) select).getStringValueCS(); XPathException err = schemaType.validateContent( value, DummyNamespaceResolver.getInstance(), config.getNameChecker()); if (err != null) { StaticError se = new StaticError( "Attribute value " + Err.wrap(value, Err.VALUE) + " does not the match the required type " + schemaType.getDescription() + ". " + err.getMessage()); se.setErrorCode("XTTE1540"); throw se; } } // If value is fixed, test whether there are any special characters that might need to be // escaped when the time comes for serialization if (select instanceof StringValue) { boolean special = false; CharSequence val = ((StringValue) select).getStringValueCS(); for (int k = 0; k < val.length(); k++) { char c = val.charAt(k); if ((int) c < 33 || (int) c > 126 || c == '<' || c == '>' || c == '&' || c == '\"') { special = true; break; } } if (!special) { this.options |= ReceiverOptions.NO_SPECIAL_CHARS; } } // If attribute name is xml:id, add whitespace normalization if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID) { Expression[] args = {select}; FunctionCall fn = SystemFunction.makeSystemFunction("normalize-space", 1, config.getNamePool()); fn.setArguments(args); select = fn; super.setSelect(select, config); } }
/** * Simplify and validate. This is a pure function so it can be simplified in advance if the * arguments are known * * @return the simplified expression * @throws net.sf.saxon.trans.StaticError if any error is found (e.g. invalid regular expression) */ public Expression simplify(StaticContext env) throws XPathException { Expression e = simplifyArguments(env); // compile the regular expression once if possible if (regexp == null && !(e instanceof Value)) { try { regexp = tryToCompile(argument, 1, 2, env); } catch (StaticError err) { err.setLocator(this); throw err; } } return e; }
/** Type-check the expression. */ public Expression analyze(StaticContext env, ItemType contextItemType) throws XPathException { if (contextItemType == null) { StaticError err = new StaticError("Cannot select a node here: the context item is undefined"); err.setIsTypeError(true); err.setLocator(this); throw err; } if (contextItemType instanceof AtomicType) { StaticError err = new StaticError("Cannot select a node here: the context item is an atomic value"); err.setIsTypeError(true); err.setLocator(this); throw err; } return this; }
public void checkArguments(StaticContext env) throws XPathException { if (checked) return; checked = true; super.checkArguments(env); Optimizer opt = env.getConfiguration().getOptimizer(); argument[1] = ExpressionTool.unsorted(opt, argument[1], false); if (argument[0] instanceof StringValue) { // common case, key name is supplied as a constant try { keyFingerprint = ((ExpressionContext) env) .getFingerprint(((StringValue) argument[0]).getStringValue(), false); } catch (XPathException e) { StaticError err = new StaticError( "Error in key name " + ((StringValue) argument[0]).getStringValue() + ": " + e.getMessage()); err.setLocator(this); err.setErrorCode("XTDE1260"); throw err; } if (keyFingerprint == -1) { StaticError err = new StaticError( "Key " + ((StringValue) argument[0]).getStringValue() + " has not been defined"); err.setLocator(this); err.setErrorCode("XTDE1260"); throw err; } } else { // we need to save the namespace context nsContext = env.getNamespaceResolver(); } }
/** * Check that any elements and attributes constructed or returned by this expression are * acceptable in the content model of a given complex type. It's always OK to say yes, since the * check will be repeated at run-time. The process of checking element and attribute constructors * against the content model of a complex type also registers the type of content expected of * those constructors, so the static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { int fp = nameCode & NamePool.FP_MASK; if (fp == StandardNames.XSI_TYPE || fp == StandardNames.XSI_SCHEMA_LOCATION || fp == StandardNames.XSI_NIL || fp == StandardNames.XSI_NO_NAMESPACE_SCHEMA_LOCATION) { return; } if (parentType instanceof SimpleType) { StaticError err = new StaticError( "Attribute " + env.getNamePool().getDisplayName(nameCode) + " is not permitted in the content model of the simple type " + parentType.getDescription()); err.setIsTypeError(true); err.setLocator(this); if (getHostLanguage() == Configuration.XSLT) { err.setErrorCode("XTTE1510"); } else { err.setErrorCode("XQDY0027"); } throw err; } SchemaType type; try { type = ((ComplexType) parentType).getAttributeUseType(fp); } catch (SchemaException e) { throw new StaticError(e); } if (type == null) { StaticError err = new StaticError( "Attribute " + env.getNamePool().getDisplayName(nameCode) + " is not permitted in the content model of the complex type " + parentType.getDescription()); err.setIsTypeError(true); err.setLocator(this); if (getHostLanguage() == Configuration.XSLT) { err.setErrorCode("XTTE1510"); } else { err.setErrorCode("XQDY0027"); } throw err; } if (type instanceof AnyType) { return; } try { select.checkPermittedContents(type, env, true); // TODO: does this allow for the fact that the content will be atomized? } catch (XPathException e) { if (e.getLocator() == null || e.getLocator() == e) { e.setLocator(this); } throw e; } }