1 16 19 package org.apache.xml.dtm.ref; 20 21 import org.apache.xml.dtm.*; 22 23 import javax.xml.transform.Source ; 24 25 import org.apache.xml.utils.XMLStringFactory; 26 27 import org.apache.xml.res.XMLErrorResources; 28 import org.apache.xml.res.XMLMessages; 29 30 31 39 public abstract class DTMDefaultBaseTraversers extends DTMDefaultBase 40 { 41 42 55 public DTMDefaultBaseTraversers(DTMManager mgr, Source source, 56 int dtmIdentity, 57 DTMWSFilter whiteSpaceFilter, 58 XMLStringFactory xstringfactory, 59 boolean doIndexing) 60 { 61 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 62 doIndexing); 63 } 64 65 81 public DTMDefaultBaseTraversers(DTMManager mgr, Source source, 82 int dtmIdentity, 83 DTMWSFilter whiteSpaceFilter, 84 XMLStringFactory xstringfactory, 85 boolean doIndexing, 86 int blocksize, 87 boolean usePrevsib, 88 boolean newNameTable) 89 { 90 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 91 doIndexing, blocksize, usePrevsib, newNameTable); 92 } 93 94 102 public DTMAxisTraverser getAxisTraverser(final int axis) 103 { 104 105 DTMAxisTraverser traverser; 106 107 if (null == m_traversers) { 109 m_traversers = new DTMAxisTraverser[Axis.names.length]; 110 traverser = null; 111 } 112 else 113 { 114 traverser = m_traversers[axis]; 116 if (traverser != null) 117 return traverser; 118 } 119 120 switch (axis) { 122 case Axis.ANCESTOR : 123 traverser = new AncestorTraverser(); 124 break; 125 case Axis.ANCESTORORSELF : 126 traverser = new AncestorOrSelfTraverser(); 127 break; 128 case Axis.ATTRIBUTE : 129 traverser = new AttributeTraverser(); 130 break; 131 case Axis.CHILD : 132 traverser = new ChildTraverser(); 133 break; 134 case Axis.DESCENDANT : 135 traverser = new DescendantTraverser(); 136 break; 137 case Axis.DESCENDANTORSELF : 138 traverser = new DescendantOrSelfTraverser(); 139 break; 140 case Axis.FOLLOWING : 141 traverser = new FollowingTraverser(); 142 break; 143 case Axis.FOLLOWINGSIBLING : 144 traverser = new FollowingSiblingTraverser(); 145 break; 146 case Axis.NAMESPACE : 147 traverser = new NamespaceTraverser(); 148 break; 149 case Axis.NAMESPACEDECLS : 150 traverser = new NamespaceDeclsTraverser(); 151 break; 152 case Axis.PARENT : 153 traverser = new ParentTraverser(); 154 break; 155 case Axis.PRECEDING : 156 traverser = new PrecedingTraverser(); 157 break; 158 case Axis.PRECEDINGSIBLING : 159 traverser = new PrecedingSiblingTraverser(); 160 break; 161 case Axis.SELF : 162 traverser = new SelfTraverser(); 163 break; 164 case Axis.ALL : 165 traverser = new AllFromRootTraverser(); 166 break; 167 case Axis.ALLFROMNODE : 168 traverser = new AllFromNodeTraverser(); 169 break; 170 case Axis.PRECEDINGANDANCESTOR : 171 traverser = new PrecedingAndAncestorTraverser(); 172 break; 173 case Axis.DESCENDANTSFROMROOT : 174 traverser = new DescendantFromRootTraverser(); 175 break; 176 case Axis.DESCENDANTSORSELFFROMROOT : 177 traverser = new DescendantOrSelfFromRootTraverser(); 178 break; 179 case Axis.ROOT : 180 traverser = new RootTraverser(); 181 break; 182 case Axis.FILTEREDLIST : 183 return null; default : 185 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_UNKNOWN_AXIS_TYPE, new Object []{Integer.toString(axis)})); } 187 188 if (null == traverser) 189 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object []{Axis.names[axis]})); 190 193 m_traversers[axis] = traverser; 194 195 return traverser; 196 } 197 198 201 private class AncestorTraverser extends DTMAxisTraverser 202 { 203 204 212 public int next(int context, int current) 213 { 214 return getParent(current); 215 } 216 217 227 public int next(int context, int current, int expandedTypeID) 228 { 229 current = makeNodeIdentity(current); 231 232 while (DTM.NULL != (current = m_parent.elementAt(current))) 233 { 234 if (m_exptype.elementAt(current) == expandedTypeID) 235 return makeNodeHandle(current); 236 } 237 238 return NULL; 239 } 240 } 241 242 245 private class AncestorOrSelfTraverser extends AncestorTraverser 246 { 247 248 257 public int first(int context) 258 { 259 return context; 260 } 261 262 274 public int first(int context, int expandedTypeID) 275 { 276 return (getExpandedTypeID(context) == expandedTypeID) 277 ? context : next(context, context, expandedTypeID); 278 } 279 } 280 281 284 private class AttributeTraverser extends DTMAxisTraverser 285 { 286 287 295 public int next(int context, int current) 296 { 297 return (context == current) 298 ? getFirstAttribute(context) : getNextAttribute(current); 299 } 300 301 311 public int next(int context, int current, int expandedTypeID) 312 { 313 314 current = (context == current) 315 ? getFirstAttribute(context) : getNextAttribute(current); 316 317 do 318 { 319 if (getExpandedTypeID(current) == expandedTypeID) 320 return current; 321 } 322 while (DTM.NULL != (current = getNextAttribute(current))); 323 324 return NULL; 325 } 326 } 327 328 331 private class ChildTraverser extends DTMAxisTraverser 332 { 333 334 346 protected int getNextIndexed(int axisRoot, int nextPotential, 347 int expandedTypeID) 348 { 349 350 int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID); 351 int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID); 352 353 for (; ; ) 354 { 355 int nextID = findElementFromIndex(nsIndex, lnIndex, nextPotential); 356 357 if (NOTPROCESSED != nextID) 358 { 359 int parentID = m_parent.elementAt(nextID); 360 361 if(parentID == axisRoot) 363 return nextID; 364 365 if(parentID < axisRoot) 368 return NULL; 369 370 do 376 { 377 parentID = m_parent.elementAt(parentID); 378 if(parentID < axisRoot) 379 return NULL; 380 } 381 while(parentID > axisRoot); 382 383 nextPotential = nextID+1; 385 continue; 386 } 387 388 nextNode(); 389 390 if(!(m_nextsib.elementAt(axisRoot) == NOTPROCESSED)) 391 break; 392 } 393 394 return DTM.NULL; 395 } 396 397 409 public int first(int context) 410 { 411 return getFirstChild(context); 412 } 413 414 428 public int first(int context, int expandedTypeID) 429 { 430 if(true) 431 { 432 int identity = makeNodeIdentity(context); 433 434 int firstMatch = getNextIndexed(identity, _firstch(identity), 435 expandedTypeID); 436 437 return makeNodeHandle(firstMatch); 438 } 439 else 440 { 441 for (int current = _firstch(makeNodeIdentity(context)); 443 DTM.NULL != current; 444 current = _nextsib(current)) 445 { 446 if (m_exptype.elementAt(current) == expandedTypeID) 447 return makeNodeHandle(current); 448 } 449 return NULL; 450 } 451 } 452 453 461 public int next(int context, int current) 462 { 463 return getNextSibling(current); 464 } 465 466 476 public int next(int context, int current, int expandedTypeID) 477 { 478 for (current = _nextsib(makeNodeIdentity(current)); 480 DTM.NULL != current; 481 current = _nextsib(current)) 482 { 483 if (m_exptype.elementAt(current) == expandedTypeID) 484 return makeNodeHandle(current); 485 } 486 487 return NULL; 488 } 489 } 490 491 495 private abstract class IndexedDTMAxisTraverser extends DTMAxisTraverser 496 { 497 498 508 protected final boolean isIndexed(int expandedTypeID) 509 { 510 return (m_indexing 511 && ExpandedNameTable.ELEMENT 512 == m_expandedNameTable.getType(expandedTypeID)); 513 } 514 515 525 protected abstract boolean isAfterAxis(int axisRoot, int identity); 526 527 536 protected abstract boolean axisHasBeenProcessed(int axisRoot); 537 538 550 protected int getNextIndexed(int axisRoot, int nextPotential, 551 int expandedTypeID) 552 { 553 554 int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID); 555 int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID); 556 557 while(true) 558 { 559 int next = findElementFromIndex(nsIndex, lnIndex, nextPotential); 560 561 if (NOTPROCESSED != next) 562 { 563 if (isAfterAxis(axisRoot, next)) 564 return NULL; 565 566 return next; 568 } 569 else if(axisHasBeenProcessed(axisRoot)) 570 break; 571 572 nextNode(); 573 } 574 575 return DTM.NULL; 576 } 577 } 578 579 582 private class DescendantTraverser extends IndexedDTMAxisTraverser 583 { 584 592 protected int getFirstPotential(int identity) 593 { 594 return identity + 1; 595 } 596 597 605 protected boolean axisHasBeenProcessed(int axisRoot) 606 { 607 return !(m_nextsib.elementAt(axisRoot) == NOTPROCESSED); 608 } 609 610 618 protected int getSubtreeRoot(int handle) 619 { 620 return makeNodeIdentity(handle); 621 } 622 623 635 protected boolean isDescendant(int subtreeRootIdentity, int identity) 636 { 637 return _parent(identity) >= subtreeRootIdentity; 638 } 639 640 650 protected boolean isAfterAxis(int axisRoot, int identity) 651 { 652 do 656 { 657 if(identity == axisRoot) 658 return false; 659 identity = m_parent.elementAt(identity); 660 } 661 while(identity >= axisRoot); 662 663 return true; 664 } 665 666 680 public int first(int context, int expandedTypeID) 681 { 682 683 if (isIndexed(expandedTypeID)) 684 { 685 int identity = getSubtreeRoot(context); 686 int firstPotential = getFirstPotential(identity); 687 688 return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID)); 689 } 690 691 return next(context, context, expandedTypeID); 692 } 693 694 702 public int next(int context, int current) 703 { 704 705 int subtreeRootIdent = getSubtreeRoot(context); 706 707 for (current = makeNodeIdentity(current) + 1; ; current++) 708 { 709 int type = _type(current); 711 if (!isDescendant(subtreeRootIdent, current)) 712 return NULL; 713 714 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type) 715 continue; 716 717 return makeNodeHandle(current); } 719 } 720 721 731 public int next(int context, int current, int expandedTypeID) 732 { 733 734 int subtreeRootIdent = getSubtreeRoot(context); 735 736 current = makeNodeIdentity(current) + 1; 737 738 if (isIndexed(expandedTypeID)) 739 { 740 return makeNodeHandle(getNextIndexed(subtreeRootIdent, current, expandedTypeID)); 741 } 742 743 for (; ; current++) 744 { 745 int exptype = _exptype(current); 747 if (!isDescendant(subtreeRootIdent, current)) 748 return NULL; 749 750 if (exptype != expandedTypeID) 751 continue; 752 753 return makeNodeHandle(current); } 755 } 756 } 757 758 761 private class DescendantOrSelfTraverser extends DescendantTraverser 762 { 763 764 772 protected int getFirstPotential(int identity) 773 { 774 return identity; 775 } 776 777 786 public int first(int context) 787 { 788 return context; 789 } 790 } 791 792 795 private class AllFromNodeTraverser extends DescendantOrSelfTraverser 796 { 797 798 806 public int next(int context, int current) 807 { 808 809 int subtreeRootIdent = makeNodeIdentity(context); 810 811 for (current = makeNodeIdentity(current) + 1; ; current++) 812 { 813 _exptype(current); 820 if (!isDescendant(subtreeRootIdent, current)) 821 return NULL; 822 823 return makeNodeHandle(current); } 825 } 826 } 827 828 831 private class FollowingTraverser extends DescendantTraverser 832 { 833 834 841 public int first(int context) 842 { 843 context=makeNodeIdentity(context); 845 846 int first; 847 int type = _type(context); 848 849 if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type)) 850 { 851 context = _parent(context); 852 first = _firstch(context); 853 854 if (NULL != first) 855 return makeNodeHandle(first); 856 } 857 858 do 859 { 860 first = _nextsib(context); 861 862 if (NULL == first) 863 context = _parent(context); 864 } 865 while (NULL == first && NULL != context); 866 867 return makeNodeHandle(first); 868 } 869 870 879 public int first(int context, int expandedTypeID) 880 { 881 int first; 884 int type = getNodeType(context); 885 886 if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type)) 887 { 888 context = getParent(context); 889 first = getFirstChild(context); 890 891 if (NULL != first) 892 { 893 if (getExpandedTypeID(first) == expandedTypeID) 894 return first; 895 else 896 return next(context, first, expandedTypeID); 897 } 898 } 899 900 do 901 { 902 first = getNextSibling(context); 903 904 if (NULL == first) 905 context = getParent(context); 906 else 907 { 908 if (getExpandedTypeID(first) == expandedTypeID) 909 return first; 910 else 911 return next(context, first, expandedTypeID); 912 } 913 } 914 while (NULL == first && NULL != context); 915 916 return first; 917 } 918 919 927 public int next(int context, int current) 928 { 929 current=makeNodeIdentity(current); 931 932 while (true) 933 { 934 current++; 936 int type = _type(current); 939 if (NULL == type) 940 return NULL; 941 942 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type) 943 continue; 944 945 return makeNodeHandle(current); } 947 } 948 949 959 public int next(int context, int current, int expandedTypeID) 960 { 961 current=makeNodeIdentity(current); 963 964 while (true) 965 { 966 current++; 967 968 int etype = _exptype(current); 970 if (NULL == etype) 971 return NULL; 972 973 if (etype != expandedTypeID) 974 continue; 975 976 return makeNodeHandle(current); } 978 } 979 } 980 981 984 private class FollowingSiblingTraverser extends DTMAxisTraverser 985 { 986 987 995 public int next(int context, int current) 996 { 997 return getNextSibling(current); 998 } 999 1000 1010 public int next(int context, int current, int expandedTypeID) 1011 { 1012 1013 while (DTM.NULL != (current = getNextSibling(current))) 1014 { 1015 if (getExpandedTypeID(current) == expandedTypeID) 1016 return current; 1017 } 1018 1019 return NULL; 1020 } 1021 } 1022 1023 1026 private class NamespaceDeclsTraverser extends DTMAxisTraverser 1027 { 1028 1029 1037 public int next(int context, int current) 1038 { 1039 1040 return (context == current) 1041 ? getFirstNamespaceNode(context, false) 1042 : getNextNamespaceNode(context, current, false); 1043 } 1044 1045 1055 public int next(int context, int current, int expandedTypeID) 1056 { 1057 1058 current = (context == current) 1059 ? getFirstNamespaceNode(context, false) 1060 : getNextNamespaceNode(context, current, false); 1061 1062 do 1063 { 1064 if (getExpandedTypeID(current) == expandedTypeID) 1065 return current; 1066 } 1067 while (DTM.NULL 1068 != (current = getNextNamespaceNode(context, current, false))); 1069 1070 return NULL; 1071 } 1072 } 1073 1074 1077 private class NamespaceTraverser extends DTMAxisTraverser 1078 { 1079 1080 1088 public int next(int context, int current) 1089 { 1090 1091 return (context == current) 1092 ? getFirstNamespaceNode(context, true) 1093 : getNextNamespaceNode(context, current, true); 1094 } 1095 1096 1106 public int next(int context, int current, int expandedTypeID) 1107 { 1108 1109 current = (context == current) 1110 ? getFirstNamespaceNode(context, true) 1111 : getNextNamespaceNode(context, current, true); 1112 1113 do 1114 { 1115 if (getExpandedTypeID(current) == expandedTypeID) 1116 return current; 1117 } 1118 while (DTM.NULL 1119 != (current = getNextNamespaceNode(context, current, true))); 1120 1121 return NULL; 1122 } 1123 } 1124 1125 1128 private class ParentTraverser extends DTMAxisTraverser 1129 { 1130 1142 public int first(int context) 1143 { 1144 return getParent(context); 1145 } 1146 1147 1161 public int first(int current, int expandedTypeID) 1162 { 1163 current = makeNodeIdentity(current); 1165 1166 while (NULL != (current = m_parent.elementAt(current))) 1167 { 1168 if (m_exptype.elementAt(current) == expandedTypeID) 1169 return makeNodeHandle(current); 1170 } 1171 1172 return NULL; 1173 } 1174 1175 1176 1184 public int next(int context, int current) 1185 { 1186 1187 return NULL; 1188 } 1189 1190 1191 1192 1202 public int next(int context, int current, int expandedTypeID) 1203 { 1204 1205 return NULL; 1206 } 1207 } 1208 1209 1212 private class PrecedingTraverser extends DTMAxisTraverser 1213 { 1214 1215 1224 protected boolean isAncestor(int contextIdent, int currentIdent) 1225 { 1226 for (contextIdent = m_parent.elementAt(contextIdent); DTM.NULL != contextIdent; 1229 contextIdent = m_parent.elementAt(contextIdent)) 1230 { 1231 if (contextIdent == currentIdent) 1232 return true; 1233 } 1234 1235 return false; 1236 } 1237 1238 1246 public int next(int context, int current) 1247 { 1248 int subtreeRootIdent = makeNodeIdentity(context); 1250 1251 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1252 { 1253 short type = _type(current); 1254 1255 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type 1256 || isAncestor(subtreeRootIdent, current)) 1257 continue; 1258 1259 return makeNodeHandle(current); } 1261 1262 return NULL; 1263 } 1264 1265 1275 public int next(int context, int current, int expandedTypeID) 1276 { 1277 int subtreeRootIdent = makeNodeIdentity(context); 1279 1280 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1281 { 1282 int exptype = m_exptype.elementAt(current); 1283 1284 if (exptype != expandedTypeID 1285 || isAncestor(subtreeRootIdent, current)) 1286 continue; 1287 1288 return makeNodeHandle(current); } 1290 1291 return NULL; 1292 } 1293 } 1294 1295 1299 private class PrecedingAndAncestorTraverser extends DTMAxisTraverser 1300 { 1301 1302 1310 public int next(int context, int current) 1311 { 1312 int subtreeRootIdent = makeNodeIdentity(context ); 1314 1315 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1316 { 1317 short type = _type(current); 1318 1319 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type) 1320 continue; 1321 1322 return makeNodeHandle(current); } 1324 1325 return NULL; 1326 } 1327 1328 1338 public int next(int context, int current, int expandedTypeID) 1339 { 1340 int subtreeRootIdent = makeNodeIdentity(context); 1342 1343 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1344 { 1345 int exptype = m_exptype.elementAt(current); 1346 1347 if (exptype != expandedTypeID) 1348 continue; 1349 1350 return makeNodeHandle(current); } 1352 1353 return NULL; 1354 } 1355 } 1356 1357 1360 private class PrecedingSiblingTraverser extends DTMAxisTraverser 1361 { 1362 1363 1371 public int next(int context, int current) 1372 { 1373 return getPreviousSibling(current); 1374 } 1375 1376 1386 public int next(int context, int current, int expandedTypeID) 1387 { 1388 1389 while (DTM.NULL != (current = getPreviousSibling(current))) 1390 { 1391 if (getExpandedTypeID(current) == expandedTypeID) 1392 return current; 1393 } 1394 1395 return NULL; 1396 } 1397 } 1398 1399 1402 private class SelfTraverser extends DTMAxisTraverser 1403 { 1404 1405 1414 public int first(int context) 1415 { 1416 return context; 1417 } 1418 1419 1431 public int first(int context, int expandedTypeID) 1432 { 1433 return (getExpandedTypeID(context) == expandedTypeID) ? context : NULL; 1434 } 1435 1436 1444 public int next(int context, int current) 1445 { 1446 return NULL; 1447 } 1448 1449 1459 public int next(int context, int current, int expandedTypeID) 1460 { 1461 return NULL; 1462 } 1463 } 1464 1465 1468 private class AllFromRootTraverser extends AllFromNodeTraverser 1469 { 1470 1471 1478 public int first(int context) 1479 { 1480 return getDocumentRoot(context); 1481 } 1482 1483 1491 public int first(int context, int expandedTypeID) 1492 { 1493 return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID) 1494 ? context : next(context, context, expandedTypeID); 1495 } 1496 1497 1505 public int next(int context, int current) 1506 { 1507 int subtreeRootIdent = makeNodeIdentity(context); 1509 1510 for (current = makeNodeIdentity(current) + 1; ; current++) 1511 { 1512 int type = _type(current); if (type == NULL) 1515 return NULL; 1516 1517 return makeNodeHandle(current); } 1519 } 1520 1521 1531 public int next(int context, int current, int expandedTypeID) 1532 { 1533 int subtreeRootIdent = makeNodeIdentity(context); 1535 1536 for (current = makeNodeIdentity(current) + 1; ; current++) 1537 { 1538 int exptype = _exptype(current); 1540 if (exptype == NULL) 1541 return NULL; 1542 1543 if (exptype != expandedTypeID) 1544 continue; 1545 1546 return makeNodeHandle(current); } 1548 } 1549 } 1550 1551 1554 private class RootTraverser extends AllFromRootTraverser 1555 { 1556 1565 public int first(int context, int expandedTypeID) 1566 { 1567 int root=getDocumentRoot(context); 1568 return (getExpandedTypeID(root) == expandedTypeID) 1569 ? root : NULL; 1570 } 1571 1572 1580 public int next(int context, int current) 1581 { 1582 return NULL; 1583 } 1584 1585 1595 public int next(int context, int current, int expandedTypeID) 1596 { 1597 return NULL; 1598 } 1599 } 1600 1601 1605 private class DescendantOrSelfFromRootTraverser extends DescendantTraverser 1606 { 1607 1608 1616 protected int getFirstPotential(int identity) 1617 { 1618 return identity; 1619 } 1620 1621 1626 protected int getSubtreeRoot(int handle) 1627 { 1628 return makeNodeIdentity(getDocument()); 1630 } 1631 1632 1639 public int first(int context) 1640 { 1641 return getDocumentRoot(context); 1642 } 1643 1644 1658 public int first(int context, int expandedTypeID) 1659 { 1660 if (isIndexed(expandedTypeID)) 1661 { 1662 int identity = 0; 1663 int firstPotential = getFirstPotential(identity); 1664 1665 return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID)); 1666 } 1667 1668 int root = first(context); 1669 return next(root, root, expandedTypeID); 1670 } 1671 } 1672 1673 1677 private class DescendantFromRootTraverser extends DescendantTraverser 1678 { 1679 1680 1688 protected int getFirstPotential(int identity) 1689 { 1690 return _firstch(0); 1691 } 1692 1693 1698 protected int getSubtreeRoot(int handle) 1699 { 1700 return 0; 1701 } 1702 1703 1710 public int first(int context) 1711 { 1712 return makeNodeHandle(_firstch(0)); 1713 } 1714 1715 1729 public int first(int context, int expandedTypeID) 1730 { 1731 if (isIndexed(expandedTypeID)) 1732 { 1733 int identity = 0; 1734 int firstPotential = getFirstPotential(identity); 1735 1736 return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID)); 1737 } 1738 1739 int root = getDocumentRoot(context); 1740 return next(root, root, expandedTypeID); 1741 } 1742 1743 } 1744 1745} 1746 | Popular Tags |