| 1 package net.sf.saxon.value; 2 import net.sf.saxon.Configuration; 3 import net.sf.saxon.Controller; 4 import net.sf.saxon.event.Builder; 5 import net.sf.saxon.event.PipelineConfiguration; 6 import net.sf.saxon.event.Sender; 7 import net.sf.saxon.event.SequenceReceiver; 8 import net.sf.saxon.expr.*; 9 import net.sf.saxon.functions.Aggregate; 10 import net.sf.saxon.om.*; 11 import net.sf.saxon.style.StandardNames; 12 import net.sf.saxon.tinytree.TinyBuilder; 13 import net.sf.saxon.trans.DynamicError; 14 import net.sf.saxon.trans.XPathException; 15 import net.sf.saxon.type.*; 16 17 import javax.xml.transform.Source ; 18 import javax.xml.transform.dom.DOMSource ; 19 import java.io.PrintStream ; 20 import java.io.Serializable ; 21 import java.lang.reflect.Array ; 22 import java.lang.reflect.InvocationTargetException ; 23 import java.lang.reflect.Method ; 24 import java.math.BigDecimal ; 25 import java.math.BigInteger ; 26 import java.net.URI ; 27 import java.net.URL ; 28 import java.util.*; 29 30 35 36 public abstract class Value implements Expression, Serializable , ValueRepresentation { 37 38 46 47 public static Value asValue(ValueRepresentation val) { 48 if (val instanceof Value) { 49 return (Value)val; 50 } else if (val == null) { 51 return EmptySequence.getInstance(); 52 } else { 53 return new SingletonNode((NodeInfo)val); 54 } 55 } 56 57 65 66 public static Item asItem(ValueRepresentation value, XPathContext context) throws XPathException { 67 if (value instanceof Item) { 68 return (Item)value; 69 } else if (value instanceof EmptySequence) { 70 return null; 71 } else if (value instanceof SingletonNode) { 72 return ((SingletonNode)value).getNode(); 73 } else if (value instanceof AtomicValue) { 74 return (AtomicValue)value; 75 } else if (value instanceof Closure) { 76 return ((Closure)value).evaluateItem(context); 77 } else { 78 SequenceIterator iter = Value.getIterator(value); 79 Item item = iter.next(); 80 if (item == null) { 81 return null; 82 } else if (iter.next() != null) { 83 throw new AssertionError ("Attempting to access a sequence as an item"); 84 } else { 85 return item; 86 } 87 } 88 } 89 90 101 102 public static SequenceIterator asIterator(ValueRepresentation val, XPathContext context) throws XPathException { 103 if (val instanceof Value) { 104 return ((Value)val).iterate(context); 105 } else if (val == null) { 106 return EmptyIterator.getInstance(); 107 } else { 108 return SingletonIterator.makeIterator((NodeInfo)val); 109 } 110 } 111 112 113 119 120 public static double stringToNumber(CharSequence s) throws NumberFormatException { 121 String n = trimWhitespace(s).toString(); 122 if ("INF".equals(n)) { 123 return Double.POSITIVE_INFINITY; 124 } else if ("-INF".equals(n)) { 125 return Double.NEGATIVE_INFINITY; 126 } else if ("NaN".equals(n)) { 127 return Double.NaN; 128 } else { 129 return Double.parseDouble(n); 130 } 131 } 132 133 134 137 138 public static CharSequence normalizeWhitespace(CharSequence in) { 139 FastStringBuffer sb = new FastStringBuffer(in.length()); 140 for (int i=0; i<in.length(); i++) { 141 char c = in.charAt(i); 142 switch (c) { 143 case '\n': 144 case '\r': 145 case '\t': 146 sb.append(' '); 147 break; 148 default: 149 sb.append(c); 150 break; 151 } 152 } 153 return sb; 154 } 155 156 159 160 public static CharSequence collapseWhitespace(CharSequence in) { 161 if (in.length()==0) { 162 return in; 163 } 164 165 FastStringBuffer sb = new FastStringBuffer(in.length()); 166 boolean inWhitespace = true; 167 int i = 0; 168 for (; i<in.length(); i++) { 169 char c = in.charAt(i); 170 switch (c) { 171 case '\n': 172 case '\r': 173 case '\t': 174 case ' ': 175 if (inWhitespace) { 176 } else { 178 sb.append(' '); 179 inWhitespace = true; 180 } 181 break; 182 default: 183 sb.append(c); 184 inWhitespace = false; 185 break; 186 } 187 } 188 if (sb.charAt(sb.length()-1)==' ') { 189 sb.setLength(sb.length()-1); 190 } 191 return sb; 192 } 193 194 200 public static CharSequence trimWhitespace(CharSequence in) { 201 if (in.length()==0) { 202 return in; 203 } 204 int first = 0; 205 int last = in.length()-1; 206 while (in.charAt(first) <= 0x20) { 207 if (first++ >= last) { 208 return ""; 209 } 210 } 211 while (in.charAt(last) <= 0x20) { 212 last--; 213 } 214 return in.subSequence(first, last+1); 215 } 216 217 220 221 public static SequenceIterator getIterator(ValueRepresentation val) throws XPathException { 222 if (val instanceof Value) { 223 return ((Value)val).iterate(null); 224 } else if (val instanceof NodeInfo) { 225 return SingletonIterator.makeIterator((NodeInfo)val); 226 } else if (val == null) { 227 throw new AssertionError ("Value of variable is undefined (null)"); 228 } else { 229 throw new AssertionError ("Unknown value representation " + val.getClass()); 230 } 231 } 232 233 237 238 public final Expression simplify(StaticContext env) { 239 return this; 240 } 241 242 246 247 public final Expression typeCheck(StaticContext env, ItemType contextItemType) { 248 return this; 249 } 250 251 255 256 public final Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) { 257 return this; 258 } 259 260 261 265 266 public ItemType getItemType() { 267 return AnyItemType.getInstance(); 268 } 269 270 273 274 public int getCardinality() { 275 try { 276 SequenceIterator iter = iterate(null); 277 Item next = iter.next(); 278 if (next == null) { 279 return StaticProperty.EMPTY; 280 } else { 281 if (iter.next() != null) { 282 return StaticProperty.ALLOWS_ONE_OR_MORE; 283 } else { 284 return StaticProperty.EXACTLY_ONE; 285 } 286 } 287 } catch (XPathException err) { 288 return StaticProperty.ALLOWS_ZERO_OR_MORE; 290 } 291 } 292 293 297 298 public final Iterator iterateSubExpressions() { 299 return Collections.EMPTY_LIST.iterator(); 300 } 301 302 310 311 public final Container getParentExpression() { 312 return null; 313 } 314 315 320 321 322 public int getSpecialProperties() { 323 return StaticProperty.NON_CREATIVE; 324 } 325 326 334 335 public final Expression promote(PromotionOffer offer) { 336 return this; 337 } 338 339 345 346 public final int getDependencies() { 347 return 0; 348 } 349 350 355 356 public Item itemAt(int n) throws XPathException { 357 if ((getImplementationMethod() & EVALUATE_METHOD) != 0) { 358 if (n==0) { 359 Item item = evaluateItem(null); 360 return (item == null ? null : item); 361 } else { 362 return null; 363 } 364 } 365 if (n < 0) { 366 return null; 367 } 368 int i = 0; SequenceIterator iter = iterate(null); 370 while (true) { 371 Item item = iter.next(); 372 if (item == null) { 373 return null; 374 } 375 if (i++ == n) { 376 return item; 377 } 378 } 379 } 380 381 384 385 public int getLength() throws XPathException { 386 return Aggregate.count(iterate(null)); 387 } 388 389 392 393 public Item evaluateItem(XPathContext context) throws XPathException { 394 return iterate(context).next(); 395 } 396 397 398 403 404 public void process(XPathContext context) throws XPathException { 405 SequenceIterator iter = iterate(context); 406 SequenceReceiver out = context.getReceiver(); 407 while (true) { 408 Item it = iter.next(); 409 if (it==null) break; 410 out.append(it, 0, NodeInfo.ALL_NAMESPACES); 411 } 412 } 413 414 415 423 424 public String getStringValue() throws XPathException { 425 FastStringBuffer sb = new FastStringBuffer(1024); 426 SequenceIterator iter = iterate(null); 427 Item item = iter.next(); 428 if (item != null) { 429 while (true) { 430 sb.append(item.getStringValueCS()); 431 item = iter.next(); 432 if (item == null) { 433 break; 434 } 435 sb.append(' '); 436 } 437 } 438 return sb.toString(); 439 } 440 441 457 458 public String evaluateAsString(XPathContext context) throws XPathException { 459 AtomicValue value = (AtomicValue) evaluateItem(context); 460 if (value == null) return ""; 461 return value.getStringValue(); 462 } 463 464 465 475 476 public boolean effectiveBooleanValue(XPathContext context) throws XPathException { 477 return ExpressionTool.effectiveBooleanValue(iterate(context)); 478 } 479 480 486 487 public boolean equals(Object obj) { 488 try { 489 if (obj instanceof Value) { 490 SequenceIterator iter1 = iterate(null); 491 SequenceIterator iter2 = ((Value)obj).iterate(null); 492 while (true) { 493 Item item1 = iter1.next(); 494 Item item2 = iter2.next(); 495 if (item1 == null && item2 == null) { 496 return true; 497 } 498 if (item1 == null || item2 == null) { 499 return false; 500 } 501 if (item1 instanceof NodeInfo || item2 instanceof NodeInfo) { 502 return false; 503 } 504 if (!item1.equals(item2)) { 505 return false; 506 } 507 } 508 } else { 509 return false; 510 } 511 } catch (XPathException e) { 512 return false; 513 } 514 } 515 516 522 523 public boolean schemaEquals(Value obj) { 524 try { 525 SequenceIterator iter1 = iterate(null); 526 SequenceIterator iter2 = obj.iterate(null); 527 while (true) { 528 Item item1 = iter1.next(); 529 Item item2 = iter2.next(); 530 if (item1 == null && item2 == null) { 531 return true; 532 } 533 if (item1 == null || item2 == null) { 534 return false; 535 } 536 if (item1 instanceof NodeInfo || item2 instanceof NodeInfo) { 537 return false; 538 } 539 if (!((AtomicValue)item1).schemaEquals((AtomicValue)item2)) { 540 return false; 541 } 542 } 543 } catch (XPathException e) { 544 return false; 545 } 546 } 547 548 551 552 public int hashCode() { 553 try { 554 int hash = 0x06639662; SequenceIterator iter = iterate(null); 556 while (true) { 557 Item item = iter.next(); 558 if (item == null) { 559 return hash; 560 } 561 hash ^= item.hashCode(); 562 } 563 } catch (XPathException e) { 564 return 0; 565 } 566 } 567 568 569 577 578 public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { 579 return; 580 } 581 582 588 589 public Value reduce() throws XPathException { 590 return this; 591 } 592 593 596 597 public Object convertToJava(Class target, XPathContext context) throws XPathException { 598 599 if (target == Object .class) { 600 List list = new ArrayList(20); 601 return convertToJavaList(list, context); 602 } 603 604 606 if (target.isAssignableFrom(this.getClass())) { 607 return this; 608 } else if (target.isAssignableFrom(SequenceIterator.class)) { 609 return iterate(context); 610 } 611 612 614 if ((this instanceof ObjectValue || !(this instanceof AtomicValue)) && !(this instanceof EmptySequence)) { 615 List externalObjectModels = context.getController().getConfiguration().getExternalObjectModels(); 616 for (int m=0; m<externalObjectModels.size(); m++) { 617 ExternalObjectModel model = (ExternalObjectModel)externalObjectModels.get(m); 618 Object object = model.convertXPathValueToObject(this, target, context); 619 if (object != null) { 620 return object; 621 } 622 } 623 } 624 625 if (Collection.class.isAssignableFrom(target)) { 626 Collection list; 627 if (target.isAssignableFrom(ArrayList.class)) { 628 list = new ArrayList(100); 629 } else { 630 try { 631 list = (Collection)target.newInstance(); 632 } catch (InstantiationException e) { 633 DynamicError de = new DynamicError("Cannot instantiate collection class " + target); 634 de.setXPathContext(context); 635 throw de; 636 } catch (IllegalAccessException e) { 637 DynamicError de = new DynamicError("Cannot access collection class " + target); 638 de.setXPathContext(context); 639 throw de; 640 } 641 } 642 return convertToJavaList(list, context); 643 } else if (target.isArray()) { 644 Class component = target.getComponentType(); 645 if (component.isAssignableFrom(Item.class) || 646 component.isAssignableFrom(NodeInfo.class) || 647 component.isAssignableFrom(DocumentInfo.class)) { 648 Value extent = this; 649 if (extent instanceof Closure) { 650 extent = SequenceExtent.makeSequenceExtent(extent.iterate(null)); 651 } 652 int length = extent.getLength(); 653 Object array = Array.newInstance(component, length); 654 SequenceIterator iter = extent.iterate(null); 655 for (int i=0; i<length; i++) { 656 Item item = iter.next(); 657 try { 658 Array.set(array, i, item); 659 } catch (IllegalArgumentException err) { 660 DynamicError d = new DynamicError( 661 "Item " + i + " in supplied sequence cannot be converted " + 662 "to the component type of the Java array (" + component + ')', err); 663 d.setXPathContext(context); 664 throw d; 665 } 666 } 667 return array; 668 } else { 669 SequenceIterator it = Atomizer.AtomizingFunction.getAtomizingIterator(iterate(context)); 672 int length; 673 if ((it.getProperties() & SequenceIterator.LAST_POSITION_FINDER) != 0) { 674 length = ((LastPositionFinder)it).getLastPosition(); 675 } else { 676 SequenceExtent extent = new SequenceExtent(it); 677 length = extent.getLength(); 678 it = extent.iterate(context); 679 } 680 Object array = Array.newInstance(component, length); 681 for (int i=0; i<length; i++) { 682 try { 683 AtomicValue val = (AtomicValue)it.next(); 684 Object jval = val.convertToJava(component, context); 685 Array.set(array, i, jval); 686 } catch (XPathException err) { 687 DynamicError d = new DynamicError( 688 "Cannot convert item in atomized sequence to the component type of the Java array", err); 689 d.setXPathContext(context); 690 throw d; 691 } 692 } 693 return array; 694 } 700 701 } else if (target.isAssignableFrom(Item.class) || 702 target.isAssignableFrom(NodeInfo.class) || 703 target.isAssignableFrom(DocumentInfo.class)) { 704 705 SequenceIterator iter = iterate(null); 707 Item first = null; 708 while (true) { 709 Item next = iter.next(); 710 if (next == null) { 711 break; 712 } 713 if (first != null) { 714 DynamicError err = new DynamicError("Sequence contains more than one value; Java method expects only one"); 715 err.setXPathContext(context); 716 throw err; 717 } 718 first = next; 719 } 720 if (first == null) { 721 return null; 723 } 724 if (target.isAssignableFrom(first.getClass())) { 725 return first; 727 } 728 729 Object n = first; 730 while (n instanceof VirtualNode) { 731 Object vn = ((VirtualNode) n).getUnderlyingNode(); 734 if (target.isAssignableFrom(vn.getClass())) { 735 return vn; 736 } else { 737 n = vn; 738 } 739 } 740 741 throw new DynamicError("Cannot convert supplied XPath value to the required type for the extension function"); 742 } else if (!(this instanceof AtomicValue)) { 743 SequenceIterator it = Atomizer.AtomizingFunction.getAtomizingIterator(iterate(context)); 745 Item first = null; 746 while (true) { 747 Item next = it.next(); 748 if (next == null) { 749 break; 750 } 751 if (first != null) { 752 DynamicError err = new DynamicError("Sequence contains more than one value; Java method expects only one"); 753 err.setXPathContext(context); 754 throw err; 755 } 756 first = next; 757 } 758 if (first == null) { 759 return null; 761 } 762 if (target.isAssignableFrom(first.getClass())) { 763 return first; 764 } else { 765 return ((AtomicValue)first).convertToJava(target, context); 766 } 767 } else { 768 throw new DynamicError("Cannot convert supplied XPath value to the required type for the extension function"); 769 } 770 } 771 772 private Collection convertToJavaList(Collection list, XPathContext context) throws XPathException { 773 SequenceIterator iter = iterate(null); 775 while (true) { 776 Item it = iter.next(); 777 if (it == null) { 778 return list; 783 } 785 if (it instanceof AtomicValue) { 786 list.add(((AtomicValue)it).convertToJava(Object .class, context)); 787 } else if (it instanceof VirtualNode) { 788 list.add(((VirtualNode)it).getUnderlyingNode()); 789 } else { 790 list.add(it); 791 } 792 } 793 } 794 795 |