1 package net.sf.saxon.jdom; 2 import net.sf.saxon.Configuration; 3 import net.sf.saxon.event.Receiver; 4 import net.sf.saxon.om.*; 5 import net.sf.saxon.pattern.AnyNodeTest; 6 import net.sf.saxon.pattern.NodeTest; 7 import net.sf.saxon.style.StandardNames; 8 import net.sf.saxon.trans.XPathException; 9 import net.sf.saxon.type.Type; 10 import net.sf.saxon.value.UntypedAtomicValue; 11 import net.sf.saxon.value.Value; 12 import org.jdom.*; 13 14 import java.util.Iterator ; 15 import java.util.List ; 16 import java.util.ListIterator ; 17 import java.util.ArrayList ; 18 19 24 25 public class NodeWrapper implements NodeInfo, VirtualNode, SiblingCountingNode { 26 27 protected Object node; protected short nodeKind; 30 private NodeWrapper parent; protected DocumentWrapper docWrapper; 32 protected int index; 35 42 protected NodeWrapper(Object node, NodeWrapper parent, int index) { 43 this.node = node; 44 this.parent = parent; 45 this.index = index; 46 } 47 48 55 protected NodeWrapper makeWrapper(Object node, DocumentWrapper docWrapper) { 56 return makeWrapper(node, docWrapper, null, -1); 57 } 58 59 68 69 protected NodeWrapper makeWrapper(Object node, DocumentWrapper docWrapper, 70 NodeWrapper parent, int index) { 71 NodeWrapper wrapper; 72 if (node instanceof Document) { 73 return docWrapper; 74 } else if (node instanceof Element) { 75 wrapper = new NodeWrapper(node, parent, index); 76 wrapper.nodeKind = Type.ELEMENT; 77 } else if (node instanceof Attribute) { 78 wrapper = new NodeWrapper(node, parent, index); 79 wrapper.nodeKind = Type.ATTRIBUTE; 80 } else if (node instanceof String || node instanceof Text) { 81 wrapper = new NodeWrapper(node, parent, index); 82 wrapper.nodeKind = Type.TEXT; 83 } else if (node instanceof Comment) { 84 wrapper = new NodeWrapper(node, parent, index); 85 wrapper.nodeKind = Type.COMMENT; 86 } else if (node instanceof ProcessingInstruction) { 87 wrapper = new NodeWrapper(node, parent, index); 88 wrapper.nodeKind = Type.PROCESSING_INSTRUCTION; 89 } else if (node instanceof Namespace) { 90 throw new IllegalArgumentException ("Cannot wrap JDOM namespace objects"); 91 } else { 92 throw new IllegalArgumentException ("Bad node type in JDOM! " + node.getClass() + " instance " + node.toString()); 93 } 94 wrapper.docWrapper = docWrapper; 95 return wrapper; 96 } 97 98 101 102 public Object getUnderlyingNode() { 103 if (node instanceof List ) { 104 return ((List )node).get(0); 105 } else { 106 return node; 107 } 108 } 109 110 113 114 public Configuration getConfiguration() { 115 return docWrapper.getConfiguration(); 116 } 117 118 122 123 public NamePool getNamePool() { 124 return docWrapper.getNamePool(); 125 } 126 127 131 132 public int getNodeKind() { 133 return nodeKind; 134 } 135 136 139 140 public SequenceIterator getTypedValue() { 141 return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValueCS())); 142 } 143 144 154 155 public Value atomize() throws XPathException { 156 return new UntypedAtomicValue(getStringValueCS()); 157 } 158 159 163 164 public int getTypeAnnotation() { 165 return -1; 166 } 167 168 174 175 public boolean isSameNodeInfo(NodeInfo other) { 176 if (!(other instanceof NodeWrapper)) { 177 return false; 178 } 179 NodeWrapper ow = (NodeWrapper)other; 180 return node.equals(ow.node); 184 } 185 186 192 193 public String getSystemId() { 194 return docWrapper.baseURI; 195 } 196 197 public void setSystemId(String uri) { 198 docWrapper.baseURI = uri; 199 } 200 201 205 206 public String getBaseURI() { 207 if (getNodeKind() == Type.NAMESPACE) { 208 return null; 209 } 210 NodeInfo n = this; 211 if (getNodeKind() != Type.ELEMENT) { 212 n = getParent(); 213 } 214 while (n != null) { 216 String xmlbase = n.getAttributeValue(StandardNames.XML_BASE); 217 if (xmlbase != null) { 218 return xmlbase; 219 } 220 n = n.getParent(); 221 } 222 return docWrapper.baseURI; 224 } 225 226 231 232 public int getLineNumber() { 233 return -1; 234 } 235 236 244 245 public int compareOrder(NodeInfo other) { 246 if (other instanceof SiblingCountingNode) { 247 return Navigator.compareOrder(this, (SiblingCountingNode)other); 248 } else { 249 return -other.compareOrder(this); 251 } 252 } 253 254 260 261 public String getStringValue() { 262 return getStringValueCS().toString(); 263 } 264 265 269 270 public CharSequence getStringValueCS() { 271 if (node instanceof List ) { 272 List nodes = (List )node; 274 FastStringBuffer fsb = new FastStringBuffer(100); 275 for (int i=0; i<nodes.size(); i++) { 276 Text o = (Text)nodes.get(i); 277 fsb.append(getStringValue(o)); 278 } 279 return fsb; 280 } else { 281 return getStringValue(node); 282 } 283 } 284 285 288 289 private static String getStringValue(Object node) { 290 if (node instanceof Document) { 291 List children1 = ((Document)node).getContent(); 292 FastStringBuffer sb1 = new FastStringBuffer(2048); 293 expandStringValue(children1, sb1); 294 return sb1.toString(); 295 } else if (node instanceof Element) { 296 return ((Element)node).getValue(); 297 } else if (node instanceof Attribute) { 298 return ((Attribute)node).getValue(); 299 } else if (node instanceof Text) { 300 return ((Text)node).getText(); 301 } else if (node instanceof String ) { 302 return (String )node; 303 } else if (node instanceof Comment) { 304 return ((Comment)node).getText(); 305 } else if (node instanceof ProcessingInstruction) { 306 return ((ProcessingInstruction)node).getData(); 307 } else if (node instanceof Namespace) { 308 return ((Namespace)node).getURI(); 309 } else { 310 return ""; 311 } 312 } 313 314 320 private static void expandStringValue(List list, FastStringBuffer sb) { 321 Iterator iter = list.iterator(); 322 while (iter.hasNext()) { 323 Object obj = iter.next(); 324 if (obj instanceof Element) { 325 sb.append(((Element)obj).getValue()); 326 } else if (obj instanceof Text) { 327 sb.append(((Text)obj).getText()); 328 } else if (obj instanceof EntityRef) { 329 throw new IllegalStateException ("Unexpanded entity in JDOM tree"); 330 } else if (obj instanceof DocType) { 331 } else { 333 throw new AssertionError ("Unknown JDOM node type"); 334 } 335 } 336 } 337 338 346 347 public int getNameCode() { 348 switch (nodeKind) { 349 case Type.ELEMENT: 350 case Type.ATTRIBUTE: 351 case Type.PROCESSING_INSTRUCTION: 352 case Type.NAMESPACE: 353 return docWrapper.getNamePool().allocate(getPrefix(), 354 getURI(), 355 getLocalPart()); 356 default: 357 return -1; 358 } 359 } 360 361 367 368 public int getFingerprint() { 369 int nc = getNameCode(); 370 if (nc == -1) { 371 return -1; 372 } else { 373 return nc&0xfffff; 374 } 375 } 376 377 381 382 public String getLocalPart() { 383 switch (nodeKind) { 384 case Type.ELEMENT: 385 return ((Element)node).getName(); 386 case Type.ATTRIBUTE: 387 return ((Attribute)node).getName(); 388 case Type.TEXT: 389 case Type.COMMENT: 390 case Type.DOCUMENT: 391 return ""; 392 case Type.PROCESSING_INSTRUCTION: 393 return ((ProcessingInstruction)node).getTarget(); 394 case Type.NAMESPACE: 395 return ((Namespace)node).getPrefix(); 396 default: 397 return null; 398 } 399 } 400 401 406 407 public String getPrefix() { 408 switch (nodeKind) { 409 case Type.ELEMENT: 410 return ((Element)node).getNamespacePrefix(); 411 case Type.ATTRIBUTE: 412 return ((Attribute)node).getNamespacePrefix(); 413 default: 414 return ""; 415 } 416 } 417 418 425 426 public String getURI() { 427 switch (nodeKind) { 428 case Type.ELEMENT: 429 return ((Element)node).getNamespaceURI(); 430 case Type.ATTRIBUTE: 431 return ((Attribute)node).getNamespaceURI(); 432 default: 433 return ""; 434 } 435 } 436 437 443 444 public String getDisplayName() { 445 switch (nodeKind) { 446 case Type.ELEMENT: 447 return ((Element)node).getQualifiedName(); 448 case Type.ATTRIBUTE: 449 return ((Attribute)node).getQualifiedName(); 450 case Type.PROCESSING_INSTRUCTION: 451 case Type.NAMESPACE: 452 return getLocalPart(); 453 default: 454 return ""; 455 456 } 457 } 458 459 462 463 public NodeInfo getParent() { 464 if (parent==null) { 465 if (node instanceof Element) { 466 if (((Element)node).isRootElement()) { 467 parent = makeWrapper(((Element)node).getDocument(), docWrapper); 468 } else { 469 parent = makeWrapper(((Element)node).getParent(), docWrapper); 470 } 471 } else if (node instanceof Text) { 472 parent = makeWrapper(((Text)node).getParent(), docWrapper); 473 } else if (node instanceof Comment) { 474 parent = makeWrapper(((Comment)node).getParent(), docWrapper); 475 } else if (node instanceof ProcessingInstruction) { 476 parent = makeWrapper(((ProcessingInstruction)node).getParent(), docWrapper); 477 } else if (node instanceof Attribute) { 478 parent = makeWrapper(((Attribute)node).getParent(), docWrapper); 479 } else if (node instanceof Document) { 480 parent = null; 481 } else if (node instanceof Namespace) { 482 throw new UnsupportedOperationException ("Cannot find parent of JDOM namespace node"); 483 } else { 484 throw new IllegalStateException ("Unknown JDOM node type " + node.getClass()); 485 } 486 } 487 return parent; 488 } 489 490 498 499 public int getSiblingPosition() { 500 if (index == -1) { 501 int ix = 0; 502 getParent(); 503 AxisIterator iter; 504 switch (nodeKind) { 505 case Type.ELEMENT: 506 case Type.TEXT: 507 case Type.COMMENT: 508 case Type.PROCESSING_INSTRUCTION: 509 iter = parent.iterateAxis(Axis.CHILD); 510 break; 511 case Type.ATTRIBUTE: 512 iter = parent.iterateAxis(Axis.ATTRIBUTE); 513 break; 514 case Type.NAMESPACE: 515 iter = parent.iterateAxis(Axis.NAMESPACE); 516 break; 517 default: 518 index = 0; 519 return index; 520 } 521 while (true) { 522 NodeInfo n = (NodeInfo)iter.next(); 523 if (n == null) { 524 break; 525 } 526 if (n.isSameNodeInfo(this)) { 527 index = ix; 528 return index; 529 } 530 if (((NodeWrapper)n).node instanceof List ) { 531 ix += ((List )(((NodeWrapper)n).node)).size(); 532 } else { 533 ix++; 534 } 535 } 536 throw new IllegalStateException ("JDOM node not linked to parent node"); 537 } 538 return index; 539 } 540 541 546 547 public AxisIterator iterateAxis(byte axisNumber) { 548 return iterateAxis(axisNumber, AnyNodeTest.getInstance()); 549 } 550 551 557 558 public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { 559 switch (axisNumber) { 560 case Axis.ANCESTOR: 561 if (nodeKind==Type.DOCUMENT) return EmptyIterator.getInstance(); 562 return new Navigator.AxisFilter( 563 new Navigator.AncestorEnumeration(this, false), 564 nodeTest); 565 566 case Axis.ANCESTOR_OR_SELF: 567 if (nodeKind==Type.DOCUMENT) return EmptyIterator.getInstance(); 568 return new Navigator.AxisFilter( 569 new Navigator.AncestorEnumeration(this, true), 570 nodeTest); 571 572 case Axis.ATTRIBUTE: 573 if (nodeKind!=Type.ELEMENT) return EmptyIterator.getInstance(); 574 return new Navigator.AxisFilter( 575 new AttributeEnumeration(this), 576 nodeTest); 577 578 case Axis.CHILD: 579 if (hasChildNodes()) { 580 return new Navigator.AxisFilter( 581 new ChildEnumeration(this, true, true), 582 nodeTest); 583 } else { 584 return EmptyIterator.getInstance(); 585 } 586 587 case Axis.DESCENDANT: 588 if (hasChildNodes()) { 589 return new Navigator.AxisFilter( 590 new Navigator.DescendantEnumeration(this, false, true), 591 nodeTest); 592 } else { 593 return EmptyIterator.getInstance(); 594 } 595 596 case Axis.DESCENDANT_OR_SELF: 597 return new Navigator.AxisFilter( 598 new Navigator.DescendantEnumeration(this, true, true), 599 nodeTest); 600 601 case Axis.FOLLOWING: 602 return new Navigator.AxisFilter( 603 new Navigator.FollowingEnumeration(this), 604 nodeTest); 605 606 case Axis.FOLLOWING_SIBLING: 607 switch (nodeKind) { 608 case Type.DOCUMENT: 609 case Type.ATTRIBUTE: 610 case Type.NAMESPACE: 611 return EmptyIterator.getInstance(); 612 default: 613 return new Navigator.AxisFilter( 614 new ChildEnumeration(this, false, true), 615 nodeTest); 616 } 617 618 case Axis.NAMESPACE: 619 if (nodeKind!=Type.ELEMENT) { 620 return EmptyIterator.getInstance(); 621 } 622 return new NamespaceIterator(this, nodeTest); 623 624 case Axis.PARENT: 625 getParent(); 626 if (parent==null) return EmptyIterator.getInstance(); 627 if (nodeTest.matches(parent)) { 628 return SingletonIterator.makeIterator(parent); 629 } 630 return EmptyIterator.getInstance(); 631 632 case Axis.PRECEDING: 633 return new Navigator.AxisFilter( 634 new Navigator.PrecedingEnumeration(this, false), 635 nodeTest); 636 637 case Axis.PRECEDING_SIBLING: 638 switch (nodeKind) { 639 case Type.DOCUMENT: 640 case Type.ATTRIBUTE: 641 case Type.NAMESPACE: 642 return EmptyIterator.getInstance(); 643 default: 644 return new Navigator.AxisFilter( 645 new ChildEnumeration(this, false, false), 646 nodeTest); 647 } 648 649 case Axis.SELF: 650 if (nodeTest.matches(this)) { 651 return SingletonIterator.makeIterator(this); 652 } 653 return EmptyIterator.getInstance(); 654 655 case Axis.PRECEDING_OR_ANCESTOR: 656 return new Navigator.AxisFilter( 657 new Navigator.PrecedingEnumeration(this, true), 658 nodeTest); 659 660 default: 661 throw new IllegalArgumentException ("Unknown axis number " + axisNumber); 662 } 663 } 664 665 670 671 public String getAttributeValue(int fingerprint) { 672 if (nodeKind==Type.ELEMENT) { 673 NamePool pool = docWrapper.getNamePool(); 674 String uri = pool.getURI(fingerprint); 675 String local = pool.getLocalName(fingerprint); 676 return ((Element)node).getAttributeValue(local, 677 ( uri.equals(NamespaceConstant.XML) ? 678 Namespace.XML_NAMESPACE : 679 Namespace.getNamespace(uri))); 680 } 682 return null; 683 } 684 685 689 690 public NodeInfo getRoot() { 691 return docWrapper; 692 } 693 694 698 699 public DocumentInfo getDocumentRoot() { 700 return docWrapper; 701 } 702 703 708 709 public boolean hasChildNodes() { 710 switch (nodeKind) { 711 case Type.DOCUMENT: 712 return true; 713 case Type.ELEMENT: 714 return !((Element)node).getContent().isEmpty(); 715 default: 716 return false; 717 } 718 } 719 725 726 public String generateId() { 727 return Navigator.getSequentialKey(this); 728 } 729 730 734 735 public int getDocumentNumber() { 736 return getDocumentRoot().getDocumentNumber(); 737 } 738 739 742 743 public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { 744 Navigator.copy(this, out, docWrapper.getNamePool(), whichNamespaces, copyAnnotations, locationId); 745 } 746 747 753 754 public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors) 755 throws XPathException { 756 Navigator.sendNamespaceDeclarations(this, out, includeAncestors); 757 } 758 759 774 775 public int[] getDeclaredNamespaces(int[] buffer) { 776 if (node instanceof Element) { 777 Element elem = (Element)node; 778 List addl = elem.getAdditionalNamespaces(); 779 int size = addl.size() + 1; 780 int[] result = (size <= buffer.length ? buffer : new int[size]); 781 NamePool pool = getNamePool(); 782 Namespace ns = elem.getNamespace(); 783 String prefix = ns.getPrefix(); 784 String uri = ns.getURI(); 785 result[0] = pool.allocateNamespaceCode(prefix, uri); 786 int i = 1; 787 if (addl.size() > 0) { 788 Iterator itr = addl.iterator(); 789 while (itr.hasNext()) { 790 ns = (Namespace) itr.next(); 791 result[i++] = pool.allocateNamespaceCode(ns.getPrefix(), ns.getURI()); 792 } 793 } 794 if (size < buffer.length) { 795 result[size] = -1; 796 } 797 return result; 798 } else { 799 return null; 800 } 801 } 802 806 807 private final class AttributeEnumeration extends Navigator.BaseEnumeration { 808 809 private Iterator atts; 810 private int ix = 0; 811 private NodeWrapper start; 812 813 public AttributeEnumeration(NodeWrapper start) { 814 this.start = start; 815 atts = ((Element)start.node).getAttributes().iterator(); 816 } 817 818 public void advance() { 819 if (atts.hasNext()) { 820 current = makeWrapper(atts.next(), docWrapper, start, ix++); 821 } else { 822 current = null; 823 } 824 } 825 826 public SequenceIterator getAnother() { 827 return new AttributeEnumeration(start); 828 } 829 830 } 832 833 839 840 private final class ChildEnumeration extends Navigator.BaseEnumeration { 841 842 private NodeWrapper start; 843 private NodeWrapper commonParent; 844 private ListIterator children; 845 private int ix = 0; 846 private boolean downwards; private boolean forwards; 849 public ChildEnumeration(NodeWrapper start, 850 boolean downwards, boolean forwards) { 851 this.start = start; 852 this.downwards = downwards; 853 this.forwards = forwards; 854 855 if (downwards) { 856 commonParent = start; 857 } else { 858 commonParent = (NodeWrapper)start.getParent(); 859 } 860 861 if (commonParent.getNodeKind()==Type.DOCUMENT) { 862 children = ((Document)commonParent.node).getContent().listIterator(); 863 } else { 864 children = ((Element)commonParent.node).getContent().listIterator(); 865 } 866 867 if (downwards) { 868 if (!forwards) { 869 while (children.hasNext()) { 871 children.next(); 872 ix++; 873 } 874 } 875 } else { 876 ix = start.getSiblingPosition(); 877 Object n = null; 879 if (forwards) { 880 for (int i=0; i<=ix; i++) { 881 n = children.next(); 882 } 883 if (n instanceof Text) { 884 boolean atEnd = false; 886 while (n instanceof Text) { 887 if (children.hasNext()) { 888 n = children.next(); 889 ix++; 890 } else { 891 atEnd = true; 892 break; 893 } 894 } 895 if (!atEnd) { 896 children.previous(); 897 } 898 } else { 899 ix++; 900 } 901 } else { 902 for (int i=0; i<ix; i++) { 903 children.next(); 904 } 905 ix--; 906 } 907 } 908 } 909 910 public void advance() { 911 if (forwards) { 912 if (children.hasNext()) { 913 Object nextChild = children.next(); 914 if (nextChild instanceof DocType) { 915 advance(); 916 return; 917 } 918 if (nextChild instanceof EntityRef) { 919 throw new IllegalStateException ("Unexpanded entity in JDOM tree"); 920 } else if (nextChild instanceof Text) { 921 if (isAtomizing()) { 923 FastStringBuffer fsb = new FastStringBuffer(100); 924 fsb.append(getStringValue(node)); 925 while (children.hasNext()) { 926 Object n = children.next(); 927 if (n instanceof Text) { 928 fsb.append(getStringValue(n)); 929 ix++; 930 } else { 931 children.previous(); 933 break; 934 } 935 } 936 current = new UntypedAtomicValue(fsb); 937 } else { 938 current = makeWrapper(nextChild, docWrapper, commonParent, ix++); 939 List list = null; 940 while (children.hasNext()) { 941 Object n = children.next(); 942 if (n instanceof Text) { 943 if (list == null) { 944 list = new ArrayList (4); 945 list.add(((NodeWrapper)current).node); 946 } 947 list.add(n); 948 ix++; 949 } else { 950 children.previous(); 952 break; 953 } 954 } 955 if (list != null) { 956 ((NodeWrapper)current).node = list; 957 } 958 } 959 } else { 960 if (isAtomizing()) { 961 current = new UntypedAtomicValue(getStringValue(node)); 962 } else { 963 current = makeWrapper(nextChild, docWrapper, commonParent, ix++); 964 } 965 } 966 } else { 967 current = null; 968 } 969 } else { if (children.hasPrevious()) { 971 Object nextChild = children.previous(); 972 if (nextChild instanceof DocType) { 973 advance(); 974 return; 975 } 976 if (nextChild instanceof EntityRef) { 977 throw new IllegalStateException ("Unexpanded entity in JDOM tree"); 978 } else if (nextChild instanceof Text) { 979 if (isAtomizing()) { 981 StringBuffer sb = new StringBuffer (100); 982 sb.insert(0, getStringValue(nextChild)); 983 while (children.hasPrevious()) { 984 Object n = children.previous(); 985 if (n instanceof Text) { 986 sb.insert(0, getStringValue(n)); 987 ix--; 988 } else { 989 children.next(); 991 break; 992 } 993 } 994 current = new UntypedAtomicValue(sb); 995 } else { 996 current = makeWrapper(nextChild, docWrapper, commonParent, ix--); 997 List list = null; 998 while (children.hasPrevious()) { 999 Object n = children.previous(); 1000 if (n instanceof Text) { 1001 if (list == null) { 1002 list = new ArrayList (4); 1003 list.add(((NodeWrapper)current).node); 1004 } 1005 list.add(0, n); 1006 ix--; 1007 } else { 1008 children.next(); 1010 break; 1011 } 1012 } 1013 if (list != null) { 1014 ((NodeWrapper)current).node = list; 1015 } 1016 } 1017 } else { 1018 if (isAtomizing()) { 1019 current = new UntypedAtomicValue(getStringValue(node)); 1020 } else { 1021 current = makeWrapper(nextChild, docWrapper, commonParent, ix--); 1022 } 1023 } 1024 } else { 1025 current = null; 1026 } 1027 } 1028 } 1029 1030 public SequenceIterator getAnother() { 1031 return new ChildEnumeration(start, downwards, forwards); 1032 } 1033 1034 } 1036} 1037 1038 | Popular Tags |