0001: /*
0002: * Copyright 1999-2005 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: /*
0017: * $Id: SAX2DTM2.java,v 1.15 2005/01/27 15:28:02 zongaro Exp $
0018: */
0019: package org.apache.xml.dtm.ref.sax2dtm;
0020:
0021: import org.apache.xml.dtm.*;
0022: import org.apache.xml.dtm.ref.*;
0023: import org.apache.xml.utils.FastStringBuffer;
0024: import org.apache.xml.utils.XMLString;
0025: import org.apache.xml.utils.XMLStringDefault;
0026: import org.apache.xml.utils.XMLStringFactory;
0027: import org.apache.xml.res.XMLMessages;
0028: import org.apache.xml.res.XMLErrorResources;
0029: import org.apache.xml.serializer.SerializationHandler;
0030:
0031: import javax.xml.transform.Source;
0032: import java.util.Vector;
0033: import org.apache.xml.utils.SuballocatedIntVector;
0034: import org.xml.sax.*;
0035:
0036: /**
0037: * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
0038: * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
0039: * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
0040: * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
0041: * are also overridden in SAX2DTM2 for performance reasons.
0042: * <p>
0043: * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
0044: * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
0045: * use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
0046: * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
0047: * SuballocatedIntVectors.
0048: * <p>
0049: * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
0050: * SAX2DTM model, please extend from SAX2DTM instead of this class.
0051: * <p>
0052: * TODO: This class is currently only used by XSLTC. We need to investigate the possibility
0053: * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
0054: * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
0055: * <p>
0056: * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
0057: * when making changes here!
0058: */
0059: public class SAX2DTM2 extends SAX2DTM {
0060:
0061: /****************************************************************
0062: * Optimized version of the nested iterators
0063: ****************************************************************/
0064:
0065: /**
0066: * Iterator that returns all immediate children of a given node
0067: */
0068: public final class ChildrenIterator extends
0069: InternalAxisIteratorBase {
0070:
0071: /**
0072: * Setting start to END should 'close' the iterator,
0073: * i.e. subsequent call to next() should return END.
0074: * <p>
0075: * If the iterator is not restartable, this has no effect.
0076: * %REVIEW% Should it return/throw something in that case,
0077: * or set current node to END, to indicate request-not-honored?
0078: *
0079: * @param node Sets the root of the iteration.
0080: *
0081: * @return A DTMAxisIterator set to the start of the iteration.
0082: */
0083: public DTMAxisIterator setStartNode(int node) {
0084: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0085: if (node == DTMDefaultBase.ROOTNODE)
0086: node = getDocument();
0087: if (_isRestartable) {
0088: _startNode = node;
0089: _currentNode = (node == DTM.NULL) ? DTM.NULL
0090: : _firstch2(makeNodeIdentity(node));
0091:
0092: return resetPosition();
0093: }
0094:
0095: return this ;
0096: }
0097:
0098: /**
0099: * Get the next node in the iteration.
0100: *
0101: * @return The next node handle in the iteration, or END if no more
0102: * are available.
0103: */
0104: public int next() {
0105: if (_currentNode != NULL) {
0106: int node = _currentNode;
0107: _currentNode = _nextsib2(node);
0108: return returnNode(makeNodeHandle(node));
0109: }
0110:
0111: return END;
0112: }
0113: } // end of ChildrenIterator
0114:
0115: /**
0116: * Iterator that returns the parent of a given node. Note that
0117: * this delivers only a single node; if you want all the ancestors,
0118: * see AncestorIterator.
0119: */
0120: public final class ParentIterator extends InternalAxisIteratorBase {
0121:
0122: /** The extended type ID that was requested. */
0123: private int _nodeType = DTM.NULL;
0124:
0125: /**
0126: * Set start to END should 'close' the iterator,
0127: * i.e. subsequent call to next() should return END.
0128: *
0129: * @param node Sets the root of the iteration.
0130: *
0131: * @return A DTMAxisIterator set to the start of the iteration.
0132: */
0133: public DTMAxisIterator setStartNode(int node) {
0134: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0135: if (node == DTMDefaultBase.ROOTNODE)
0136: node = getDocument();
0137: if (_isRestartable) {
0138: _startNode = node;
0139:
0140: if (node != DTM.NULL)
0141: _currentNode = _parent2(makeNodeIdentity(node));
0142: else
0143: _currentNode = DTM.NULL;
0144:
0145: return resetPosition();
0146: }
0147:
0148: return this ;
0149: }
0150:
0151: /**
0152: * Set the node type of the parent that we're looking for.
0153: * Note that this does _not_ mean "find the nearest ancestor of
0154: * this type", but "yield the parent if it is of this type".
0155: *
0156: *
0157: * @param type extended type ID.
0158: *
0159: * @return ParentIterator configured with the type filter set.
0160: */
0161: public DTMAxisIterator setNodeType(final int type) {
0162:
0163: _nodeType = type;
0164:
0165: return this ;
0166: }
0167:
0168: /**
0169: * Get the next node in the iteration. In this case, we return
0170: * only the immediate parent, _if_ it matches the requested nodeType.
0171: *
0172: * @return The next node handle in the iteration, or END.
0173: */
0174: public int next() {
0175: int result = _currentNode;
0176: if (result == END)
0177: return DTM.NULL;
0178:
0179: // %OPT% The most common case is handled first.
0180: if (_nodeType == NULL) {
0181: _currentNode = END;
0182: return returnNode(makeNodeHandle(result));
0183: } else if (_nodeType >= DTM.NTYPES) {
0184: if (_nodeType == _exptype2(result)) {
0185: _currentNode = END;
0186: return returnNode(makeNodeHandle(result));
0187: }
0188: } else {
0189: if (_nodeType == _type2(result)) {
0190: _currentNode = END;
0191: return returnNode(makeNodeHandle(result));
0192: }
0193: }
0194:
0195: return DTM.NULL;
0196: }
0197: } // end of ParentIterator
0198:
0199: /**
0200: * Iterator that returns children of a given type for a given node.
0201: * The functionality chould be achieved by putting a filter on top
0202: * of a basic child iterator, but a specialised iterator is used
0203: * for efficiency (both speed and size of translet).
0204: */
0205: public final class TypedChildrenIterator extends
0206: InternalAxisIteratorBase {
0207:
0208: /** The extended type ID that was requested. */
0209: private final int _nodeType;
0210:
0211: /**
0212: * Constructor TypedChildrenIterator
0213: *
0214: *
0215: * @param nodeType The extended type ID being requested.
0216: */
0217: public TypedChildrenIterator(int nodeType) {
0218: _nodeType = nodeType;
0219: }
0220:
0221: /**
0222: * Set start to END should 'close' the iterator,
0223: * i.e. subsequent call to next() should return END.
0224: *
0225: * @param node Sets the root of the iteration.
0226: *
0227: * @return A DTMAxisIterator set to the start of the iteration.
0228: */
0229: public DTMAxisIterator setStartNode(int node) {
0230: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0231: if (node == DTMDefaultBase.ROOTNODE)
0232: node = getDocument();
0233: if (_isRestartable) {
0234: _startNode = node;
0235: _currentNode = (node == DTM.NULL) ? DTM.NULL
0236: : _firstch2(makeNodeIdentity(_startNode));
0237:
0238: return resetPosition();
0239: }
0240:
0241: return this ;
0242: }
0243:
0244: /**
0245: * Get the next node in the iteration.
0246: *
0247: * @return The next node handle in the iteration, or END.
0248: */
0249: public int next() {
0250: int node = _currentNode;
0251: if (node == DTM.NULL)
0252: return DTM.NULL;
0253:
0254: final int nodeType = _nodeType;
0255:
0256: if (nodeType != DTM.ELEMENT_NODE) {
0257: while (node != DTM.NULL && _exptype2(node) != nodeType) {
0258: node = _nextsib2(node);
0259: }
0260: }
0261: // %OPT% If the nodeType is element (matching child::*), we only
0262: // need to compare the expType with DTM.NTYPES. A child node of
0263: // an element can be either an element, text, comment or
0264: // processing instruction node. Only element node has an extended
0265: // type greater than or equal to DTM.NTYPES.
0266: else {
0267: int eType;
0268: while (node != DTM.NULL) {
0269: eType = _exptype2(node);
0270: if (eType >= DTM.NTYPES)
0271: break;
0272: else
0273: node = _nextsib2(node);
0274: }
0275: }
0276:
0277: if (node == DTM.NULL) {
0278: _currentNode = DTM.NULL;
0279: return DTM.NULL;
0280: } else {
0281: _currentNode = _nextsib2(node);
0282: return returnNode(makeNodeHandle(node));
0283: }
0284:
0285: }
0286:
0287: /**
0288: * Return the node at the given position.
0289: */
0290: public int getNodeByPosition(int position) {
0291: if (position <= 0)
0292: return DTM.NULL;
0293:
0294: int node = _currentNode;
0295: int pos = 0;
0296:
0297: final int nodeType = _nodeType;
0298: if (nodeType != DTM.ELEMENT_NODE) {
0299: while (node != DTM.NULL) {
0300: if (_exptype2(node) == nodeType) {
0301: pos++;
0302: if (pos == position)
0303: return makeNodeHandle(node);
0304: }
0305:
0306: node = _nextsib2(node);
0307: }
0308: return NULL;
0309: } else {
0310: while (node != DTM.NULL) {
0311: if (_exptype2(node) >= DTM.NTYPES) {
0312: pos++;
0313: if (pos == position)
0314: return makeNodeHandle(node);
0315: }
0316: node = _nextsib2(node);
0317: }
0318: return NULL;
0319: }
0320: }
0321:
0322: } // end of TypedChildrenIterator
0323:
0324: /**
0325: * Iterator that returns the namespace nodes as defined by the XPath data model
0326: * for a given node, filtered by extended type ID.
0327: */
0328: public class TypedRootIterator extends RootIterator {
0329:
0330: /** The extended type ID that was requested. */
0331: private final int _nodeType;
0332:
0333: /**
0334: * Constructor TypedRootIterator
0335: *
0336: * @param nodeType The extended type ID being requested.
0337: */
0338: public TypedRootIterator(int nodeType) {
0339: super ();
0340: _nodeType = nodeType;
0341: }
0342:
0343: /**
0344: * Get the next node in the iteration.
0345: *
0346: * @return The next node handle in the iteration, or END.
0347: */
0348: public int next() {
0349: if (_startNode == _currentNode)
0350: return NULL;
0351:
0352: final int node = _startNode;
0353: int expType = _exptype2(makeNodeIdentity(node));
0354:
0355: _currentNode = node;
0356:
0357: if (_nodeType >= DTM.NTYPES) {
0358: if (_nodeType == expType) {
0359: return returnNode(node);
0360: }
0361: } else {
0362: if (expType < DTM.NTYPES) {
0363: if (expType == _nodeType) {
0364: return returnNode(node);
0365: }
0366: } else {
0367: if (m_extendedTypes[expType].getNodeType() == _nodeType) {
0368: return returnNode(node);
0369: }
0370: }
0371: }
0372:
0373: return NULL;
0374: }
0375: } // end of TypedRootIterator
0376:
0377: /**
0378: * Iterator that returns all siblings of a given node.
0379: */
0380: public class FollowingSiblingIterator extends
0381: InternalAxisIteratorBase {
0382:
0383: /**
0384: * Set start to END should 'close' the iterator,
0385: * i.e. subsequent call to next() should return END.
0386: *
0387: * @param node Sets the root of the iteration.
0388: *
0389: * @return A DTMAxisIterator set to the start of the iteration.
0390: */
0391: public DTMAxisIterator setStartNode(int node) {
0392: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0393: if (node == DTMDefaultBase.ROOTNODE)
0394: node = getDocument();
0395: if (_isRestartable) {
0396: _startNode = node;
0397: _currentNode = makeNodeIdentity(node);
0398:
0399: return resetPosition();
0400: }
0401:
0402: return this ;
0403: }
0404:
0405: /**
0406: * Get the next node in the iteration.
0407: *
0408: * @return The next node handle in the iteration, or END.
0409: */
0410: public int next() {
0411: _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
0412: : _nextsib2(_currentNode);
0413: return returnNode(makeNodeHandle(_currentNode));
0414: }
0415: } // end of FollowingSiblingIterator
0416:
0417: /**
0418: * Iterator that returns all following siblings of a given node.
0419: */
0420: public final class TypedFollowingSiblingIterator extends
0421: FollowingSiblingIterator {
0422:
0423: /** The extended type ID that was requested. */
0424: private final int _nodeType;
0425:
0426: /**
0427: * Constructor TypedFollowingSiblingIterator
0428: *
0429: *
0430: * @param type The extended type ID being requested.
0431: */
0432: public TypedFollowingSiblingIterator(int type) {
0433: _nodeType = type;
0434: }
0435:
0436: /**
0437: * Get the next node in the iteration.
0438: *
0439: * @return The next node handle in the iteration, or END.
0440: */
0441: public int next() {
0442: if (_currentNode == DTM.NULL) {
0443: return DTM.NULL;
0444: }
0445:
0446: int node = _currentNode;
0447: final int nodeType = _nodeType;
0448:
0449: if (nodeType != DTM.ELEMENT_NODE) {
0450: while ((node = _nextsib2(node)) != DTM.NULL
0451: && _exptype2(node) != nodeType) {
0452: }
0453: } else {
0454: while ((node = _nextsib2(node)) != DTM.NULL
0455: && _exptype2(node) < DTM.NTYPES) {
0456: }
0457: }
0458:
0459: _currentNode = node;
0460:
0461: return (node == DTM.NULL) ? DTM.NULL
0462: : returnNode(makeNodeHandle(node));
0463: }
0464:
0465: } // end of TypedFollowingSiblingIterator
0466:
0467: /**
0468: * Iterator that returns attribute nodes (of what nodes?)
0469: */
0470: public final class AttributeIterator extends
0471: InternalAxisIteratorBase {
0472:
0473: // assumes caller will pass element nodes
0474:
0475: /**
0476: * Set start to END should 'close' the iterator,
0477: * i.e. subsequent call to next() should return END.
0478: *
0479: * @param node Sets the root of the iteration.
0480: *
0481: * @return A DTMAxisIterator set to the start of the iteration.
0482: */
0483: public DTMAxisIterator setStartNode(int node) {
0484: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0485: if (node == DTMDefaultBase.ROOTNODE)
0486: node = getDocument();
0487: if (_isRestartable) {
0488: _startNode = node;
0489: _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
0490:
0491: return resetPosition();
0492: }
0493:
0494: return this ;
0495: }
0496:
0497: /**
0498: * Get the next node in the iteration.
0499: *
0500: * @return The next node handle in the iteration, or END.
0501: */
0502: public int next() {
0503:
0504: final int node = _currentNode;
0505:
0506: if (node != NULL) {
0507: _currentNode = getNextAttributeIdentity(node);
0508: return returnNode(makeNodeHandle(node));
0509: }
0510:
0511: return NULL;
0512: }
0513: } // end of AttributeIterator
0514:
0515: /**
0516: * Iterator that returns attribute nodes of a given type
0517: */
0518: public final class TypedAttributeIterator extends
0519: InternalAxisIteratorBase {
0520:
0521: /** The extended type ID that was requested. */
0522: private final int _nodeType;
0523:
0524: /**
0525: * Constructor TypedAttributeIterator
0526: *
0527: *
0528: * @param nodeType The extended type ID that is requested.
0529: */
0530: public TypedAttributeIterator(int nodeType) {
0531: _nodeType = nodeType;
0532: }
0533:
0534: // assumes caller will pass element nodes
0535:
0536: /**
0537: * Set start to END should 'close' the iterator,
0538: * i.e. subsequent call to next() should return END.
0539: *
0540: * @param node Sets the root of the iteration.
0541: *
0542: * @return A DTMAxisIterator set to the start of the iteration.
0543: */
0544: public DTMAxisIterator setStartNode(int node) {
0545: if (_isRestartable) {
0546: _startNode = node;
0547:
0548: _currentNode = getTypedAttribute(node, _nodeType);
0549:
0550: return resetPosition();
0551: }
0552:
0553: return this ;
0554: }
0555:
0556: /**
0557: * Get the next node in the iteration.
0558: *
0559: * @return The next node handle in the iteration, or END.
0560: */
0561: public int next() {
0562:
0563: final int node = _currentNode;
0564:
0565: // singleton iterator, since there can only be one attribute of
0566: // a given type.
0567: _currentNode = NULL;
0568:
0569: return returnNode(node);
0570: }
0571: } // end of TypedAttributeIterator
0572:
0573: /**
0574: * Iterator that returns preceding siblings of a given node
0575: */
0576: public class PrecedingSiblingIterator extends
0577: InternalAxisIteratorBase {
0578:
0579: /**
0580: * The node identity of _startNode for this iterator
0581: */
0582: protected int _startNodeID;
0583:
0584: /**
0585: * True if this iterator has a reversed axis.
0586: *
0587: * @return true.
0588: */
0589: public boolean isReverse() {
0590: return true;
0591: }
0592:
0593: /**
0594: * Set start to END should 'close' the iterator,
0595: * i.e. subsequent call to next() should return END.
0596: *
0597: * @param node Sets the root of the iteration.
0598: *
0599: * @return A DTMAxisIterator set to the start of the iteration.
0600: */
0601: public DTMAxisIterator setStartNode(int node) {
0602: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0603: if (node == DTMDefaultBase.ROOTNODE)
0604: node = getDocument();
0605: if (_isRestartable) {
0606: _startNode = node;
0607: node = _startNodeID = makeNodeIdentity(node);
0608:
0609: if (node == NULL) {
0610: _currentNode = node;
0611: return resetPosition();
0612: }
0613:
0614: int type = _type2(node);
0615: if (ExpandedNameTable.ATTRIBUTE == type
0616: || ExpandedNameTable.NAMESPACE == type) {
0617: _currentNode = node;
0618: } else {
0619: // Be careful to handle the Document node properly
0620: _currentNode = _parent2(node);
0621: if (NULL != _currentNode)
0622: _currentNode = _firstch2(_currentNode);
0623: else
0624: _currentNode = node;
0625: }
0626:
0627: return resetPosition();
0628: }
0629:
0630: return this ;
0631: }
0632:
0633: /**
0634: * Get the next node in the iteration.
0635: *
0636: * @return The next node handle in the iteration, or END.
0637: */
0638: public int next() {
0639:
0640: if (_currentNode == _startNodeID
0641: || _currentNode == DTM.NULL) {
0642: return NULL;
0643: } else {
0644: final int node = _currentNode;
0645: _currentNode = _nextsib2(node);
0646:
0647: return returnNode(makeNodeHandle(node));
0648: }
0649: }
0650: } // end of PrecedingSiblingIterator
0651:
0652: /**
0653: * Iterator that returns preceding siblings of a given type for
0654: * a given node
0655: */
0656: public final class TypedPrecedingSiblingIterator extends
0657: PrecedingSiblingIterator {
0658:
0659: /** The extended type ID that was requested. */
0660: private final int _nodeType;
0661:
0662: /**
0663: * Constructor TypedPrecedingSiblingIterator
0664: *
0665: *
0666: * @param type The extended type ID being requested.
0667: */
0668: public TypedPrecedingSiblingIterator(int type) {
0669: _nodeType = type;
0670: }
0671:
0672: /**
0673: * Get the next node in the iteration.
0674: *
0675: * @return The next node handle in the iteration, or END.
0676: */
0677: public int next() {
0678: int node = _currentNode;
0679:
0680: final int nodeType = _nodeType;
0681: final int startNodeID = _startNodeID;
0682:
0683: if (nodeType != DTM.ELEMENT_NODE) {
0684: while (node != NULL && node != startNodeID
0685: && _exptype2(node) != nodeType) {
0686: node = _nextsib2(node);
0687: }
0688: } else {
0689: while (node != NULL && node != startNodeID
0690: && _exptype2(node) < DTM.NTYPES) {
0691: node = _nextsib2(node);
0692: }
0693: }
0694:
0695: if (node == DTM.NULL || node == startNodeID) {
0696: _currentNode = NULL;
0697: return NULL;
0698: } else {
0699: _currentNode = _nextsib2(node);
0700: return returnNode(makeNodeHandle(node));
0701: }
0702: }
0703:
0704: /**
0705: * Return the index of the last node in this iterator.
0706: */
0707: public int getLast() {
0708: if (_last != -1)
0709: return _last;
0710:
0711: setMark();
0712:
0713: int node = _currentNode;
0714: final int nodeType = _nodeType;
0715: final int startNodeID = _startNodeID;
0716:
0717: int last = 0;
0718: if (nodeType != DTM.ELEMENT_NODE) {
0719: while (node != NULL && node != startNodeID) {
0720: if (_exptype2(node) == nodeType) {
0721: last++;
0722: }
0723: node = _nextsib2(node);
0724: }
0725: } else {
0726: while (node != NULL && node != startNodeID) {
0727: if (_exptype2(node) >= DTM.NTYPES) {
0728: last++;
0729: }
0730: node = _nextsib2(node);
0731: }
0732: }
0733:
0734: gotoMark();
0735:
0736: return (_last = last);
0737: }
0738: } // end of TypedPrecedingSiblingIterator
0739:
0740: /**
0741: * Iterator that returns preceding nodes of a given node.
0742: * This includes the node set {root+1, start-1}, but excludes
0743: * all ancestors, attributes, and namespace nodes.
0744: */
0745: public class PrecedingIterator extends InternalAxisIteratorBase {
0746:
0747: /** The max ancestors, but it can grow... */
0748: private final int _maxAncestors = 8;
0749:
0750: /**
0751: * The stack of start node + ancestors up to the root of the tree,
0752: * which we must avoid.
0753: */
0754: protected int[] _stack = new int[_maxAncestors];
0755:
0756: /** (not sure yet... -sb) */
0757: protected int _sp, _oldsp;
0758:
0759: protected int _markedsp, _markedNode, _markedDescendant;
0760:
0761: /* _currentNode precedes candidates. This is the identity, not the handle! */
0762:
0763: /**
0764: * True if this iterator has a reversed axis.
0765: *
0766: * @return true since this iterator is a reversed axis.
0767: */
0768: public boolean isReverse() {
0769: return true;
0770: }
0771:
0772: /**
0773: * Returns a deep copy of this iterator. The cloned iterator is not reset.
0774: *
0775: * @return a deep copy of this iterator.
0776: */
0777: public DTMAxisIterator cloneIterator() {
0778: _isRestartable = false;
0779:
0780: try {
0781: final PrecedingIterator clone = (PrecedingIterator) super
0782: .clone();
0783: final int[] stackCopy = new int[_stack.length];
0784: System
0785: .arraycopy(_stack, 0, stackCopy, 0,
0786: _stack.length);
0787:
0788: clone._stack = stackCopy;
0789:
0790: // return clone.reset();
0791: return clone;
0792: } catch (CloneNotSupportedException e) {
0793: throw new DTMException(
0794: XMLMessages
0795: .createXMLMessage(
0796: XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED,
0797: null)); //"Iterator clone not supported.");
0798: }
0799: }
0800:
0801: /**
0802: * Set start to END should 'close' the iterator,
0803: * i.e. subsequent call to next() should return END.
0804: *
0805: * @param node Sets the root of the iteration.
0806: *
0807: * @return A DTMAxisIterator set to the start of the iteration.
0808: */
0809: public DTMAxisIterator setStartNode(int node) {
0810: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0811: if (node == DTMDefaultBase.ROOTNODE)
0812: node = getDocument();
0813: if (_isRestartable) {
0814: node = makeNodeIdentity(node);
0815:
0816: // iterator is not a clone
0817: int parent, index;
0818:
0819: if (_type2(node) == DTM.ATTRIBUTE_NODE)
0820: node = _parent2(node);
0821:
0822: _startNode = node;
0823: _stack[index = 0] = node;
0824:
0825: parent = node;
0826: while ((parent = _parent2(parent)) != NULL) {
0827: if (++index == _stack.length) {
0828: final int[] stack = new int[index * 2];
0829: System.arraycopy(_stack, 0, stack, 0, index);
0830: _stack = stack;
0831: }
0832: _stack[index] = parent;
0833: }
0834:
0835: if (index > 0)
0836: --index; // Pop actual root node (if not start) back off the stack
0837:
0838: _currentNode = _stack[index]; // Last parent before root node
0839:
0840: _oldsp = _sp = index;
0841:
0842: return resetPosition();
0843: }
0844:
0845: return this ;
0846: }
0847:
0848: /**
0849: * Get the next node in the iteration.
0850: *
0851: * @return The next node handle in the iteration, or END.
0852: */
0853: public int next() {
0854: // Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
0855: // Also recoded the loop controls for clarity and to flatten out
0856: // the tail-recursion.
0857: for (++_currentNode; _sp >= 0; ++_currentNode) {
0858: if (_currentNode < _stack[_sp]) {
0859: int type = _type2(_currentNode);
0860: if (type != ATTRIBUTE_NODE
0861: && type != NAMESPACE_NODE)
0862: return returnNode(makeNodeHandle(_currentNode));
0863: } else
0864: --_sp;
0865: }
0866: return NULL;
0867: }
0868:
0869: // redefine DTMAxisIteratorBase's reset
0870:
0871: /**
0872: * Resets the iterator to the last start node.
0873: *
0874: * @return A DTMAxisIterator, which may or may not be the same as this
0875: * iterator.
0876: */
0877: public DTMAxisIterator reset() {
0878:
0879: _sp = _oldsp;
0880:
0881: return resetPosition();
0882: }
0883:
0884: public void setMark() {
0885: _markedsp = _sp;
0886: _markedNode = _currentNode;
0887: _markedDescendant = _stack[0];
0888: }
0889:
0890: public void gotoMark() {
0891: _sp = _markedsp;
0892: _currentNode = _markedNode;
0893: }
0894: } // end of PrecedingIterator
0895:
0896: /**
0897: * Iterator that returns preceding nodes of agiven type for a
0898: * given node. This includes the node set {root+1, start-1}, but
0899: * excludes all ancestors.
0900: */
0901: public final class TypedPrecedingIterator extends PrecedingIterator {
0902:
0903: /** The extended type ID that was requested. */
0904: private final int _nodeType;
0905:
0906: /**
0907: * Constructor TypedPrecedingIterator
0908: *
0909: *
0910: * @param type The extended type ID being requested.
0911: */
0912: public TypedPrecedingIterator(int type) {
0913: _nodeType = type;
0914: }
0915:
0916: /**
0917: * Get the next node in the iteration.
0918: *
0919: * @return The next node handle in the iteration, or END.
0920: */
0921: public int next() {
0922: int node = _currentNode;
0923: final int nodeType = _nodeType;
0924:
0925: if (nodeType >= DTM.NTYPES) {
0926: while (true) {
0927: node++;
0928:
0929: if (_sp < 0) {
0930: node = NULL;
0931: break;
0932: } else if (node >= _stack[_sp]) {
0933: if (--_sp < 0) {
0934: node = NULL;
0935: break;
0936: }
0937: } else if (_exptype2(node) == nodeType) {
0938: break;
0939: }
0940: }
0941: } else {
0942: int expType;
0943:
0944: while (true) {
0945: node++;
0946:
0947: if (_sp < 0) {
0948: node = NULL;
0949: break;
0950: } else if (node >= _stack[_sp]) {
0951: if (--_sp < 0) {
0952: node = NULL;
0953: break;
0954: }
0955: } else {
0956: expType = _exptype2(node);
0957: if (expType < DTM.NTYPES) {
0958: if (expType == nodeType) {
0959: break;
0960: }
0961: } else {
0962: if (m_extendedTypes[expType].getNodeType() == nodeType) {
0963: break;
0964: }
0965: }
0966: }
0967: }
0968: }
0969:
0970: _currentNode = node;
0971:
0972: return (node == NULL) ? NULL
0973: : returnNode(makeNodeHandle(node));
0974: }
0975: } // end of TypedPrecedingIterator
0976:
0977: /**
0978: * Iterator that returns following nodes of for a given node.
0979: */
0980: public class FollowingIterator extends InternalAxisIteratorBase {
0981: //DTMAxisTraverser m_traverser; // easier for now
0982:
0983: public FollowingIterator() {
0984: //m_traverser = getAxisTraverser(Axis.FOLLOWING);
0985: }
0986:
0987: /**
0988: * Set start to END should 'close' the iterator,
0989: * i.e. subsequent call to next() should return END.
0990: *
0991: * @param node Sets the root of the iteration.
0992: *
0993: * @return A DTMAxisIterator set to the start of the iteration.
0994: */
0995: public DTMAxisIterator setStartNode(int node) {
0996: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
0997: if (node == DTMDefaultBase.ROOTNODE)
0998: node = getDocument();
0999: if (_isRestartable) {
1000: _startNode = node;
1001:
1002: //_currentNode = m_traverser.first(node);
1003:
1004: node = makeNodeIdentity(node);
1005:
1006: int first;
1007: int type = _type2(node);
1008:
1009: if ((DTM.ATTRIBUTE_NODE == type)
1010: || (DTM.NAMESPACE_NODE == type)) {
1011: node = _parent2(node);
1012: first = _firstch2(node);
1013:
1014: if (NULL != first) {
1015: _currentNode = makeNodeHandle(first);
1016: return resetPosition();
1017: }
1018: }
1019:
1020: do {
1021: first = _nextsib2(node);
1022:
1023: if (NULL == first)
1024: node = _parent2(node);
1025: } while (NULL == first && NULL != node);
1026:
1027: _currentNode = makeNodeHandle(first);
1028:
1029: // _currentNode precedes possible following(node) nodes
1030: return resetPosition();
1031: }
1032:
1033: return this ;
1034: }
1035:
1036: /**
1037: * Get the next node in the iteration.
1038: *
1039: * @return The next node handle in the iteration, or END.
1040: */
1041: public int next() {
1042:
1043: int node = _currentNode;
1044:
1045: //_currentNode = m_traverser.next(_startNode, _currentNode);
1046: int current = makeNodeIdentity(node);
1047:
1048: while (true) {
1049: current++;
1050:
1051: int type = _type2(current);
1052: if (NULL == type) {
1053: _currentNode = NULL;
1054: return returnNode(node);
1055: }
1056:
1057: if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
1058: continue;
1059:
1060: _currentNode = makeNodeHandle(current);
1061: return returnNode(node);
1062: }
1063: }
1064:
1065: } // end of FollowingIterator
1066:
1067: /**
1068: * Iterator that returns following nodes of a given type for a given node.
1069: */
1070: public final class TypedFollowingIterator extends FollowingIterator {
1071:
1072: /** The extended type ID that was requested. */
1073: private final int _nodeType;
1074:
1075: /**
1076: * Constructor TypedFollowingIterator
1077: *
1078: *
1079: * @param type The extended type ID being requested.
1080: */
1081: public TypedFollowingIterator(int type) {
1082: _nodeType = type;
1083: }
1084:
1085: /**
1086: * Get the next node in the iteration.
1087: *
1088: * @return The next node handle in the iteration, or END.
1089: */
1090: public int next() {
1091: int current;
1092: int node;
1093: int type;
1094:
1095: final int nodeType = _nodeType;
1096: int currentNodeID = makeNodeIdentity(_currentNode);
1097:
1098: if (nodeType >= DTM.NTYPES) {
1099: do {
1100: node = currentNodeID;
1101: current = node;
1102:
1103: do {
1104: current++;
1105: type = _type2(current);
1106: } while (type != NULL
1107: && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
1108:
1109: currentNodeID = (type != NULL) ? current : NULL;
1110: } while (node != DTM.NULL
1111: && _exptype2(node) != nodeType);
1112: } else {
1113: do {
1114: node = currentNodeID;
1115: current = node;
1116:
1117: do {
1118: current++;
1119: type = _type2(current);
1120: } while (type != NULL
1121: && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
1122:
1123: currentNodeID = (type != NULL) ? current : NULL;
1124: } while (node != DTM.NULL
1125: && (_exptype2(node) != nodeType && _type2(node) != nodeType));
1126: }
1127:
1128: _currentNode = makeNodeHandle(currentNodeID);
1129: return (node == DTM.NULL ? DTM.NULL
1130: : returnNode(makeNodeHandle(node)));
1131: }
1132: } // end of TypedFollowingIterator
1133:
1134: /**
1135: * Iterator that returns the ancestors of a given node in document
1136: * order. (NOTE! This was changed from the XSLTC code!)
1137: */
1138: public class AncestorIterator extends InternalAxisIteratorBase {
1139: // The initial size of the ancestor array
1140: private static final int m_blocksize = 32;
1141:
1142: // The array for ancestor nodes. This array will grow dynamically.
1143: int[] m_ancestors = new int[m_blocksize];
1144:
1145: // Number of ancestor nodes in the array
1146: int m_size = 0;
1147:
1148: int m_ancestorsPos;
1149:
1150: int m_markedPos;
1151:
1152: /** The real start node for this axes, since _startNode will be adjusted. */
1153: int m_realStartNode;
1154:
1155: /**
1156: * Get start to END should 'close' the iterator,
1157: * i.e. subsequent call to next() should return END.
1158: *
1159: * @return The root node of the iteration.
1160: */
1161: public int getStartNode() {
1162: return m_realStartNode;
1163: }
1164:
1165: /**
1166: * True if this iterator has a reversed axis.
1167: *
1168: * @return true since this iterator is a reversed axis.
1169: */
1170: public final boolean isReverse() {
1171: return true;
1172: }
1173:
1174: /**
1175: * Returns a deep copy of this iterator. The cloned iterator is not reset.
1176: *
1177: * @return a deep copy of this iterator.
1178: */
1179: public DTMAxisIterator cloneIterator() {
1180: _isRestartable = false; // must set to false for any clone
1181:
1182: try {
1183: final AncestorIterator clone = (AncestorIterator) super
1184: .clone();
1185:
1186: clone._startNode = _startNode;
1187:
1188: // return clone.reset();
1189: return clone;
1190: } catch (CloneNotSupportedException e) {
1191: throw new DTMException(
1192: XMLMessages
1193: .createXMLMessage(
1194: XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED,
1195: null)); //"Iterator clone not supported.");
1196: }
1197: }
1198:
1199: /**
1200: * Set start to END should 'close' the iterator,
1201: * i.e. subsequent call to next() should return END.
1202: *
1203: * @param node Sets the root of the iteration.
1204: *
1205: * @return A DTMAxisIterator set to the start of the iteration.
1206: */
1207: public DTMAxisIterator setStartNode(int node) {
1208: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1209: if (node == DTMDefaultBase.ROOTNODE)
1210: node = getDocument();
1211: m_realStartNode = node;
1212:
1213: if (_isRestartable) {
1214: int nodeID = makeNodeIdentity(node);
1215: m_size = 0;
1216:
1217: if (nodeID == DTM.NULL) {
1218: _currentNode = DTM.NULL;
1219: m_ancestorsPos = 0;
1220: return this ;
1221: }
1222:
1223: // Start from the current node's parent if
1224: // _includeSelf is false.
1225: if (!_includeSelf) {
1226: nodeID = _parent2(nodeID);
1227: node = makeNodeHandle(nodeID);
1228: }
1229:
1230: _startNode = node;
1231:
1232: while (nodeID != END) {
1233: //m_ancestors.addElement(node);
1234: if (m_size >= m_ancestors.length) {
1235: int[] newAncestors = new int[m_size * 2];
1236: System.arraycopy(m_ancestors, 0, newAncestors,
1237: 0, m_ancestors.length);
1238: m_ancestors = newAncestors;
1239: }
1240:
1241: m_ancestors[m_size++] = node;
1242: nodeID = _parent2(nodeID);
1243: node = makeNodeHandle(nodeID);
1244: }
1245:
1246: m_ancestorsPos = m_size - 1;
1247:
1248: _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
1249: : DTM.NULL;
1250:
1251: return resetPosition();
1252: }
1253:
1254: return this ;
1255: }
1256:
1257: /**
1258: * Resets the iterator to the last start node.
1259: *
1260: * @return A DTMAxisIterator, which may or may not be the same as this
1261: * iterator.
1262: */
1263: public DTMAxisIterator reset() {
1264:
1265: m_ancestorsPos = m_size - 1;
1266:
1267: _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
1268: : DTM.NULL;
1269:
1270: return resetPosition();
1271: }
1272:
1273: /**
1274: * Get the next node in the iteration.
1275: *
1276: * @return The next node handle in the iteration, or END.
1277: */
1278: public int next() {
1279:
1280: int next = _currentNode;
1281:
1282: int pos = --m_ancestorsPos;
1283:
1284: _currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
1285: : DTM.NULL;
1286:
1287: return returnNode(next);
1288: }
1289:
1290: public void setMark() {
1291: m_markedPos = m_ancestorsPos;
1292: }
1293:
1294: public void gotoMark() {
1295: m_ancestorsPos = m_markedPos;
1296: _currentNode = m_ancestorsPos >= 0 ? m_ancestors[m_ancestorsPos]
1297: : DTM.NULL;
1298: }
1299: } // end of AncestorIterator
1300:
1301: /**
1302: * Typed iterator that returns the ancestors of a given node.
1303: */
1304: public final class TypedAncestorIterator extends AncestorIterator {
1305:
1306: /** The extended type ID that was requested. */
1307: private final int _nodeType;
1308:
1309: /**
1310: * Constructor TypedAncestorIterator
1311: *
1312: *
1313: * @param type The extended type ID being requested.
1314: */
1315: public TypedAncestorIterator(int type) {
1316: _nodeType = type;
1317: }
1318:
1319: /**
1320: * Set start to END should 'close' the iterator,
1321: * i.e. subsequent call to next() should return END.
1322: *
1323: * @param node Sets the root of the iteration.
1324: *
1325: * @return A DTMAxisIterator set to the start of the iteration.
1326: */
1327: public DTMAxisIterator setStartNode(int node) {
1328: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1329: if (node == DTMDefaultBase.ROOTNODE)
1330: node = getDocument();
1331: m_realStartNode = node;
1332:
1333: if (_isRestartable) {
1334: int nodeID = makeNodeIdentity(node);
1335: m_size = 0;
1336:
1337: if (nodeID == DTM.NULL) {
1338: _currentNode = DTM.NULL;
1339: m_ancestorsPos = 0;
1340: return this ;
1341: }
1342:
1343: final int nodeType = _nodeType;
1344:
1345: if (!_includeSelf) {
1346: nodeID = _parent2(nodeID);
1347: node = makeNodeHandle(nodeID);
1348: }
1349:
1350: _startNode = node;
1351:
1352: if (nodeType >= DTM.NTYPES) {
1353: while (nodeID != END) {
1354: int eType = _exptype2(nodeID);
1355:
1356: if (eType == nodeType) {
1357: if (m_size >= m_ancestors.length) {
1358: int[] newAncestors = new int[m_size * 2];
1359: System.arraycopy(m_ancestors, 0,
1360: newAncestors, 0,
1361: m_ancestors.length);
1362: m_ancestors = newAncestors;
1363: }
1364: m_ancestors[m_size++] = makeNodeHandle(nodeID);
1365: }
1366: nodeID = _parent2(nodeID);
1367: }
1368: } else {
1369: while (nodeID != END) {
1370: int eType = _exptype2(nodeID);
1371:
1372: if ((eType < DTM.NTYPES && eType == nodeType)
1373: || (eType >= DTM.NTYPES && m_extendedTypes[eType]
1374: .getNodeType() == nodeType)) {
1375: if (m_size >= m_ancestors.length) {
1376: int[] newAncestors = new int[m_size * 2];
1377: System.arraycopy(m_ancestors, 0,
1378: newAncestors, 0,
1379: m_ancestors.length);
1380: m_ancestors = newAncestors;
1381: }
1382: m_ancestors[m_size++] = makeNodeHandle(nodeID);
1383: }
1384: nodeID = _parent2(nodeID);
1385: }
1386: }
1387: m_ancestorsPos = m_size - 1;
1388:
1389: _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
1390: : DTM.NULL;
1391:
1392: return resetPosition();
1393: }
1394:
1395: return this ;
1396: }
1397:
1398: /**
1399: * Return the node at the given position.
1400: */
1401: public int getNodeByPosition(int position) {
1402: if (position > 0 && position <= m_size) {
1403: return m_ancestors[position - 1];
1404: } else
1405: return DTM.NULL;
1406: }
1407:
1408: /**
1409: * Returns the position of the last node within the iteration, as
1410: * defined by XPath.
1411: */
1412: public int getLast() {
1413: return m_size;
1414: }
1415: } // end of TypedAncestorIterator
1416:
1417: /**
1418: * Iterator that returns the descendants of a given node.
1419: */
1420: public class DescendantIterator extends InternalAxisIteratorBase {
1421:
1422: /**
1423: * Set start to END should 'close' the iterator,
1424: * i.e. subsequent call to next() should return END.
1425: *
1426: * @param node Sets the root of the iteration.
1427: *
1428: * @return A DTMAxisIterator set to the start of the iteration.
1429: */
1430: public DTMAxisIterator setStartNode(int node) {
1431: //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1432: if (node == DTMDefaultBase.ROOTNODE)
1433: node = getDocument();
1434: if (_isRestartable) {
1435: node = makeNodeIdentity(node);
1436: _startNode = node;
1437:
1438: if (_includeSelf)
1439: node--;
1440:
1441: _currentNode = node;
1442:
1443: return resetPosition();
1444: }
1445:
1446: return this ;
1447: }
1448:
1449: /**
1450: * Tell if this node identity is a descendant. Assumes that
1451: * the node info for the element has already been obtained.
1452: *
1453: * This one-sided test works only if the parent has been
1454: * previously tested and is known to be a descendent. It fails if
1455: * the parent is the _startNode's next sibling, or indeed any node
1456: * that follows _startNode in document order. That may suffice
1457: * for this iterator, but it's not really an isDescendent() test.
1458: * %REVIEW% rename?
1459: *
1460: * @param identity The index number of the node in question.
1461: * @return true if the index is a descendant of _startNode.
1462: */
1463: protected final boolean isDescendant(int identity) {
1464: return (_parent2(identity) >= _startNode)
1465: || (_startNode == identity);
1466: }
1467:
1468: /**
1469: * Get the next node in the iteration.
1470: *
1471: * @return The next node handle in the iteration, or END.
1472: */
1473: public int next() {
1474: final int startNode = _startNode;
1475: if (startNode == NULL) {
1476: return NULL;
1477: }
1478:
1479: if (_includeSelf && (_currentNode + 1) == startNode)
1480: return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
1481:
1482: int node = _currentNode;
1483: int type;
1484:
1485: // %OPT% If the startNode is the root node, do not need
1486: // to do the isDescendant() check.
1487: if (startNode == ROOTNODE) {
1488: int eType;
1489: do {
1490: node++;
1491: eType = _exptype2(node);
1492:
1493: if (NULL == eType) {
1494: _currentNode = NULL;
1495: return END;
1496: }
1497: } while (eType == TEXT_NODE
1498: || (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
1499: || type == NAMESPACE_NODE);
1500: } else {
1501: do {
1502: node++;
1503: type = _type2(node);
1504:
1505: if (NULL == type || !isDescendant(node)) {
1506: _currentNode = NULL;
1507: return END;
1508: }
1509: } while (ATTRIBUTE_NODE == type || TEXT_NODE == type
1510: || NAMESPACE_NODE == type);
1511: }
1512:
1513: _currentNode = node;
1514: return returnNode(makeNodeHandle(node)); // make handle.
1515: }
1516:
1517: /**
1518: * Reset.
1519: *
1520: */
1521: public DTMAxisIterator reset() {
1522:
1523: final boolean temp = _isRestartable;
1524:
1525: _isRestartable = true;
1526:
1527: setStartNode(makeNodeHandle(_startNode));
1528:
1529: _isRestartable = temp;
1530:
1531: return this ;
1532: }
1533:
1534: } // end of DescendantIterator
1535:
1536: /**
1537: * Typed iterator that returns the descendants of a given node.
1538: */
1539: public final class TypedDescendantIterator extends
1540: DescendantIterator {
1541:
1542: /** The extended type ID that was requested. */
1543: private final int _nodeType;
1544:
1545: /**
1546: * Constructor TypedDescendantIterator
1547: *
1548: *
1549: * @param nodeType Extended type ID being requested.
1550: */
1551: public TypedDescendantIterator(int nodeType) {
1552: _nodeType = nodeType;
1553: }
1554:
1555: /**
1556: * Get the next node in the iteration.
1557: *
1558: * @return The next node handle in the iteration, or END.
1559: */
1560: public int next() {
1561: final int startNode = _startNode;
1562: if (_startNode == NULL) {
1563: return NULL;
1564: }
1565:
1566: int node = _currentNode;
1567:
1568: int expType;
1569: final int nodeType = _nodeType;
1570:
1571: if (nodeType != DTM.ELEMENT_NODE) {
1572: do {
1573: node++;
1574: expType = _exptype2(node);
1575:
1576: if (NULL == expType || _parent2(node) < startNode
1577: && startNode != node) {
1578: _currentNode = NULL;
1579: return END;
1580: }
1581: } while (expType != nodeType);
1582: }
1583: // %OPT% If the start node is root (e.g. in the case of //node),
1584: // we can save the isDescendant() check, because all nodes are
1585: // descendants of root.
1586: else if (startNode == DTMDefaultBase.ROOTNODE) {
1587: do {
1588: node++;
1589: expType = _exptype2(node);
1590:
1591: if (NULL == expType) {
1592: _currentNode = NULL;
1593: return END;
1594: }
1595: } while (expType < DTM.NTYPES
1596: || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
1597: } else {
1598: do {
1599: node++;
1600: expType = _exptype2(node);
1601:
1602: if (NULL == expType || _parent2(node) < startNode
1603: && startNode != node) {
1604: _currentNode = NULL;
1605: return END;
1606: }
1607: } while (expType < DTM.NTYPES
1608: || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
1609: }
1610:
1611: _currentNode = node;
1612: return returnNode(makeNodeHandle(node));
1613: }
1614: } // end of TypedDescendantIterator
1615:
1616: /**
1617: * Iterator that returns a given node only if it is of a given type.
1618: */
1619: public final class TypedSingletonIterator extends SingletonIterator {
1620:
1621: /** The extended type ID that was requested. */
1622: private final int _nodeType;
1623:
1624: /**
1625: * Constructor TypedSingletonIterator
1626: *
1627: *
1628: * @param nodeType The extended type ID being requested.
1629: */
1630: public TypedSingletonIterator(int nodeType) {
1631: _nodeType = nodeType;
1632: }
1633:
1634: /**
1635: * Get the next node in the iteration.
1636: *
1637: * @return The next node handle in the iteration, or END.
1638: */
1639: public int next() {
1640:
1641: final int result = _currentNode;
1642: if (result == END)
1643: return DTM.NULL;
1644:
1645: _currentNode = END;
1646:
1647: if (_nodeType >= DTM.NTYPES) {
1648: if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
1649: return returnNode(result);
1650: }
1651: } else {
1652: if (_type2(makeNodeIdentity(result)) == _nodeType) {
1653: return returnNode(result);
1654: }
1655: }
1656:
1657: return NULL;
1658: }
1659: } // end of TypedSingletonIterator
1660:
1661: /*******************************************************************
1662: * End of nested iterators
1663: *******************************************************************/
1664:
1665: // %OPT% Array references which are used to cache the map0 arrays in
1666: // SuballocatedIntVectors. Using the cached arrays reduces the level
1667: // of indirection and results in better performance than just calling
1668: // SuballocatedIntVector.elementAt().
1669: private int[] m_exptype_map0;
1670: private int[] m_nextsib_map0;
1671: private int[] m_firstch_map0;
1672: private int[] m_parent_map0;
1673:
1674: // Double array references to the map arrays in SuballocatedIntVectors.
1675: private int[][] m_exptype_map;
1676: private int[][] m_nextsib_map;
1677: private int[][] m_firstch_map;
1678: private int[][] m_parent_map;
1679:
1680: // %OPT% Cache the array of extended types in this class
1681: protected ExtendedType[] m_extendedTypes;
1682:
1683: // A Vector which is used to store the values of attribute, namespace,
1684: // comment and PI nodes.
1685: //
1686: // %OPT% These values are unlikely to be equal. Storing
1687: // them in a plain Vector is more efficient than storing in the
1688: // DTMStringPool because we can save the cost for hash calculation.
1689: //
1690: // %REVISIT% Do we need a custom class (e.g. StringVector) here?
1691: protected Vector m_values;
1692:
1693: // The current index into the m_values Vector.
1694: private int m_valueIndex = 0;
1695:
1696: // The maximum value of the current node index.
1697: private int m_maxNodeIndex;
1698:
1699: // Cache the shift and mask values for the SuballocatedIntVectors.
1700: protected int m_SHIFT;
1701: protected int m_MASK;
1702: protected int m_blocksize;
1703:
1704: /** %OPT% If the offset and length of a Text node are within certain limits,
1705: * we store a bitwise encoded value into an int, using 10 bits (max. 1024)
1706: * for length and 21 bits for offset. We can save two SuballocatedIntVector
1707: * calls for each getStringValueX() and dispatchCharacterEvents() call by
1708: * doing this.
1709: */
1710: // The number of bits for the length of a Text node.
1711: protected final static int TEXT_LENGTH_BITS = 10;
1712:
1713: // The number of bits for the offset of a Text node.
1714: protected final static int TEXT_OFFSET_BITS = 21;
1715:
1716: // The maximum length value
1717: protected final static int TEXT_LENGTH_MAX = (1 << TEXT_LENGTH_BITS) - 1;
1718:
1719: // The maximum offset value
1720: protected final static int TEXT_OFFSET_MAX = (1 << TEXT_OFFSET_BITS) - 1;
1721:
1722: // True if we want to build the ID index table.
1723: protected boolean m_buildIdIndex = true;
1724:
1725: // Constant for empty String
1726: private static final String EMPTY_STR = "";
1727:
1728: // Constant for empty XMLString
1729: private static final XMLString EMPTY_XML_STR = new XMLStringDefault(
1730: "");
1731:
1732: /**
1733: * Construct a SAX2DTM2 object using the default block size.
1734: */
1735: public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
1736: DTMWSFilter whiteSpaceFilter,
1737: XMLStringFactory xstringfactory, boolean doIndexing) {
1738:
1739: this (mgr, source, dtmIdentity, whiteSpaceFilter,
1740: xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true,
1741: true, false);
1742: }
1743:
1744: /**
1745: * Construct a SAX2DTM2 object using the given block size.
1746: */
1747: public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
1748: DTMWSFilter whiteSpaceFilter,
1749: XMLStringFactory xstringfactory, boolean doIndexing,
1750: int blocksize, boolean usePrevsib, boolean buildIdIndex,
1751: boolean newNameTable) {
1752:
1753: super (mgr, source, dtmIdentity, whiteSpaceFilter,
1754: xstringfactory, doIndexing, blocksize, usePrevsib,
1755: newNameTable);
1756:
1757: // Initialize the values of m_SHIFT and m_MASK.
1758: int shift;
1759: for (shift = 0; (blocksize >>>= 1) != 0; ++shift)
1760: ;
1761:
1762: m_blocksize = 1 << shift;
1763: m_SHIFT = shift;
1764: m_MASK = m_blocksize - 1;
1765:
1766: m_buildIdIndex = buildIdIndex;
1767:
1768: // Some documents do not have attribute nodes. That is why
1769: // we set the initial size of this Vector to be small and set
1770: // the increment to a bigger number.
1771: m_values = new Vector(32, 512);
1772:
1773: m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
1774:
1775: // Set the map0 values in the constructor.
1776: m_exptype_map0 = m_exptype.getMap0();
1777: m_nextsib_map0 = m_nextsib.getMap0();
1778: m_firstch_map0 = m_firstch.getMap0();
1779: m_parent_map0 = m_parent.getMap0();
1780: }
1781:
1782: /**
1783: * Override DTMDefaultBase._exptype() by dropping the incremental code.
1784: *
1785: * <p>This one is less efficient than _exptype2. It is only used during
1786: * DTM building. _exptype2 is used after the document is fully built.
1787: */
1788: public final int _exptype(int identity) {
1789: return m_exptype.elementAt(identity);
1790: }
1791:
1792: /************************************************************************
1793: * DTM base accessor interfaces
1794: *
1795: * %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
1796: * very important to the DTM performance. To have the best performace,
1797: * these several interfaces have direct access to the internal arrays of
1798: * the SuballocatedIntVectors. The final modifier also has a noticeable
1799: * impact on performance.
1800: ***********************************************************************/
1801:
1802: /**
1803: * The optimized version of DTMDefaultBase._exptype().
1804: *
1805: * @param identity A node identity, which <em>must not</em> be equal to
1806: * <code>DTM.NULL</code>
1807: */
1808: public final int _exptype2(int identity) {
1809: //return m_exptype.elementAt(identity);
1810:
1811: if (identity < m_blocksize)
1812: return m_exptype_map0[identity];
1813: else
1814: return m_exptype_map[identity >>> m_SHIFT][identity
1815: & m_MASK];
1816: }
1817:
1818: /**
1819: * The optimized version of DTMDefaultBase._nextsib().
1820: *
1821: * @param identity A node identity, which <em>must not</em> be equal to
1822: * <code>DTM.NULL</code>
1823: */
1824: public final int _nextsib2(int identity) {
1825: //return m_nextsib.elementAt(identity);
1826:
1827: if (identity < m_blocksize)
1828: return m_nextsib_map0[identity];
1829: else
1830: return m_nextsib_map[identity >>> m_SHIFT][identity
1831: & m_MASK];
1832: }
1833:
1834: /**
1835: * The optimized version of DTMDefaultBase._firstch().
1836: *
1837: * @param identity A node identity, which <em>must not</em> be equal to
1838: * <code>DTM.NULL</code>
1839: */
1840: public final int _firstch2(int identity) {
1841: //return m_firstch.elementAt(identity);
1842:
1843: if (identity < m_blocksize)
1844: return m_firstch_map0[identity];
1845: else
1846: return m_firstch_map[identity >>> m_SHIFT][identity
1847: & m_MASK];
1848: }
1849:
1850: /**
1851: * The optimized version of DTMDefaultBase._parent().
1852: *
1853: * @param identity A node identity, which <em>must not</em> be equal to
1854: * <code>DTM.NULL</code>
1855: */
1856: public final int _parent2(int identity) {
1857: //return m_parent.elementAt(identity);
1858:
1859: if (identity < m_blocksize)
1860: return m_parent_map0[identity];
1861: else
1862: return m_parent_map[identity >>> m_SHIFT][identity & m_MASK];
1863: }
1864:
1865: /**
1866: * The optimized version of DTMDefaultBase._type().
1867: *
1868: * @param identity A node identity, which <em>must not</em> be equal to
1869: * <code>DTM.NULL</code>
1870: */
1871: public final int _type2(int identity) {
1872: //int eType = _exptype2(identity);
1873: int eType;
1874: if (identity < m_blocksize)
1875: eType = m_exptype_map0[identity];
1876: else
1877: eType = m_exptype_map[identity >>> m_SHIFT][identity
1878: & m_MASK];
1879:
1880: if (NULL != eType)
1881: return m_extendedTypes[eType].getNodeType();
1882: else
1883: return NULL;
1884: }
1885:
1886: /**
1887: * The optimized version of DTMDefaultBase.getExpandedTypeID(int).
1888: *
1889: * <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
1890: * is mostly called from the compiled translets.
1891: */
1892: public final int getExpandedTypeID2(int nodeHandle) {
1893: int nodeID = makeNodeIdentity(nodeHandle);
1894:
1895: //return (nodeID != NULL) ? _exptype2(nodeID) : NULL;
1896:
1897: if (nodeID != NULL) {
1898: if (nodeID < m_blocksize)
1899: return m_exptype_map0[nodeID];
1900: else
1901: return m_exptype_map[nodeID >>> m_SHIFT][nodeID
1902: & m_MASK];
1903: } else
1904: return NULL;
1905: }
1906:
1907: /*************************************************************************
1908: * END of DTM base accessor interfaces
1909: *************************************************************************/
1910:
1911: /**
1912: * Return the node type from the expanded type
1913: */
1914: public final int _exptype2Type(int exptype) {
1915: if (NULL != exptype)
1916: return m_extendedTypes[exptype].getNodeType();
1917: else
1918: return NULL;
1919: }
1920:
1921: /**
1922: * Get a prefix either from the uri mapping, or just make
1923: * one up!
1924: *
1925: * @param uri The namespace URI, which may be null.
1926: *
1927: * @return The prefix if there is one, or null.
1928: */
1929: public int getIdForNamespace(String uri) {
1930: int index = m_values.indexOf(uri);
1931: if (index < 0) {
1932: m_values.addElement(uri);
1933: return m_valueIndex++;
1934: } else
1935: return index;
1936: }
1937:
1938: /**
1939: * Override SAX2DTM.startElement()
1940: *
1941: * <p>Receive notification of the start of an element.
1942: *
1943: * <p>By default, do nothing. Application writers may override this
1944: * method in a subclass to take specific actions at the start of
1945: * each element (such as allocating a new tree node or writing
1946: * output to a file).</p>
1947: *
1948: * @param uri The Namespace URI, or the empty string if the
1949: * element has no Namespace URI or if Namespace
1950: * processing is not being performed.
1951: * @param localName The local name (without prefix), or the
1952: * empty string if Namespace processing is not being
1953: * performed.
1954: * @param qName The qualified name (with prefix), or the
1955: * empty string if qualified names are not available.
1956: * @param attributes The specified or defaulted attributes.
1957: * @throws SAXException Any SAX exception, possibly
1958: * wrapping another exception.
1959: * @see org.xml.sax.ContentHandler#startElement
1960: */
1961: public void startElement(String uri, String localName,
1962: String qName, Attributes attributes) throws SAXException {
1963:
1964: charactersFlush();
1965:
1966: int exName = m_expandedNameTable.getExpandedTypeID(uri,
1967: localName, DTM.ELEMENT_NODE);
1968:
1969: int prefixIndex = (qName.length() != localName.length()) ? m_valuesOrPrefixes
1970: .stringToIndex(qName)
1971: : 0;
1972:
1973: int elemNode = addNode(DTM.ELEMENT_NODE, exName, m_parents
1974: .peek(), m_previous, prefixIndex, true);
1975:
1976: if (m_indexing)
1977: indexNode(exName, elemNode);
1978:
1979: m_parents.push(elemNode);
1980:
1981: int startDecls = m_contextIndexes.peek();
1982: int nDecls = m_prefixMappings.size();
1983: String prefix;
1984:
1985: if (!m_pastFirstElement) {
1986: // SPECIAL CASE: Implied declaration at root element
1987: prefix = "xml";
1988: String declURL = "http://www.w3.org/XML/1998/namespace";
1989: exName = m_expandedNameTable.getExpandedTypeID(null,
1990: prefix, DTM.NAMESPACE_NODE);
1991: m_values.addElement(declURL);
1992: int val = m_valueIndex++;
1993: addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL,
1994: val, false);
1995: m_pastFirstElement = true;
1996: }
1997:
1998: for (int i = startDecls; i < nDecls; i += 2) {
1999: prefix = (String) m_prefixMappings.elementAt(i);
2000:
2001: if (prefix == null)
2002: continue;
2003:
2004: String declURL = (String) m_prefixMappings.elementAt(i + 1);
2005:
2006: exName = m_expandedNameTable.getExpandedTypeID(null,
2007: prefix, DTM.NAMESPACE_NODE);
2008:
2009: m_values.addElement(declURL);
2010: int val = m_valueIndex++;
2011:
2012: addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL,
2013: val, false);
2014: }
2015:
2016: int n = attributes.getLength();
2017:
2018: for (int i = 0; i < n; i++) {
2019: String attrUri = attributes.getURI(i);
2020: String attrQName = attributes.getQName(i);
2021: String valString = attributes.getValue(i);
2022:
2023: int nodeType;
2024:
2025: String attrLocalName = attributes.getLocalName(i);
2026:
2027: if ((null != attrQName)
2028: && (attrQName.equals("xmlns") || attrQName
2029: .startsWith("xmlns:"))) {
2030: prefix = getPrefix(attrQName, attrUri);
2031: if (declAlreadyDeclared(prefix))
2032: continue; // go to the next attribute.
2033:
2034: nodeType = DTM.NAMESPACE_NODE;
2035: } else {
2036: nodeType = DTM.ATTRIBUTE_NODE;
2037:
2038: if (m_buildIdIndex
2039: && attributes.getType(i).equalsIgnoreCase("ID"))
2040: setIDAttribute(valString, elemNode);
2041: }
2042:
2043: // Bit of a hack... if somehow valString is null, stringToIndex will
2044: // return -1, which will make things very unhappy.
2045: if (null == valString)
2046: valString = "";
2047:
2048: m_values.addElement(valString);
2049: int val = m_valueIndex++;
2050:
2051: if (attrLocalName.length() != attrQName.length()) {
2052:
2053: prefixIndex = m_valuesOrPrefixes
2054: .stringToIndex(attrQName);
2055:
2056: int dataIndex = m_data.size();
2057:
2058: m_data.addElement(prefixIndex);
2059: m_data.addElement(val);
2060:
2061: val = -dataIndex;
2062: }
2063:
2064: exName = m_expandedNameTable.getExpandedTypeID(attrUri,
2065: attrLocalName, nodeType);
2066: addNode(nodeType, exName, elemNode, DTM.NULL, val, false);
2067: }
2068:
2069: if (null != m_wsfilter) {
2070: short wsv = m_wsfilter.getShouldStripSpace(
2071: makeNodeHandle(elemNode), this );
2072: boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ? getShouldStripWhitespace()
2073: : (DTMWSFilter.STRIP == wsv);
2074:
2075: pushShouldStripWhitespace(shouldStrip);
2076: }
2077:
2078: m_previous = DTM.NULL;
2079:
2080: m_contextIndexes.push(m_prefixMappings.size()); // for the children.
2081: }
2082:
2083: /**
2084: * Receive notification of the end of an element.
2085: *
2086: * <p>By default, do nothing. Application writers may override this
2087: * method in a subclass to take specific actions at the end of
2088: * each element (such as finalising a tree node or writing
2089: * output to a file).</p>
2090: *
2091: * @param uri The Namespace URI, or the empty string if the
2092: * element has no Namespace URI or if Namespace
2093: * processing is not being performed.
2094: * @param localName The local name (without prefix), or the
2095: * empty string if Namespace processing is not being
2096: * performed.
2097: * @param qName The qualified XML 1.0 name (with prefix), or the
2098: * empty string if qualified names are not available.
2099: * @throws SAXException Any SAX exception, possibly
2100: * wrapping another exception.
2101: * @see org.xml.sax.ContentHandler#endElement
2102: */
2103: public void endElement(String uri, String localName, String qName)
2104: throws SAXException {
2105: charactersFlush();
2106:
2107: // If no one noticed, startPrefixMapping is a drag.
2108: // Pop the context for the last child (the one pushed by startElement)
2109: m_contextIndexes.quickPop(1);
2110:
2111: // Do it again for this one (the one pushed by the last endElement).
2112: int topContextIndex = m_contextIndexes.peek();
2113: if (topContextIndex != m_prefixMappings.size()) {
2114: m_prefixMappings.setSize(topContextIndex);
2115: }
2116:
2117: m_previous = m_parents.pop();
2118:
2119: popShouldStripWhitespace();
2120: }
2121:
2122: /**
2123: * Report an XML comment anywhere in the document.
2124: *
2125: * <p>This callback will be used for comments inside or outside the
2126: * document element, including comments in the external DTD
2127: * subset (if read).</p>
2128: *
2129: * @param ch An array holding the characters in the comment.
2130: * @param start The starting position in the array.
2131: * @param length The number of characters to use from the array.
2132: * @throws SAXException The application may raise an exception.
2133: */
2134: public void comment(char ch[], int start, int length)
2135: throws SAXException {
2136:
2137: if (m_insideDTD) // ignore comments if we're inside the DTD
2138: return;
2139:
2140: charactersFlush();
2141:
2142: // %OPT% Saving the comment string in a Vector has a lower cost than
2143: // saving it in DTMStringPool.
2144: m_values.addElement(new String(ch, start, length));
2145: int dataIndex = m_valueIndex++;
2146:
2147: m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
2148: m_parents.peek(), m_previous, dataIndex, false);
2149: }
2150:
2151: /**
2152: * Receive notification of the beginning of the document.
2153: *
2154: * @throws SAXException Any SAX exception, possibly
2155: * wrapping another exception.
2156: * @see org.xml.sax.ContentHandler#startDocument
2157: */
2158: public void startDocument() throws SAXException {
2159:
2160: int doc = addNode(DTM.DOCUMENT_NODE, DTM.DOCUMENT_NODE,
2161: DTM.NULL, DTM.NULL, 0, true);
2162:
2163: m_parents.push(doc);
2164: m_previous = DTM.NULL;
2165:
2166: m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
2167: }
2168:
2169: /**
2170: * Receive notification of the end of the document.
2171: *
2172: * @throws SAXException Any SAX exception, possibly
2173: * wrapping another exception.
2174: * @see org.xml.sax.ContentHandler#endDocument
2175: */
2176: public void endDocument() throws SAXException {
2177: super .endDocument();
2178:
2179: // Add a NULL entry to the end of the node arrays as
2180: // the end indication.
2181: m_exptype.addElement(NULL);
2182: m_parent.addElement(NULL);
2183: m_nextsib.addElement(NULL);
2184: m_firstch.addElement(NULL);
2185:
2186: // Set the cached references after the document is built.
2187: m_extendedTypes = m_expandedNameTable.getExtendedTypes();
2188: m_exptype_map = m_exptype.getMap();
2189: m_nextsib_map = m_nextsib.getMap();
2190: m_firstch_map = m_firstch.getMap();
2191: m_parent_map = m_parent.getMap();
2192: }
2193:
2194: /**
2195: * Construct the node map from the node.
2196: *
2197: * @param type raw type ID, one of DTM.XXX_NODE.
2198: * @param expandedTypeID The expended type ID.
2199: * @param parentIndex The current parent index.
2200: * @param previousSibling The previous sibling index.
2201: * @param dataOrPrefix index into m_data table, or string handle.
2202: * @param canHaveFirstChild true if the node can have a first child, false
2203: * if it is atomic.
2204: *
2205: * @return The index identity of the node that was added.
2206: */
2207: protected final int addNode(int type, int expandedTypeID,
2208: int parentIndex, int previousSibling, int dataOrPrefix,
2209: boolean canHaveFirstChild) {
2210: // Common to all nodes:
2211: int nodeIndex = m_size++;
2212:
2213: // Have we overflowed a DTM Identity's addressing range?
2214: //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
2215: if (nodeIndex == m_maxNodeIndex) {
2216: addNewDTMID(nodeIndex);
2217: m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
2218: }
2219:
2220: m_firstch.addElement(DTM.NULL);
2221: m_nextsib.addElement(DTM.NULL);
2222: m_parent.addElement(parentIndex);
2223: m_exptype.addElement(expandedTypeID);
2224: m_dataOrQName.addElement(dataOrPrefix);
2225:
2226: if (m_prevsib != null) {
2227: m_prevsib.addElement(previousSibling);
2228: }
2229:
2230: if (m_locator != null && m_useSourceLocationProperty) {
2231: setSourceLocation();
2232: }
2233:
2234: // Note that nextSibling is not processed until charactersFlush()
2235: // is called, to handle successive characters() events.
2236:
2237: // Special handling by type: Declare namespaces, attach first child
2238: switch (type) {
2239: case DTM.NAMESPACE_NODE:
2240: declareNamespaceInContext(parentIndex, nodeIndex);
2241: break;
2242: case DTM.ATTRIBUTE_NODE:
2243: break;
2244: default:
2245: if (DTM.NULL != previousSibling) {
2246: m_nextsib.setElementAt(nodeIndex, previousSibling);
2247: } else if (DTM.NULL != parentIndex) {
2248: m_firstch.setElementAt(nodeIndex, parentIndex);
2249: }
2250: break;
2251: }
2252:
2253: return nodeIndex;
2254: }
2255:
2256: /**
2257: * Check whether accumulated text should be stripped; if not,
2258: * append the appropriate flavor of text/cdata node.
2259: */
2260: protected final void charactersFlush() {
2261:
2262: if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
2263: {
2264: int length = m_chars.size() - m_textPendingStart;
2265: boolean doStrip = false;
2266:
2267: if (getShouldStripWhitespace()) {
2268: doStrip = m_chars.isWhitespace(m_textPendingStart,
2269: length);
2270: }
2271:
2272: if (doStrip) {
2273: m_chars.setLength(m_textPendingStart); // Discard accumulated text
2274: } else {
2275: // Guard against characters/ignorableWhitespace events that
2276: // contained no characters. They should not result in a node.
2277: if (length > 0) {
2278: // If the offset and length do not exceed the given limits
2279: // (offset < 2^21 and length < 2^10), then save both the offset
2280: // and length in a bitwise encoded value.
2281: if (length <= TEXT_LENGTH_MAX
2282: && m_textPendingStart <= TEXT_OFFSET_MAX) {
2283: m_previous = addNode(
2284: m_coalescedTextType,
2285: DTM.TEXT_NODE,
2286: m_parents.peek(),
2287: m_previous,
2288: length
2289: + (m_textPendingStart << TEXT_LENGTH_BITS),
2290: false);
2291:
2292: } else {
2293: // Store offset and length in the m_data array if one exceeds
2294: // the given limits. Use a negative dataIndex as an indication.
2295: int dataIndex = m_data.size();
2296: m_previous = addNode(m_coalescedTextType,
2297: DTM.TEXT_NODE, m_parents.peek(),
2298: m_previous, -dataIndex, false);
2299:
2300: m_data.addElement(m_textPendingStart);
2301: m_data.addElement(length);
2302: }
2303: }
2304: }
2305:
2306: // Reset for next text block
2307: m_textPendingStart = -1;
2308: m_textType = m_coalescedTextType = DTM.TEXT_NODE;
2309: }
2310: }
2311:
2312: /**
2313: * Override the processingInstruction() interface in SAX2DTM2.
2314: * <p>
2315: * %OPT% This one is different from SAX2DTM.processingInstruction()
2316: * in that we do not use extended types for PI nodes. The name of
2317: * the PI is saved in the DTMStringPool.
2318: *
2319: * Receive notification of a processing instruction.
2320: *
2321: * @param target The processing instruction target.
2322: * @param data The processing instruction data, or null if
2323: * none is supplied.
2324: * @throws SAXException Any SAX exception, possibly
2325: * wrapping another exception.
2326: * @see org.xml.sax.ContentHandler#processingInstruction
2327: */
2328: public void processingInstruction(String target, String data)
2329: throws SAXException {
2330:
2331: charactersFlush();
2332:
2333: int dataIndex = m_data.size();
2334: m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
2335: DTM.PROCESSING_INSTRUCTION_NODE, m_parents.peek(),
2336: m_previous, -dataIndex, false);
2337:
2338: m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
2339: m_values.addElement(data);
2340: m_data.addElement(m_valueIndex++);
2341:
2342: }
2343:
2344: /**
2345: * The optimized version of DTMDefaultBase.getFirstAttribute().
2346: * <p>
2347: * Given a node handle, get the index of the node's first attribute.
2348: *
2349: * @param nodeHandle int Handle of the node.
2350: * @return Handle of first attribute, or DTM.NULL to indicate none exists.
2351: */
2352: public final int getFirstAttribute(int nodeHandle) {
2353: int nodeID = makeNodeIdentity(nodeHandle);
2354:
2355: if (nodeID == DTM.NULL)
2356: return DTM.NULL;
2357:
2358: int type = _type2(nodeID);
2359:
2360: if (DTM.ELEMENT_NODE == type) {
2361: // Assume that attributes and namespaces immediately follow the element.
2362: while (true) {
2363: nodeID++;
2364: // Assume this can not be null.
2365: type = _type2(nodeID);
2366:
2367: if (type == DTM.ATTRIBUTE_NODE) {
2368: return makeNodeHandle(nodeID);
2369: } else if (DTM.NAMESPACE_NODE != type) {
2370: break;
2371: }
2372: }
2373: }
2374:
2375: return DTM.NULL;
2376: }
2377:
2378: /**
2379: * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
2380: * <p>
2381: * Given a node identity, get the index of the node's first attribute.
2382: *
2383: * @param identity int identity of the node.
2384: * @return Identity of first attribute, or DTM.NULL to indicate none exists.
2385: */
2386: protected int getFirstAttributeIdentity(int identity) {
2387: if (identity == NULL) {
2388: return NULL;
2389: }
2390: int type = _type2(identity);
2391:
2392: if (DTM.ELEMENT_NODE == type) {
2393: // Assume that attributes and namespaces immediately follow the element.
2394: while (true) {
2395: identity++;
2396:
2397: // Assume this can not be null.
2398: type = _type2(identity);
2399:
2400: if (type == DTM.ATTRIBUTE_NODE) {
2401: return identity;
2402: } else if (DTM.NAMESPACE_NODE != type) {
2403: break;
2404: }
2405: }
2406: }
2407:
2408: return DTM.NULL;
2409: }
2410:
2411: /**
2412: * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
2413: * <p>
2414: * Given a node identity for an attribute, advance to the next attribute.
2415: *
2416: * @param identity int identity of the attribute node. This
2417: * <strong>must</strong> be an attribute node.
2418: *
2419: * @return int DTM node-identity of the resolved attr,
2420: * or DTM.NULL to indicate none exists.
2421: *
2422: */
2423: protected int getNextAttributeIdentity(int identity) {
2424: // Assume that attributes and namespace nodes immediately follow the element
2425: while (true) {
2426: identity++;
2427: int type = _type2(identity);
2428:
2429: if (type == DTM.ATTRIBUTE_NODE) {
2430: return identity;
2431: } else if (type != DTM.NAMESPACE_NODE) {
2432: break;
2433: }
2434: }
2435:
2436: return DTM.NULL;
2437: }
2438:
2439: /**
2440: * The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
2441: * <p>
2442: * Given a node handle and an expanded type ID, get the index of the node's
2443: * attribute of that type, if any.
2444: *
2445: * @param nodeHandle int Handle of the node.
2446: * @param attType int expanded type ID of the required attribute.
2447: * @return Handle of attribute of the required type, or DTM.NULL to indicate
2448: * none exists.
2449: */
2450: protected final int getTypedAttribute(int nodeHandle, int attType) {
2451:
2452: int nodeID = makeNodeIdentity(nodeHandle);
2453:
2454: if (nodeID == DTM.NULL)
2455: return DTM.NULL;
2456:
2457: int type = _type2(nodeID);
2458:
2459: if (DTM.ELEMENT_NODE == type) {
2460: int expType;
2461: while (true) {
2462: nodeID++;
2463: expType = _exptype2(nodeID);
2464:
2465: if (expType != DTM.NULL)
2466: type = m_extendedTypes[expType].getNodeType();
2467: else
2468: return DTM.NULL;
2469:
2470: if (type == DTM.ATTRIBUTE_NODE) {
2471: if (expType == attType)
2472: return makeNodeHandle(nodeID);
2473: } else if (DTM.NAMESPACE_NODE != type) {
2474: break;
2475: }
2476: }
2477: }
2478:
2479: return DTM.NULL;
2480: }
2481:
2482: /**
2483: * Override SAX2DTM.getLocalName() in SAX2DTM2.
2484: * <p>Processing for PIs is different.
2485: *
2486: * Given a node handle, return its XPath- style localname. (As defined in
2487: * Namespaces, this is the portion of the name after any colon character).
2488: *
2489: * @param nodeHandle the id of the node.
2490: * @return String Local name of this node.
2491: */
2492: public String getLocalName(int nodeHandle) {
2493: int expType = _exptype(makeNodeIdentity(nodeHandle));
2494:
2495: if (expType == DTM.PROCESSING_INSTRUCTION_NODE) {
2496: int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
2497: dataIndex = m_data.elementAt(-dataIndex);
2498: return m_valuesOrPrefixes.indexToString(dataIndex);
2499: } else
2500: return m_expandedNameTable.getLocalName(expType);
2501: }
2502:
2503: /**
2504: * The optimized version of SAX2DTM.getNodeNameX().
2505: * <p>
2506: * Given a node handle, return the XPath node name. This should be the name
2507: * as described by the XPath data model, NOT the DOM- style name.
2508: *
2509: * @param nodeHandle the id of the node.
2510: * @return String Name of this node, which may be an empty string.
2511: */
2512: public final String getNodeNameX(int nodeHandle) {
2513:
2514: int nodeID = makeNodeIdentity(nodeHandle);
2515: int eType = _exptype2(nodeID);
2516:
2517: if (eType == DTM.PROCESSING_INSTRUCTION_NODE) {
2518: int dataIndex = _dataOrQName(nodeID);
2519: dataIndex = m_data.elementAt(-dataIndex);
2520: return m_valuesOrPrefixes.indexToString(dataIndex);
2521: }
2522:
2523: final ExtendedType extType = m_extendedTypes[eType];
2524:
2525: if (extType.getNamespace().length() == 0) {
2526: return extType.getLocalName();
2527: } else {
2528: int qnameIndex = m_dataOrQName.elementAt(nodeID);
2529:
2530: if (qnameIndex == 0)
2531: return extType.getLocalName();
2532:
2533: if (qnameIndex < 0) {
2534: qnameIndex = -qnameIndex;
2535: qnameIndex = m_data.elementAt(qnameIndex);
2536: }
2537:
2538: return m_valuesOrPrefixes.indexToString(qnameIndex);
2539: }
2540: }
2541:
2542: /**
2543: * The optimized version of SAX2DTM.getNodeName().
2544: * <p>
2545: * Given a node handle, return its DOM-style node name. This will include
2546: * names such as #text or #document.
2547: *
2548: * @param nodeHandle the id of the node.
2549: * @return String Name of this node, which may be an empty string.
2550: * %REVIEW% Document when empty string is possible...
2551: * %REVIEW-COMMENT% It should never be empty, should it?
2552: */
2553: public String getNodeName(int nodeHandle) {
2554:
2555: int nodeID = makeNodeIdentity(nodeHandle);
2556: int eType = _exptype2(nodeID);
2557:
2558: final ExtendedType extType = m_extendedTypes[eType];
2559: if (extType.getNamespace().length() == 0) {
2560: int type = extType.getNodeType();
2561:
2562: String localName = extType.getLocalName();
2563: if (type == DTM.NAMESPACE_NODE) {
2564: if (localName.length() == 0)
2565: return "xmlns";
2566: else
2567: return "xmlns:" + localName;
2568: } else if (type == DTM.PROCESSING_INSTRUCTION_NODE) {
2569: int dataIndex = _dataOrQName(nodeID);
2570: dataIndex = m_data.elementAt(-dataIndex);
2571: return m_valuesOrPrefixes.indexToString(dataIndex);
2572: } else if (localName.length() == 0) {
2573: return getFixedNames(type);
2574: } else
2575: return localName;
2576: } else {
2577: int qnameIndex = m_dataOrQName.elementAt(nodeID);
2578:
2579: if (qnameIndex == 0)
2580: return extType.getLocalName();
2581:
2582: if (qnameIndex < 0) {
2583: qnameIndex = -qnameIndex;
2584: qnameIndex = m_data.elementAt(qnameIndex);
2585: }
2586:
2587: return m_valuesOrPrefixes.indexToString(qnameIndex);
2588: }
2589: }
2590:
2591: /**
2592: * Override SAX2DTM.getStringValue(int)
2593: * <p>
2594: * This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
2595: * <p>
2596: * If the caller supplies an XMLStringFactory, the getStringValue() interface
2597: * in SAX2DTM will be called. Otherwise just calls getStringValueX() and
2598: * wraps the returned String in an XMLString.
2599: *
2600: * Get the string-value of a node as a String object
2601: * (see http://www.w3.org/TR/xpath#data-model
2602: * for the definition of a node's string-value).
2603: *
2604: * @param nodeHandle The node ID.
2605: *
2606: * @return A string object that represents the string-value of the given node.
2607: */
2608: public XMLString getStringValue(int nodeHandle) {
2609: int identity = makeNodeIdentity(nodeHandle);
2610: if (identity == DTM.NULL)
2611: return EMPTY_XML_STR;
2612:
2613: int type = _type2(identity);
2614:
2615: if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE) {
2616: int startNode = identity;
2617: identity = _firstch2(identity);
2618: if (DTM.NULL != identity) {
2619: int offset = -1;
2620: int length = 0;
2621:
2622: do {
2623: type = _exptype2(identity);
2624:
2625: if (type == DTM.TEXT_NODE
2626: || type == DTM.CDATA_SECTION_NODE) {
2627: int dataIndex = m_dataOrQName
2628: .elementAt(identity);
2629: if (dataIndex >= 0) {
2630: if (-1 == offset) {
2631: offset = dataIndex >>> TEXT_LENGTH_BITS;
2632: }
2633:
2634: length += dataIndex & TEXT_LENGTH_MAX;
2635: } else {
2636: if (-1 == offset) {
2637: offset = m_data.elementAt(-dataIndex);
2638: }
2639:
2640: length += m_data.elementAt(-dataIndex + 1);
2641: }
2642: }
2643:
2644: identity++;
2645: } while (_parent2(identity) >= startNode);
2646:
2647: if (length > 0) {
2648: if (m_xstrf != null)
2649: return m_xstrf.newstr(m_chars, offset, length);
2650: else
2651: return new XMLStringDefault(m_chars.getString(
2652: offset, length));
2653: } else
2654: return EMPTY_XML_STR;
2655: } else
2656: return EMPTY_XML_STR;
2657: } else if (DTM.TEXT_NODE == type
2658: || DTM.CDATA_SECTION_NODE == type) {
2659: int dataIndex = m_dataOrQName.elementAt(identity);
2660: if (dataIndex >= 0) {
2661: if (m_xstrf != null)
2662: return m_xstrf.newstr(m_chars,
2663: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2664: & TEXT_LENGTH_MAX);
2665: else
2666: return new XMLStringDefault(m_chars.getString(
2667: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2668: & TEXT_LENGTH_MAX));
2669: } else {
2670: if (m_xstrf != null)
2671: return m_xstrf.newstr(m_chars, m_data
2672: .elementAt(-dataIndex), m_data
2673: .elementAt(-dataIndex + 1));
2674: else
2675: return new XMLStringDefault(m_chars.getString(
2676: m_data.elementAt(-dataIndex), m_data
2677: .elementAt(-dataIndex + 1)));
2678: }
2679: } else {
2680: int dataIndex = m_dataOrQName.elementAt(identity);
2681:
2682: if (dataIndex < 0) {
2683: dataIndex = -dataIndex;
2684: dataIndex = m_data.elementAt(dataIndex + 1);
2685: }
2686:
2687: if (m_xstrf != null)
2688: return m_xstrf.newstr((String) m_values
2689: .elementAt(dataIndex));
2690: else
2691: return new XMLStringDefault((String) m_values
2692: .elementAt(dataIndex));
2693: }
2694: }
2695:
2696: /**
2697: * The optimized version of SAX2DTM.getStringValue(int).
2698: * <p>
2699: * %OPT% This is one of the most often used interfaces. Performance is
2700: * critical here. This one is different from SAX2DTM.getStringValue(int) in
2701: * that it returns a String instead of a XMLString.
2702: *
2703: * Get the string- value of a node as a String object (see http: //www. w3.
2704: * org/TR/xpath#data- model for the definition of a node's string- value).
2705: *
2706: * @param nodeHandle The node ID.
2707: *
2708: * @return A string object that represents the string-value of the given node.
2709: */
2710: public final String getStringValueX(final int nodeHandle) {
2711: int identity = makeNodeIdentity(nodeHandle);
2712: if (identity == DTM.NULL)
2713: return EMPTY_STR;
2714:
2715: int type = _type2(identity);
2716:
2717: if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE) {
2718: int startNode = identity;
2719: identity = _firstch2(identity);
2720: if (DTM.NULL != identity) {
2721: int offset = -1;
2722: int length = 0;
2723:
2724: do {
2725: type = _exptype2(identity);
2726:
2727: if (type == DTM.TEXT_NODE
2728: || type == DTM.CDATA_SECTION_NODE) {
2729: int dataIndex = m_dataOrQName
2730: .elementAt(identity);
2731: if (dataIndex >= 0) {
2732: if (-1 == offset) {
2733: offset = dataIndex >>> TEXT_LENGTH_BITS;
2734: }
2735:
2736: length += dataIndex & TEXT_LENGTH_MAX;
2737: } else {
2738: if (-1 == offset) {
2739: offset = m_data.elementAt(-dataIndex);
2740: }
2741:
2742: length += m_data.elementAt(-dataIndex + 1);
2743: }
2744: }
2745:
2746: identity++;
2747: } while (_parent2(identity) >= startNode);
2748:
2749: if (length > 0) {
2750: return m_chars.getString(offset, length);
2751: } else
2752: return EMPTY_STR;
2753: } else
2754: return EMPTY_STR;
2755: } else if (DTM.TEXT_NODE == type
2756: || DTM.CDATA_SECTION_NODE == type) {
2757: int dataIndex = m_dataOrQName.elementAt(identity);
2758: if (dataIndex >= 0) {
2759: return m_chars.getString(
2760: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2761: & TEXT_LENGTH_MAX);
2762: } else {
2763: return m_chars.getString(m_data.elementAt(-dataIndex),
2764: m_data.elementAt(-dataIndex + 1));
2765: }
2766: } else {
2767: int dataIndex = m_dataOrQName.elementAt(identity);
2768:
2769: if (dataIndex < 0) {
2770: dataIndex = -dataIndex;
2771: dataIndex = m_data.elementAt(dataIndex + 1);
2772: }
2773:
2774: return (String) m_values.elementAt(dataIndex);
2775: }
2776: }
2777:
2778: /**
2779: * Returns the string value of the entire tree
2780: */
2781: public String getStringValue() {
2782: int child = _firstch2(ROOTNODE);
2783: if (child == DTM.NULL)
2784: return EMPTY_STR;
2785:
2786: // optimization: only create StringBuffer if > 1 child
2787: if ((_exptype2(child) == DTM.TEXT_NODE)
2788: && (_nextsib2(child) == DTM.NULL)) {
2789: int dataIndex = m_dataOrQName.elementAt(child);
2790: if (dataIndex >= 0)
2791: return m_chars.getString(
2792: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2793: & TEXT_LENGTH_MAX);
2794: else
2795: return m_chars.getString(m_data.elementAt(-dataIndex),
2796: m_data.elementAt(-dataIndex + 1));
2797: } else
2798: return getStringValueX(getDocument());
2799:
2800: }
2801:
2802: /**
2803: * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
2804: * <p>
2805: * Directly call the
2806: * characters method on the passed ContentHandler for the
2807: * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2808: * for the definition of a node's string-value). Multiple calls to the
2809: * ContentHandler's characters methods may well occur for a single call to
2810: * this method.
2811: *
2812: * @param nodeHandle The node ID.
2813: * @param ch A non-null reference to a ContentHandler.
2814: * @param normalize true if the content should be normalized according to
2815: * the rules for the XPath
2816: * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
2817: * function.
2818: *
2819: * @throws SAXException
2820: */
2821: public final void dispatchCharactersEvents(int nodeHandle,
2822: ContentHandler ch, boolean normalize) throws SAXException {
2823:
2824: int identity = makeNodeIdentity(nodeHandle);
2825:
2826: if (identity == DTM.NULL)
2827: return;
2828:
2829: int type = _type2(identity);
2830:
2831: if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE) {
2832: int startNode = identity;
2833: identity = _firstch2(identity);
2834: if (DTM.NULL != identity) {
2835: int offset = -1;
2836: int length = 0;
2837:
2838: do {
2839: type = _exptype2(identity);
2840:
2841: if (type == DTM.TEXT_NODE
2842: || type == DTM.CDATA_SECTION_NODE) {
2843: int dataIndex = m_dataOrQName
2844: .elementAt(identity);
2845:
2846: if (dataIndex >= 0) {
2847: if (-1 == offset) {
2848: offset = dataIndex >>> TEXT_LENGTH_BITS;
2849: }
2850:
2851: length += dataIndex & TEXT_LENGTH_MAX;
2852: } else {
2853: if (-1 == offset) {
2854: offset = m_data.elementAt(-dataIndex);
2855: }
2856:
2857: length += m_data.elementAt(-dataIndex + 1);
2858: }
2859: }
2860:
2861: identity++;
2862: } while (_parent2(identity) >= startNode);
2863:
2864: if (length > 0) {
2865: if (normalize)
2866: m_chars.sendNormalizedSAXcharacters(ch, offset,
2867: length);
2868: else
2869: m_chars.sendSAXcharacters(ch, offset, length);
2870: }
2871: }
2872: } else if (DTM.TEXT_NODE == type
2873: || DTM.CDATA_SECTION_NODE == type) {
2874: int dataIndex = m_dataOrQName.elementAt(identity);
2875:
2876: if (dataIndex >= 0) {
2877: if (normalize)
2878: m_chars.sendNormalizedSAXcharacters(ch,
2879: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2880: & TEXT_LENGTH_MAX);
2881: else
2882: m_chars.sendSAXcharacters(ch,
2883: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2884: & TEXT_LENGTH_MAX);
2885: } else {
2886: if (normalize)
2887: m_chars.sendNormalizedSAXcharacters(ch, m_data
2888: .elementAt(-dataIndex), m_data
2889: .elementAt(-dataIndex + 1));
2890: else
2891: m_chars.sendSAXcharacters(ch, m_data
2892: .elementAt(-dataIndex), m_data
2893: .elementAt(-dataIndex + 1));
2894: }
2895: } else {
2896: int dataIndex = m_dataOrQName.elementAt(identity);
2897:
2898: if (dataIndex < 0) {
2899: dataIndex = -dataIndex;
2900: dataIndex = m_data.elementAt(dataIndex + 1);
2901: }
2902:
2903: String str = (String) m_values.elementAt(dataIndex);
2904:
2905: if (normalize)
2906: FastStringBuffer.sendNormalizedSAXcharacters(str
2907: .toCharArray(), 0, str.length(), ch);
2908: else
2909: ch.characters(str.toCharArray(), 0, str.length());
2910: }
2911: }
2912:
2913: /**
2914: * Given a node handle, return its node value. This is mostly
2915: * as defined by the DOM, but may ignore some conveniences.
2916: * <p>
2917: *
2918: * @param nodeHandle The node id.
2919: * @return String Value of this node, or null if not
2920: * meaningful for this node type.
2921: */
2922: public String getNodeValue(int nodeHandle) {
2923:
2924: int identity = makeNodeIdentity(nodeHandle);
2925: int type = _type2(identity);
2926:
2927: if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE) {
2928: int dataIndex = _dataOrQName(identity);
2929: if (dataIndex > 0) {
2930: return m_chars.getString(
2931: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2932: & TEXT_LENGTH_MAX);
2933: } else {
2934: return m_chars.getString(m_data.elementAt(-dataIndex),
2935: m_data.elementAt(-dataIndex + 1));
2936: }
2937: } else if (DTM.ELEMENT_NODE == type
2938: || DTM.DOCUMENT_FRAGMENT_NODE == type
2939: || DTM.DOCUMENT_NODE == type) {
2940: return null;
2941: } else {
2942: int dataIndex = m_dataOrQName.elementAt(identity);
2943:
2944: if (dataIndex < 0) {
2945: dataIndex = -dataIndex;
2946: dataIndex = m_data.elementAt(dataIndex + 1);
2947: }
2948:
2949: return (String) m_values.elementAt(dataIndex);
2950: }
2951: }
2952:
2953: /**
2954: * Copy the String value of a Text node to a SerializationHandler
2955: */
2956: protected final void copyTextNode(final int nodeID,
2957: SerializationHandler handler) throws SAXException {
2958: if (nodeID != DTM.NULL) {
2959: int dataIndex = m_dataOrQName.elementAt(nodeID);
2960: if (dataIndex >= 0) {
2961: m_chars.sendSAXcharacters(handler,
2962: dataIndex >>> TEXT_LENGTH_BITS, dataIndex
2963: & TEXT_LENGTH_MAX);
2964: } else {
2965: m_chars.sendSAXcharacters(handler, m_data
2966: .elementAt(-dataIndex), m_data
2967: .elementAt(-dataIndex + 1));
2968: }
2969: }
2970: }
2971:
2972: /**
2973: * Copy an Element node to a SerializationHandler.
2974: *
2975: * @param nodeID The node identity
2976: * @param exptype The expanded type of the Element node
2977: * @param handler The SerializationHandler
2978: * @return The qualified name of the Element node.
2979: */
2980: protected final String copyElement(int nodeID, int exptype,
2981: SerializationHandler handler) throws SAXException {
2982: final ExtendedType extType = m_extendedTypes[exptype];
2983: String uri = extType.getNamespace();
2984: String name = extType.getLocalName();
2985:
2986: if (uri.length() == 0) {
2987: handler.startElement(name);
2988: return name;
2989: } else {
2990: int qnameIndex = m_dataOrQName.elementAt(nodeID);
2991:
2992: if (qnameIndex == 0) {
2993: handler.startElement(name);
2994: handler.namespaceAfterStartElement(EMPTY_STR, uri);
2995: return name;
2996: }
2997:
2998: if (qnameIndex < 0) {
2999: qnameIndex = -qnameIndex;
3000: qnameIndex = m_data.elementAt(qnameIndex);
3001: }
3002:
3003: String qName = m_valuesOrPrefixes.indexToString(qnameIndex);
3004: handler.startElement(qName);
3005: int prefixIndex = qName.indexOf(':');
3006: String prefix;
3007: if (prefixIndex > 0) {
3008: prefix = qName.substring(0, prefixIndex);
3009: } else {
3010: prefix = null;
3011: }
3012: handler.namespaceAfterStartElement(prefix, uri);
3013: return qName;
3014: }
3015:
3016: }
3017:
3018: /**
3019: * Copy namespace nodes.
3020: *
3021: * @param nodeID The Element node identity
3022: * @param handler The SerializationHandler
3023: * @param inScope true if all namespaces in scope should be copied,
3024: * false if only the namespace declarations should be copied.
3025: */
3026: protected final void copyNS(final int nodeID,
3027: SerializationHandler handler, boolean inScope)
3028: throws SAXException {
3029: // %OPT% Optimization for documents which does not have any explicit
3030: // namespace nodes. For these documents, there is an implicit
3031: // namespace node (xmlns:xml="http://www.w3.org/XML/1998/namespace")
3032: // declared on the root element node. In this case, there is no
3033: // need to do namespace copying. We can safely return without
3034: // doing anything.
3035: if (m_namespaceDeclSetElements != null
3036: && m_namespaceDeclSetElements.size() == 1
3037: && m_namespaceDeclSets != null
3038: && ((SuballocatedIntVector) m_namespaceDeclSets
3039: .elementAt(0)).size() == 1)
3040: return;
3041:
3042: SuballocatedIntVector nsContext = null;
3043: int nextNSNode;
3044:
3045: // Find the first namespace node
3046: if (inScope) {
3047: nsContext = findNamespaceContext(nodeID);
3048: if (nsContext == null || nsContext.size() < 1)
3049: return;
3050: else
3051: nextNSNode = makeNodeIdentity(nsContext.elementAt(0));
3052: } else
3053: nextNSNode = getNextNamespaceNode2(nodeID);
3054:
3055: int nsIndex = 1;
3056: while (nextNSNode != DTM.NULL) {
3057: // Retrieve the name of the namespace node
3058: int eType = _exptype2(nextNSNode);
3059: String nodeName = m_extendedTypes[eType].getLocalName();
3060:
3061: // Retrieve the node value of the namespace node
3062: int dataIndex = m_dataOrQName.elementAt(nextNSNode);
3063:
3064: if (dataIndex < 0) {
3065: dataIndex = -dataIndex;
3066: dataIndex = m_data.elementAt(dataIndex + 1);
3067: }
3068:
3069: String nodeValue = (String) m_values.elementAt(dataIndex);
3070:
3071: handler.namespaceAfterStartElement(nodeName, nodeValue);
3072:
3073: if (inScope) {
3074: if (nsIndex < nsContext.size()) {
3075: nextNSNode = makeNodeIdentity(nsContext
3076: .elementAt(nsIndex));
3077: nsIndex++;
3078: } else
3079: return;
3080: } else
3081: nextNSNode = getNextNamespaceNode2(nextNSNode);
3082: }
3083: }
3084:
3085: /**
3086: * Return the next namespace node following the given base node.
3087: *
3088: * @baseID The node identity of the base node, which can be an
3089: * element, attribute or namespace node.
3090: * @return The namespace node immediately following the base node.
3091: */
3092: protected final int getNextNamespaceNode2(int baseID) {
3093: int type;
3094: while ((type = _type2(++baseID)) == DTM.ATTRIBUTE_NODE)
3095: ;
3096:
3097: if (type == DTM.NAMESPACE_NODE)
3098: return baseID;
3099: else
3100: return NULL;
3101: }
3102:
3103: /**
3104: * Copy attribute nodes from an element .
3105: *
3106: * @param nodeID The Element node identity
3107: * @param handler The SerializationHandler
3108: */
3109: protected final void copyAttributes(final int nodeID,
3110: SerializationHandler handler) throws SAXException {
3111:
3112: for (int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)) {
3113: int eType = _exptype2(current);
3114: copyAttribute(current, eType, handler);
3115: }
3116: }
3117:
3118: /**
3119: * Copy an Attribute node to a SerializationHandler
3120: *
3121: * @param nodeID The node identity
3122: * @param exptype The expanded type of the Element node
3123: * @param handler The SerializationHandler
3124: */
3125: protected final void copyAttribute(int nodeID, int exptype,
3126: SerializationHandler handler) throws SAXException {
3127: /*
3128: final String uri = getNamespaceName(node);
3129: if (uri.length() != 0) {
3130: final String prefix = getPrefix(node);
3131: handler.namespaceAfterStartElement(prefix, uri);
3132: }
3133: handler.addAttribute(getNodeName(node), getNodeValue(node));
3134: */
3135: final ExtendedType extType = m_extendedTypes[exptype];
3136: final String uri = extType.getNamespace();
3137: final String localName = extType.getLocalName();
3138:
3139: String prefix = null;
3140: String qname = null;
3141: int dataIndex = _dataOrQName(nodeID);
3142: int valueIndex = dataIndex;
3143: if (dataIndex <= 0) {
3144: int prefixIndex = m_data.elementAt(-dataIndex);
3145: valueIndex = m_data.elementAt(-dataIndex + 1);
3146: qname = m_valuesOrPrefixes.indexToString(prefixIndex);
3147: int colonIndex = qname.indexOf(':');
3148: if (colonIndex > 0) {
3149: prefix = qname.substring(0, colonIndex);
3150: }
3151: }
3152: if (uri.length() != 0) {
3153: handler.namespaceAfterStartElement(prefix, uri);
3154: }
3155:
3156: String nodeName = (prefix != null) ? qname : localName;
3157: String nodeValue = (String) m_values.elementAt(valueIndex);
3158:
3159: handler.addAttribute(nodeName, nodeValue);
3160: }
3161:
3162: }
|