/** * Analyze a picture string into two sub-pictures. * * @param picture the picture as written (possibly two subpictures separated by a semicolon) * @param dfs the decimal format symbols * @return an array of two sub-pictures, the positive and the negative sub-pictures respectively. * If there is only one sub-picture, the second one is null. */ private SubPicture[] getSubPictures(String picture, DecimalSymbols dfs) throws XPathException { int[] picture4 = StringValue.expand(picture); SubPicture[] pics = new SubPicture[2]; if (picture4.length == 0) { XPathException err = new XPathException("format-number() picture is zero-length"); err.setErrorCode("XTDE1310"); throw err; } int sep = -1; for (int c = 0; c < picture4.length; c++) { if (picture4[c] == dfs.patternSeparator) { if (c == 0) { grumble("first subpicture is zero-length"); } else if (sep >= 0) { grumble("more than one pattern separator"); } else if (sep == picture4.length - 1) { grumble("second subpicture is zero-length"); } sep = c; } } if (sep < 0) { pics[0] = new SubPicture(picture4, dfs); pics[1] = null; } else { int[] pic0 = new int[sep]; System.arraycopy(picture4, 0, pic0, 0, sep); int[] pic1 = new int[picture4.length - sep - 1]; System.arraycopy(picture4, sep + 1, pic1, 0, picture4.length - sep - 1); pics[0] = new SubPicture(pic0, dfs); pics[1] = new SubPicture(pic1, dfs); } return pics; }
public void checkArguments(ExpressionVisitor visitor) throws XPathException { StaticContext env = visitor.getStaticContext(); if (checked) return; checked = true; super.checkArguments(visitor); if (argument[1] instanceof StringLiteral) { // picture is known statically - optimize for this common case picture = ((StringLiteral) argument[1]).getStringValue(); } if (argument.length == 3) { if (argument[2] instanceof StringLiteral) { // common case, decimal format name is supplied as a string literal String lexicalName = ((StringLiteral) argument[2]).getStringValue(); StructuredQName qName; try { qName = StructuredQName.fromLexicalQName( lexicalName, false, visitor.getConfiguration().getNameChecker(), env.getNamespaceResolver()); } catch (XPathException e) { XPathException se = new XPathException("Invalid decimal format name. " + e.getMessage()); se.setErrorCode("XTDE1280"); throw se; } DecimalFormatManager dfm = ((ExpressionContext) env).getXSLStylesheet().getDecimalFormatManager(); requireFixup = true; dfm.registerUsage(qName, this); // this causes a callback to the fixup() method, either now, or later if it's a forwards // reference } else { // we need to save the namespace context nsContext = env.getNamespaceResolver(); } } else { // two arguments only: it uses the default decimal format if (env instanceof ExpressionContext) { // this is XSLT DecimalFormatManager dfm = ((ExpressionContext) env).getXSLStylesheet().getDecimalFormatManager(); dfm.registerUsage(DecimalFormatManager.DEFAULT_NAME, this); // Note: if using the "default default", there will be no fixup call. } else { // using saxon:decimal-format in some other environment } } }
/** Evaluate in a context where a string is wanted */ public CharSequence evaluateAsString(XPathContext context) throws XPathException { int numArgs = argument.length; Controller ctrl = context.getController(); DecimalSymbols dfs = decimalFormatSymbols; AtomicValue av0 = (AtomicValue) argument[0].evaluateItem(context); if (av0 == null) { av0 = DoubleValue.NaN; } NumericValue number = (NumericValue) av0; if (dfs == null) { // the decimal-format name was not resolved statically if (requireFixup) { // we registered for a fixup, but none came dynamicError("Unknown decimal format name", "XTDE1280", context); return null; } DecimalFormatManager dfm = ctrl.getExecutable().getDecimalFormatManager(); if (numArgs == 2) { dfs = dfm.getDefaultDecimalFormat(); } else { // the decimal-format name was given as a run-time expression String lexicalName = argument[2].evaluateItem(context).getStringValue(); StructuredQName qName = null; try { qName = StructuredQName.fromLexicalQName( lexicalName, false, context.getConfiguration().getNameChecker(), nsContext); } catch (XPathException e) { dynamicError("Invalid decimal format name. " + e.getMessage(), "XTDE1280", context); } dfs = dfm.getNamedDecimalFormat(qName); if (dfs == null) { dynamicError( "format-number function: decimal-format '" + lexicalName + "' is not defined", "XTDE1280", context); return null; } } } SubPicture[] pics = subPictures; if (pics == null) { String format = argument[1].evaluateItem(context).getStringValue(); pics = getSubPictures(format, dfs); } return formatNumber(number, pics, dfs).toString(); }
public void visitLocationStep(LocationStep locationStep) { super.visitLocationStep(locationStep); boolean optimize = false; // only location steps with predicates can be optimized: if (locationStep.hasPredicates()) { List preds = locationStep.getPredicates(); // walk through the predicates attached to the current location step. // try to find a predicate containing an expression which is an instance // of Optimizable. for (Iterator i = preds.iterator(); i.hasNext(); ) { Predicate pred = (Predicate) i.next(); FindOptimizable find = new FindOptimizable(); pred.accept(find); List list = find.getOptimizables(); if (list.size() > 0 && canOptimize(list)) { optimize = true; break; } } } if (optimize) { // we found at least one Optimizable. Rewrite the whole expression and // enclose it in an (#exist:optimize#) pragma. Expression parent = locationStep.getParent(); if (!(parent instanceof PathExpr)) { LOG.warn("Parent expression of step is not a PathExpr: " + parent); return; } if (LOG.isTraceEnabled()) LOG.trace("Rewriting expression: " + ExpressionDumper.dump(locationStep)); hasOptimized = true; PathExpr path = (PathExpr) parent; try { // Create the pragma ExtensionExpression extension = new ExtensionExpression(context); extension.addPragma(new Optimize(context, Optimize.OPTIMIZE_PRAGMA, null, false)); extension.setExpression(locationStep); // Replace the old expression with the pragma path.replaceExpression(locationStep, extension); } catch (XPathException e) { LOG.warn("Failed to optimize expression: " + locationStep + ": " + e.getMessage(), e); } } }