1 package net.sf.saxon.om; 2 3 import net.sf.saxon.Controller; 4 import net.sf.saxon.event.Receiver; 5 import net.sf.saxon.expr.Expression; 6 import net.sf.saxon.expr.ReversibleIterator; 7 import net.sf.saxon.expr.XPathContext; 8 import net.sf.saxon.functions.EscapeURI; 9 import net.sf.saxon.pattern.*; 10 import net.sf.saxon.style.StandardNames; 11 import net.sf.saxon.trans.XPathException; 12 import net.sf.saxon.type.Type; 13 import net.sf.saxon.value.SequenceExtent; 14 import net.sf.saxon.value.Whitespace; 15 16 import java.net.URI ; 17 import java.net.URISyntaxException ; 18 import java.util.ArrayList ; 19 import java.util.List ; 20 21 22 28 29 30 31 public final class Navigator { 32 33 private Navigator() { 35 } 36 37 42 43 public static String getAttributeValue(NodeInfo element, String uri, String localName) { 44 int fingerprint = element.getNamePool().allocate("", uri, localName); 45 return element.getAttributeValue(fingerprint); 46 } 47 48 51 52 public static String getBaseURI(NodeInfo element) { 53 String xmlBase = element.getAttributeValue(StandardNames.XML_BASE); 54 if (xmlBase!=null) { 55 String escaped = EscapeURI.escape(xmlBase, false).toString(); 56 URI escapedURI; 57 try { 58 escapedURI = new URI(escaped); 59 if (!escapedURI.isAbsolute()) { 60 NodeInfo parent = element.getParent(); 61 if (parent==null) { 62 return escapedURI.toString(); 63 } 64 String startSystemId = element.getSystemId(); 65 String parentSystemId = parent.getSystemId(); 66 if (startSystemId.equals(parentSystemId)) { 67 URI base = new URI(element.getParent().getBaseURI()); 68 escapedURI = base.resolve(escapedURI); 69 } else { 70 URI base = new URI(startSystemId); 71 escapedURI = base.resolve(escapedURI); 72 } 73 } 74 } catch (URISyntaxException e) { 75 return xmlBase; 78 } 79 return escapedURI.toString(); 80 } 81 String startSystemId = element.getSystemId(); 82 NodeInfo parent = element.getParent(); 83 if (parent==null) { 84 return startSystemId; 85 } 86 String parentSystemId = parent.getSystemId(); 87 if (startSystemId.equals(parentSystemId)) { 88 return parent.getBaseURI(); 89 } else { 90 return startSystemId; 91 } 92 } 93 94 102 103 public static void sendNamespaceDeclarations(NodeInfo node, Receiver out, boolean includeAncestors) 104 throws XPathException { 105 if (node.getNodeKind() == Type.ELEMENT) { 106 int[] codes; 107 if (includeAncestors) { 108 codes = new NamespaceIterator(node, null).getInScopeNamespaceCodes(); 109 } else { 110 codes = node.getDeclaredNamespaces(NodeInfo.EMPTY_NAMESPACE_LIST); 111 } 112 for (int i=0; i<codes.length; i++) { 113 if (codes[i] == -1) break; 114 out.namespace(codes[i], 0); 115 } 116 } 117 } 118 119 127 128 public static String getPath(NodeInfo node) { 129 if (node==null) { 130 return ""; 131 } 132 String pre; 133 NodeInfo parent = node.getParent(); 134 136 switch (node.getNodeKind()) { 137 case Type.DOCUMENT: 138 return "/"; 139 case Type.ELEMENT: 140 if (parent==null) { 141 return node.getDisplayName(); 142 } else { 143 pre = getPath(parent); 144 if (pre.equals("/")) { 145 return '/' + node.getDisplayName(); 146 } else { 147 return pre + '/' + node.getDisplayName() + '[' + getNumberSimple(node) + ']'; 148 } 149 } 150 case Type.ATTRIBUTE: 151 return getPath(parent) + "/@" + node.getDisplayName(); 152 case Type.TEXT: 153 pre = getPath(parent); 154 return (pre.equals("/") ? "" : pre) + 155 "/text()[" + getNumberSimple(node) + ']'; 156 case Type.COMMENT: 157 pre = getPath(parent); 158 return (pre.equals("/") ? "" : pre) + 159 "/comment()[" + getNumberSimple(node) + ']'; 160 case Type.PROCESSING_INSTRUCTION: 161 pre = getPath(parent); 162 return (pre.equals("/") ? "" : pre) + 163 "/processing-instruction()[" + getNumberSimple(node) + ']'; 164 case Type.NAMESPACE: 165 String test = node.getLocalPart(); 166 if (test.equals("")) { 167 test="*[not(local-name()]"; 169 } 170 return getPath(parent)+ "/namespace::" + test; 171 default: 172 return ""; 173 } 174 } 175 176 186 187 public static int getNumberSimple(NodeInfo node, XPathContext context) throws XPathException { 188 189 191 int fingerprint = node.getFingerprint(); 192 NodeTest same; 193 194 if (fingerprint==-1) { 195 same = NodeKindTest.makeNodeKindTest(node.getNodeKind()); 196 } else { 197 same = new NameTest(node); 198 } 199 200 SequenceIterator preceding = node.iterateAxis(Axis.PRECEDING_SIBLING, same); 201 202 int i=1; 203 while (true) { 204 NodeInfo prev = (NodeInfo)preceding.next(); 205 if (prev == null) { 206 break; 207 } 208 209 Controller controller = context.getController(); 210 int memo = controller.getRememberedNumber(prev); 211 if (memo>0) { 212 memo += i; 213 controller.setRememberedNumber(node, memo); 214 return memo; 215 } 216 217 i++; 218 } 219 220 context.getController().setRememberedNumber(node, i); 221 return i; 222 } 223 224 232 233 private static int getNumberSimple(NodeInfo node) { 234 235 int fingerprint = node.getFingerprint(); 236 NodeTest same; 237 238 if (fingerprint==-1) { 239 same = NodeKindTest.makeNodeKindTest(node.getNodeKind()); 240 } else { 241 same = new NameTest(node); 242 } 243 244 AxisIterator preceding = node.iterateAxis(Axis.PRECEDING_SIBLING, same); 245 246 int i=1; 247 while (preceding.next() != null) { 248 i++; 249 } 250 251 return i; 252 } 253 254 276 277 public static int getNumberSingle(NodeInfo node, Pattern count, 278 Pattern from, XPathContext context) throws XPathException { 279 280 282 if (count==null && from==null) { 283 return getNumberSimple(node, context); 284 } 285 286 boolean knownToMatch = false; 287 if (count==null) { 288 if (node.getFingerprint()==-1) { count = new NodeTestPattern(NodeKindTest.makeNodeKindTest(node.getNodeKind())); 290 } else { 291 count = new NodeTestPattern(new NameTest(node)); 292 } 293 knownToMatch = true; 294 } 295 296 NodeInfo target = node; 297 while (!(knownToMatch || count.matches(target, context))) { 298 target = target.getParent(); 299 if (target==null) { 300 return 0; 301 } 302 if (from!=null && from.matches(target, context)) { 303 return 0; 304 } 305 } 306 307 309 SequenceIterator preceding = 310 target.iterateAxis(Axis.PRECEDING_SIBLING, count.getNodeTest()); 311 boolean alreadyChecked = (count instanceof NodeTestPattern); 313 int i = 1; 314 while (true) { 315 NodeInfo p = (NodeInfo)preceding.next(); 316 if (p == null) { 317 return i; 318 } 319 if (alreadyChecked || count.matches(p, context)) { 320 i++; 321 } 322 } 323 } 324 325 349 350 public static int getNumberAny(Expression inst, NodeInfo node, Pattern count, 351 Pattern from, XPathContext context, boolean hasVariablesInPatterns) throws XPathException { 352 353 NodeInfo memoNode = null; 354 int memoNumber = 0; 355 Controller controller = context.getController(); 356 boolean memoise = (!hasVariablesInPatterns && count!=null); 357 if (memoise) { 358 Object [] memo = (Object [])controller.getUserData(inst, "xsl:number"); 359 if (memo != null) { 360 memoNode = (NodeInfo)memo[0]; 361 memoNumber = ((Integer )memo[1]).intValue(); 362 } 363 } 364 365 int num = 0; 366 if (count==null) { 367 if (node.getFingerprint()==-1) { count = new NodeTestPattern(NodeKindTest.makeNodeKindTest(node.getNodeKind())); 369 } else { 370 count = new NodeTestPattern(new NameTest(node)); 371 } 372 num = 1; 373 } else if (count.matches(node, context)) { 374 num = 1; 375 } 376 377 380 NodeTest filter; 382 if (from==null) { 383 filter = count.getNodeTest(); 384 } else if (from.getNodeKind()==Type.ELEMENT && count.getNodeKind()==Type.ELEMENT) { 385 filter = NodeKindTest.ELEMENT; 386 } else { 387 filter = AnyNodeTest.getInstance(); 388 } 389 390 SequenceIterator preceding = 391 node.iterateAxis(Axis.PRECEDING_OR_ANCESTOR, filter); 392 393 while (true) { 394 NodeInfo prev = (NodeInfo)preceding.next(); 395 if (prev == null) { 396 break; 397 } 398 if (from!=null && from.matches(prev, context)) { 399 return num; 400 } 401 if (count.matches(prev, context)) { 402 if (num==1 && memoNode!=null && prev.isSameNodeInfo(memoNode)) { 403 num = memoNumber + 1; 404 break; 405 } 406 num++; 407 } 408 } 409 if (from != null) { 410 return 0; 412 } 413 if (memoise) { 414 Object [] memo = new Object [2]; 415 memo[0] = node; 416 memo[1] = new Integer (num); 417 controller.setUserData(inst, "xsl:number", memo); 418 } 419 return num; 420 } 421 422 441 442 public static List getNumberMulti(NodeInfo node, Pattern count, 443 Pattern from, XPathContext context) throws XPathException { 444 445 447 ArrayList v = new ArrayList (5); 448 449 if (count==null) { 450 if (node.getFingerprint()==-1) { count = new NodeTestPattern(NodeKindTest.makeNodeKindTest(node.getNodeKind())); 452 } else { 453 count = new NodeTestPattern(new NameTest(node)); 454 } 455 } 456 457 NodeInfo curr = node; 458 459 while(true) { 460 if (count.matches(curr, context)) { 461 int num = getNumberSingle(curr, count, null, context); 462 v.add(0, new Long (num)); 463 } 464 curr = curr.getParent(); 465 if (curr==null) break; 466 if (from!=null && from.matches(curr, context)) break; 467 } 468 469 return v; 470 } 471 472 484 485 public static void copy(NodeInfo node, 486 Receiver out, 487 NamePool namePool, 488 int whichNamespaces, 489 boolean copyAnnotations, int locationId) throws XPathException { 490 491 switch (node.getNodeKind()) { 492 case Type.DOCUMENT: { 493 out.startDocument(0); 494 AxisIterator children0 = node.iterateAxis(Axis.CHILD, new AnyNodeTest()); 495 while (true) { 496 NodeInfo child = (NodeInfo)children0.next(); 497 if (child == null) { 498 break; 499 } 500 child.copy(out, whichNamespaces, copyAnnotations, locationId); 501 } 502 out.endDocument(); 503 break; 504 } 505 case Type.ELEMENT: { 506 out.startElement(node.getNameCode(), 507 copyAnnotations? node.getTypeAnnotation(): StandardNames.XDT_UNTYPED, 508 0, 0); 509 510 512 if (whichNamespaces != NodeInfo.NO_NAMESPACES) { 513 node.sendNamespaceDeclarations(out, true); 514 } 515 516 518 AxisIterator attributes = node.iterateAxis(Axis.ATTRIBUTE, new AnyNodeTest()); 519 while (true) { 520 NodeInfo att = (NodeInfo)attributes.next(); 521 if (att == null) { 522 break; 523 } 524 att.copy(out, whichNamespaces, copyAnnotations, locationId); 525 } 526 527 529 out.startContent(); 530 531 533 AxisIterator children = node.iterateAxis(Axis.CHILD, new AnyNodeTest()); 534 while (true) { 535 NodeInfo child = (NodeInfo)children.next(); 536 if (child == null) { 537 break; 538 } 539 child.copy(out, whichNamespaces, copyAnnotations, locationId); 540 } 541 542 544 out.endElement(); 545 return; 546 } 547 case Type.ATTRIBUTE: { 548 out.attribute(node.getNameCode(), 549 copyAnnotations? node.getTypeAnnotation(): StandardNames.XDT_UNTYPED_ATOMIC, 550 node.getStringValueCS(), 0, 0); 551 return; 552 } 553 case Type.TEXT: { 554 out.characters(node.getStringValueCS(), 0, 0); 555 return; 556 } 557 case Type.COMMENT: { 558 out.comment(node.getStringValueCS(), 0, 0); 559 return; 560 } 561 case Type.PROCESSING_INSTRUCTION: { 562 out.processingInstruction(node.getLocalPart(), node.getStringValueCS(), 0, 0); 563 return; 564 } 565 case Type.NAMESPACE: { 566 out.namespace(namePool.allocateNamespaceCode(node.getLocalPart(), node.getStringValue()),0); 567 return; 568 } 569 default: 570 571 } 572 } 573 574 583 584 public static int compareOrder(SiblingCountingNode first, SiblingCountingNode second) { 585 NodeInfo ow = second; 586 587 if (first.isSameNodeInfo(second)) { 589 return 0; 590 } 591 592 NodeInfo firstParent = first.getParent(); 593 if (firstParent == null) { 594 return -1; 596 } 597 598 NodeInfo secondParent = second.getParent(); 599 if (secondParent == null) { 600 return +1; 602 } 603 604 if (firstParent.isSameNodeInfo(secondParent)) { 606 int cat1 = nodeCategories[first.getNodeKind()]; 607 int cat2 = nodeCategories[second.getNodeKind()]; 608 if (cat1 == cat2) { 609 return first.getSiblingPosition() - second.getSiblingPosition(); 610 } else { 611 return cat1 - cat2; 612 } 613 } 614 615 int depth1 = 0; 617 int depth2 = 0; 618 NodeInfo p1 = first; 619 NodeInfo p2 = second; 620 while (p1 != null) { 621 depth1++; 622 p1 = p1.getParent(); 623 } 624 while (p2 != null) { 625 depth2++; 626 p2 = p2.getParent(); 627 } 628 630 p1 = first; 631 while (depth1>depth2) { 632 p1 = p1.getParent(); 633 if (p1.isSameNodeInfo(second)) { 634 return +1; 635 } 636 depth1--; 637 } 638 639 p2 = ow; 640 while (depth2>depth1) { 641 p2 = p2.getParent(); 642 if (p2.isSameNodeInfo(first)) { 643 return -1; 644 } 645 depth2--; 646 } 647 648 while (true) { 650 NodeInfo par1 = p1.getParent(); 651 NodeInfo par2 = p2.getParent(); 652 if (par1==null || par2==null) { 653 throw new NullPointerException ("DOM/JDOM tree compare - internal error"); 654 } 655 if (par1.isSameNodeInfo(par2)) { 656 return ((SiblingCountingNode)p1).getSiblingPosition() - 657 ((SiblingCountingNode)p2).getSiblingPosition(); 658 } 659 p1 = par1; 660 p2 = par2; 661 } 662 } 663 664 668 669 private static int[] nodeCategories = { 670 -1, 3, 2, 3, -1, -1, -1, 3, 3, 0, -1, -1, -1, 1 }; 681 682 687 688 public static String getSequentialKey(SiblingCountingNode node) { 689 StringBuffer key = new StringBuffer (12); 692 int num = node.getDocumentNumber(); 693 while(node != null && !(node instanceof DocumentInfo)) { 694 key.insert(0, alphaKey(node.getSiblingPosition())); 695 node = (SiblingCountingNode)node.getParent(); 696 } 697 key.insert(0, "w" + num); 698 return key.toString().intern(); 699 } 700 701 706 707 public static String alphaKey(int value) { 708 if (value<1) return "a"; 709 if (value<10) return "b" + value; 710 if (value<100) return "c" + value; 711 if (value<1000) return "d" + value; 712 if (value<10000) return "e" + value; 713 if (value<100000) return "f" + value; 714 if (value<1000000) return "g" + value; 715 if (value<10000000) return "h" + value; 716 if (value<100000000) return "i" + value; 717 if (value<1000000000) return "j" + value; 718 return "k" + value; 719 } 720 721 729 730 public static final boolean isWhite(CharSequence content) { 731 return Whitespace.isWhite(content); 732 } 733 734 735 739 743 744 public static class AxisFilter extends AxisIteratorImpl { 745 private AxisIterator base; 746 private NodeTest nodeTest; 747 749 757 758 public AxisFilter(AxisIterator base, NodeTest test) { 759 this.base = base; 760 this.nodeTest = test; 761 position = 0; 762 } 763 764 public Item next() { 765 while (true) { 766 current = base.next(); 767 if (current == null) { 768 position = -1; 769 return null; 770 } 771 if (nodeTest.matches((NodeInfo)current)) { 772 position++; 773 return current; 774 } 775 } 776 } 777 778 public SequenceIterator getAnother() { 779 return new AxisFilter((AxisIterator)base.getAnother(), nodeTest); 780 } 781 } 782 783 792 793 public static abstract class BaseEnumeration extends AxisIteratorImpl { 794 795 public final Item next() { 796 advance(); 797 return current; 798 } 799 800 805 806 public abstract void advance(); 807 808 public abstract SequenceIterator getAnother(); 809 810 } 811 812 815 816 public static final class AncestorEnumeration extends BaseEnumeration { 817 818 private boolean includeSelf; 819 private boolean atStart; 820 private NodeInfo start; 821 822 public AncestorEnumeration(NodeInfo start, boolean includeSelf) { 823 this.start = start; 824 this.includeSelf = includeSelf; 825 this.current = start; 826 atStart = true; 827 } 828 829 public void advance() { 830 if (atStart) { 831 atStart = false; 832 if (includeSelf) { 833 return; 834 } 835 } 836 current = ((NodeInfo)current).getParent(); 837 } 838 839 public SequenceIterator getAnother() { 840 return new AncestorEnumeration(start, includeSelf); 841 } 842 843 } 845 853 854 public static final class DescendantEnumeration extends BaseEnumeration { 855 856 private AxisIterator children = null; 857 private AxisIterator descendants = null; 858 private NodeInfo start; 859 private boolean includeSelf; 860 private boolean forwards; 861 private boolean atEnd = false; 862 863 public DescendantEnumeration(NodeInfo start, 864 boolean includeSelf, boolean forwards) { 865 this.start = start; 866 this.includeSelf = includeSelf; 867 this.forwards = forwards; 868 } 869 870 public void advance() { 871 if (descendants!=null) { 872 Item nextd = descendants.next(); 873 if (nextd != null) { 874 current = nextd; 875 return; 876 } else { 877 descendants = null; 878 } 879 } 880 if (children!=null) { 881 NodeInfo n = (NodeInfo)children.next(); 882 if (n != null) { 883 if (n.hasChildNodes()) { 884 if (forwards) { 885 descendants = new DescendantEnumeration(n, 886 false, forwards); 887 current = n; 888 } else { 889 descendants = new DescendantEnumeration(n, true, forwards); 890 advance(); 891 } 892 } else { 893 current = n; 894 } 895 } else { 896 if (forwards || !includeSelf) { 897 current = null; 898 } else { 899 atEnd = true; 900 children = null; 901 current = start; 902 } 903 } 904 } else if (atEnd) { 905 current = null; 907 } else { 908 if (start.hasChildNodes()) { 910 children = start.iterateAxis(Axis.CHILD); 912 if (!forwards) { 913 if (children instanceof ReversibleIterator) { 914 children = (AxisIterator)((ReversibleIterator)children).getReverseIterator(); 915 } else { 916 try { 917 children = new SequenceExtent(start.iterateAxis(Axis.CHILD)).reverseIterate(); 918 } catch (XPathException e) { 919 throw new AssertionError ( 920 "Internal error in Navigator#descendantEnumeration: " + e.getMessage()); 921 } 923 } 924 } 925 } else { 926 children = EmptyIterator.getInstance(); 927 } 928 if (forwards && includeSelf) { 929 current = start; 930 } else { 931 advance(); 932 } 933 } 934 } 935 936 public SequenceIterator getAnother() { 937 return new DescendantEnumeration(start, includeSelf, forwards); 938 } 939 940 } 942 946 947 public static final class FollowingEnumeration extends BaseEnumeration { 948 private NodeInfo start; 949 private AxisIterator ancestorEnum = null; 950 private AxisIterator siblingEnum = null; 951 private AxisIterator descendEnum = null; 952 953 public FollowingEnumeration(NodeInfo start) { 954 this.start = start; 955 ancestorEnum = new AncestorEnumeration(start, false); 956 switch (start.getNodeKind()) { 957 case Type.ELEMENT: 958 case Type.TEXT: 959 case Type.COMMENT: 960 case Type.PROCESSING_INSTRUCTION: 961 siblingEnum = start.iterateAxis(Axis.FOLLOWING_SIBLING); 964 break; 965 case Type.ATTRIBUTE: 966 case Type.NAMESPACE: 967 NodeInfo parent = start.getParent(); 970 if (parent == null) { 971 siblingEnum = EmptyIterator.getInstance(); 972 } else { 973 siblingEnum = parent.iterateAxis(Axis.CHILD); 974 } 975 break; 976 default: 977 siblingEnum = EmptyIterator.getInstance(); 978 } 979 } 981 982 public void advance() { 983 if (descendEnum!=null) { 984 Item nextd = descendEnum.next(); 985 if (nextd != null) { 986 current = nextd; 987 return; 988 } else { 989 descendEnum = null; 990 } 991 } 992 if (siblingEnum!=null) { 993 Item nexts = siblingEnum.next(); 994 if (nexts != null) { 995 current = nexts; 996 NodeInfo n = (NodeInfo)current; 997 if (n.hasChildNodes()) { 998 descendEnum = new DescendantEnumeration(n, false, true); 999 } else { 1000 descendEnum = null; 1001 } 1002 return; 1003 } else { 1004 descendEnum = null; 1005 siblingEnum = null; 1006 } 1007 } 1008 Item nexta = ancestorEnum.next(); 1009 if (nexta != null) { 1010 current = nexta; 1011 NodeInfo n = (NodeInfo)current; 1012 if (n.getNodeKind() == Type.DOCUMENT) { 1013 siblingEnum = EmptyIterator.getInstance(); 1014 } else { 1015 siblingEnum = n.iterateAxis(Axis.FOLLOWING_SIBLING); 1017 } 1018 advance(); 1019 } else { 1020 current = null; 1021 } 1022 } 1023 1024 public SequenceIterator getAnother() { 1025 return new FollowingEnumeration(start); 1026 } 1027 1028 } 1030 public static final class PrecedingEnumeration extends BaseEnumeration { 1031 1032 private NodeInfo start; 1033 private AxisIterator ancestorEnum = null; 1034 private AxisIterator siblingEnum = null; 1035 private AxisIterator descendEnum = null; 1036 private boolean includeAncestors; 1037 1038 public PrecedingEnumeration(NodeInfo start, boolean includeAncestors) { 1039 this.start = start; 1040 this.includeAncestors = includeAncestors; 1041 ancestorEnum = new AncestorEnumeration(start, false); 1042 switch (start.getNodeKind()) { 1043 case Type.ELEMENT: 1044 case Type.TEXT: 1045 case Type.COMMENT: 1046 case Type.PROCESSING_INSTRUCTION: 1047 siblingEnum = start.iterateAxis(Axis.PRECEDING_SIBLING); 1050 break; 1051 default: 1052 siblingEnum = EmptyIterator.getInstance(); 1053 } 1054 } 1056 1057 public void advance() { 1058 if (descendEnum!=null) { 1059 Item nextd = descendEnum.next(); 1060 if (nextd != null) { 1061 current = nextd; 1062 return; 1063 } else { 1064 descendEnum = null; 1065 } 1066 } 1067 if (siblingEnum!=null) { 1068 Item nexts = siblingEnum.next(); 1069 if (nexts != null) { 1070 NodeInfo sib = (NodeInfo)nexts; 1071 if (sib.hasChildNodes()) { 1072 descendEnum = new DescendantEnumeration(sib, true, false); 1073 advance(); 1074 } else { 1075 descendEnum = null; 1076 current = sib; 1077 } 1078 return; 1079 } else { 1080 descendEnum = null; 1081 siblingEnum = null; 1082 } 1083 } 1084 Item nexta = ancestorEnum.next(); 1085 if (nexta != null) { 1086 current = nexta; 1087 NodeInfo n = (NodeInfo)current; 1088 if (n.getNodeKind() == Type.DOCUMENT) { 1089 siblingEnum = EmptyIterator.getInstance(); 1090 } else { 1091 siblingEnum = n.iterateAxis(Axis.PRECEDING_SIBLING); 1092 } 1093 if (!includeAncestors) { 1094 advance(); 1095 } 1096 } else { 1097 current = null; 1098 } 1099 } 1100 1101 public SequenceIterator getAnother() { 1102 return new PrecedingEnumeration(start, includeAncestors); 1103 } 1104 1105 } 1107 1108} 1109 1110 | Popular Tags |