1 package net.sf.saxon.instruct; 2 3 import net.sf.saxon.Configuration; 4 import net.sf.saxon.Controller; 5 import net.sf.saxon.expr.*; 6 import net.sf.saxon.functions.NumberFn; 7 import net.sf.saxon.number.NumberFormatter; 8 import net.sf.saxon.number.Numberer; 9 import net.sf.saxon.number.Numberer_en; 10 import net.sf.saxon.om.*; 11 import net.sf.saxon.pattern.Pattern; 12 import net.sf.saxon.pattern.PatternSponsor; 13 import net.sf.saxon.trans.DynamicError; 14 import net.sf.saxon.trans.StaticError; 15 import net.sf.saxon.trans.XPathException; 16 import net.sf.saxon.type.AtomicType; 17 import net.sf.saxon.type.ItemType; 18 import net.sf.saxon.type.Type; 19 import net.sf.saxon.value.*; 20 21 import java.io.PrintStream ; 22 import java.util.*; 23 24 28 29 public class NumberInstruction extends ComputedExpression { 30 31 private static final int SINGLE = 0; 32 private static final int MULTI = 1; 33 private static final int ANY = 2; 34 private static final int SIMPLE = 3; 35 36 private int level; 37 private Pattern count = null; 38 private Pattern from = null; 39 private Expression select = null; 40 private Expression value = null; 41 private Expression format = null; 42 private Expression groupSize = null; 43 private Expression groupSeparator = null; 44 private Expression letterValue = null; 45 private Expression ordinal = null; 46 private Expression lang = null; 47 private NumberFormatter formatter = null; 48 private Numberer numberer = null; 49 private HashMap nationalNumberers = null; 50 private boolean hasVariablesInPatterns; 51 private boolean backwardsCompatible; 52 53 private static Numberer defaultNumberer = new Numberer_en(); 54 55 public NumberInstruction(Expression select, 56 int level, 57 Pattern count, 58 Pattern from, 59 Expression value, 60 Expression format, 61 Expression groupSize, 62 Expression groupSeparator, 63 Expression letterValue, 64 Expression ordinal, 65 Expression lang, 66 NumberFormatter formatter, 67 Numberer numberer, 68 boolean hasVariablesInPatterns, 69 boolean backwardsCompatible) { 70 this.select = select; 71 this.level = level; 72 this.count = count; 73 this.from = from; 74 this.value = value; 75 this.format = format; 76 this.groupSize = groupSize; 77 this.groupSeparator = groupSeparator; 78 this.letterValue = letterValue; 79 this.ordinal = ordinal; 80 this.lang = lang; 81 this.formatter = formatter; 82 this.numberer = numberer; 83 this.hasVariablesInPatterns = hasVariablesInPatterns; 84 this.backwardsCompatible = backwardsCompatible; 85 86 if (this.value != null && !Type.isSubType(this.value.getItemType(), Type.ANY_ATOMIC_TYPE)) { 87 this.value = new Atomizer(this.value, null); 88 } 89 90 Iterator kids = iterateSubExpressions(); 91 while (kids.hasNext()) { 92 Expression child = (Expression)kids.next(); 93 adoptChildExpression(child); 94 } 95 96 97 } 122 123 public Expression simplify(StaticContext env) throws XPathException { 124 if (select != null) { 125 select = select.simplify(env); 126 } 127 if (value != null) { 128 value = value.simplify(env); 129 } 130 if (format != null) { 131 format = format.simplify(env); 132 } 133 if (groupSize != null) { 134 groupSize = groupSize.simplify(env); 135 } 136 if (groupSeparator != null) { 137 groupSeparator = groupSeparator.simplify(env); 138 } 139 if (letterValue != null) { 140 letterValue = letterValue.simplify(env); 141 } 142 if (ordinal != null) { 143 ordinal = ordinal.simplify(env); 144 } 145 if (lang != null) { 146 lang = lang.simplify(env); 147 } 148 if (count != null) { 149 count = count.simplify(env); 150 } 151 if (from != null) { 152 from = from.simplify(env); 153 } 154 return this; 155 } 156 157 176 177 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 178 if (select != null) { 179 select = select.typeCheck(env, contextItemType); 180 } else { 181 if (value==null) { 182 if (contextItemType instanceof AtomicType) { 184 StaticError err = new StaticError("xsl:number requires the context item to be a node, but it is an atomic value"); 185 err.setIsTypeError(true); 186 err.setErrorCode("XTTE0990"); 187 } 188 } 189 } 190 if (value != null) { 191 value = value.typeCheck(env, contextItemType); 192 } 193 if (format != null) { 194 format = format.typeCheck(env, contextItemType); 195 } 196 if (groupSize != null) { 197 groupSize = groupSize.typeCheck(env, contextItemType); 198 } 199 if (groupSeparator != null) { 200 groupSeparator = groupSeparator.typeCheck(env, contextItemType); 201 } 202 if (letterValue != null) { 203 letterValue = letterValue.typeCheck(env, contextItemType); 204 } 205 if (ordinal != null) { 206 ordinal = ordinal.typeCheck(env, contextItemType); 207 } 208 if (lang != null) { 209 lang = lang.typeCheck(env, contextItemType); 210 } 211 if (count != null) { 212 count = count.analyze(env, contextItemType); 213 } 214 if (from != null) { 215 from = from.analyze(env, contextItemType); 216 } 217 return this; 218 } 219 220 237 238 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 239 if (select != null) { 240 select = select.optimize(opt, env, contextItemType); 241 } 242 if (value != null) { 243 value = value.optimize(opt, env, contextItemType); 244 } 245 if (format != null) { 246 format = format.optimize(opt, env, contextItemType); 247 } 248 if (groupSize != null) { 249 groupSize = groupSize.optimize(opt, env, contextItemType); 250 } 251 if (groupSeparator != null) { 252 groupSeparator = groupSeparator.optimize(opt, env, contextItemType); 253 } 254 if (letterValue != null) { 255 letterValue = letterValue.optimize(opt, env, contextItemType); 256 } 257 if (ordinal != null) { 258 ordinal = ordinal.optimize(opt, env, contextItemType); 259 } 260 if (lang != null) { 261 lang = lang.optimize(opt, env, contextItemType); 262 } 263 return this; 270 } 271 272 273 279 280 public Iterator iterateSubExpressions() { 281 List sub = new ArrayList(9); 282 if (select != null) { 283 sub.add(select); 284 } 285 if (value != null) { 286 sub.add(value); 287 } 288 if (format != null) { 289 sub.add(format); 290 } 291 if (groupSize != null) { 292 sub.add(groupSize); 293 } 294 if (groupSeparator != null) { 295 sub.add(groupSeparator); 296 } 297 if (letterValue != null) { 298 sub.add(letterValue); 299 } 300 if (ordinal != null) { 301 sub.add(ordinal); 302 } 303 if (lang != null) { 304 sub.add(lang); 305 } 306 if (count != null) { 307 sub.add(new PatternSponsor(count)); 308 } 309 if (from != null) { 310 sub.add(new PatternSponsor(from)); 311 } 312 return sub.iterator(); 313 } 314 315 324 325 public int getIntrinsicDependencies() { 326 return (select == null ? StaticProperty.DEPENDS_ON_CONTEXT_ITEM : 0); 327 } 328 329 public ItemType getItemType() { 330 return Type.STRING_TYPE; 331 } 332 333 public int computeCardinality() { 334 return StaticProperty.EXACTLY_ONE; 335 } 336 337 353 354 public Expression promote(PromotionOffer offer) throws XPathException { 355 Expression exp = offer.accept(this); 356 if (exp!=null) { 357 return exp; 358 } else { 359 if (select != null) { 360 select = doPromotion(select, offer); 361 } 362 if (value != null) { 363 value = doPromotion(value, offer); 364 } 365 if (format != null) { 366 format = doPromotion(format, offer); 367 } 368 if (groupSize != null) { 369 groupSize = doPromotion(groupSize, offer); 370 } 371 if (groupSeparator != null) { 372 groupSeparator = doPromotion(groupSeparator, offer); 373 } 374 if (letterValue != null) { 375 letterValue = doPromotion(letterValue, offer); 376 } 377 if (ordinal != null) { 378 ordinal = doPromotion(ordinal, offer); 379 } 380 if (lang != null) { 381 lang = doPromotion(lang, offer); 382 } 383 if (count != null) { 384 count.promote(offer); 385 } 386 if (from != null) { 387 from.promote(offer); 388 } 389 return this; 390 } 391 } 392 393 public Item evaluateItem(XPathContext context) throws XPathException { 394 long value = -1; 395 List vec = null; 398 if (this.value != null) { 399 400 SequenceIterator iter = this.value.iterate(context); 401 vec = new ArrayList(4); 402 while (true) { 403 AtomicValue val = (AtomicValue) iter.next(); 404 if (val == null) { 405 break; 406 } 407 try { 408 NumericValue num; 409 if (val instanceof NumericValue) { 410 num = (NumericValue) val; 411 } else { 412 num = NumberFn.convert(val); 413 } 414 if (num.isNaN()) { 415 throw new DynamicError("NaN"); } 417 num = num.round(); 418 if (num.compareTo(IntegerValue.MAX_LONG) > 0) { 419 vec.add(((BigIntegerValue)num.convert(Type.INTEGER, context)).getBigInteger()); 420 } else { 425 if (num.compareTo(IntegerValue.ZERO) < 0) { 426 DynamicError e = new DynamicError("The numbers to be formatted must not be negative"); 427 throw e; 430 } 431 long i = ((NumericValue) num.convert(Type.INTEGER, context)).longValue(); 432 vec.add(new Long (i)); 439 } 440 } catch (DynamicError err) { 441 if (backwardsCompatible) { 442 vec.add("NaN"); 443 } else { 444 vec.add(val.getStringValue()); 445 DynamicError e = new DynamicError("Cannot convert supplied value to an integer. " + err.getMessage()); 446 e.setErrorCode("XTDE0980"); 447 e.setXPathContext(context); 448 throw e; 449 } 450 } 451 } 452 if (backwardsCompatible && vec.size()==0) { 453 vec.add("NaN"); 454 } 455 } else { 456 NodeInfo source; 457 if (select != null) { 458 source = (NodeInfo) select.evaluateItem(context); 459 } else { 460 Item item = context.getContextItem(); 461 if (!(item instanceof NodeInfo)) { 462 DynamicError err = new DynamicError("context item for xsl:number must be a node"); 463 err.setErrorCode("XTTE0990"); 464 err.setIsTypeError(true); 465 err.setXPathContext(context); 466 throw err; 467 } 470 source = (NodeInfo) item; 471 } 472 473 if (level == SIMPLE) { 474 value = Navigator.getNumberSimple(source, context); 475 } else if (level == SINGLE) { 476 value = Navigator.getNumberSingle(source, count, from, context); 477 if (value == 0) { 478 vec = Collections.EMPTY_LIST; } 480 } else if (level == ANY) { 481 value = Navigator.getNumberAny(this, source, count, from, context, hasVariablesInPatterns); 482 if (value == 0) { 483 vec = Collections.EMPTY_LIST; } 485 } else if (level == MULTI) { 486 vec = Navigator.getNumberMulti(source, count, from, context); 487 } 488 } 489 490 int gpsize = 0; 491 String gpseparator = ""; 492 String letterVal; 493 String ordinalVal = null; 494 495 if (groupSize != null) { 496 String g = groupSize.evaluateAsString(context); 497 try { 498 gpsize = Integer.parseInt(g); 499 } catch (NumberFormatException err) { 500 DynamicError e = new DynamicError("grouping-size must be numeric"); 501 e.setXPathContext(context); 502 e.setErrorCode("XTDE0030"); 503 throw e; 504 } 505 } 506 507 if (groupSeparator != null) { 508 gpseparator = groupSeparator.evaluateAsString(context); 509 } 510 511 if (ordinal != null) { 512 ordinalVal = ordinal.evaluateAsString(context); 513 } 514 515 517 if (vec == null && format == null && gpsize == 0 && lang == null) { 518 return new StringValue("" + value); 519 } 520 521 Numberer numb = numberer; 525 if (numb == null) { 526 String language = lang.evaluateAsString(context); 527 if (nationalNumberers == null) { 528 nationalNumberers = new HashMap(4); 529 } 530 numb = (Numberer)nationalNumberers.get(language); 531 if (numb == null) { 532 numb = makeNumberer(language, context); 533 nationalNumberers.put(language, numb); 534 } 535 } 536 537 if (letterValue == null) { 538 letterVal = ""; 539 } else { 540 letterVal = letterValue.evaluateAsString(context); 541 if (!("alphabetic".equals(letterVal) || "traditional".equals(letterVal))) { 542 DynamicError e = new DynamicError("letter-value must be \"traditional\" or \"alphabetic\""); 543 e.setXPathContext(context); 544 e.setErrorCode("XTDE0030"); 545 throw e; 546 } 547 } 548 549 if (vec == null) { 550 vec = new ArrayList(1); 551 vec.add(new Long (value)); 552 } 553 554 NumberFormatter nf; 555 if (formatter == null) { nf = new NumberFormatter(); 557 nf.prepare(format.evaluateAsString(context)); 558 } else { 559 nf = formatter; 560 } 561 562 CharSequence s = nf.format(vec, gpsize, gpseparator, letterVal, ordinalVal, numb); 563 return new StringValue(s); 564 } 565 566 private void recoverableError(DynamicError error, XPathContext context) throws XPathException { 567 error.setLocator(ExpressionTool.getLocator(this)); 568 context.getController().recoverableError(error); 569 } 570 571 577 578 public static Numberer makeNumberer(String language, XPathContext context) { 579 580 Numberer numberer; 581 if ("en".equals(language)) { 582 numberer = defaultNumberer; 583 } else { 584 String langClassName = "net.sf.saxon.number.Numberer_"; 585 for (int i = 0; i < language.length(); i++) { 586 if (Character.isLetter(language.charAt(i))) { 587 langClassName += language.charAt(i); 588 } 589 } 590 try { 591 Controller controller = context.getController(); 592 Configuration config = controller.getConfiguration(); 593 numberer = (Numberer) (config.getInstance(langClassName, controller.getClassLoader())); 594 } catch (XPathException err) { 595 numberer = defaultNumberer; 596 } 597 } 598 599 return numberer; 600 } 601 602 609 610 public void display(int level, NamePool pool, PrintStream out) { 611 out.println(ExpressionTool.indent(level) + "xsl:number"); 612 } 613 } 614 615 | Popular Tags |