/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: SAX2DTM2.java 468653 2006-10-28 07:07:05Z minchau $
*/
package org.apache.xml.dtm.ref.sax2dtm;
import org.apache.xml.dtm.*;
import org.apache.xml.dtm.ref.*;
import org.apache.xml.utils.FastStringBuffer;
import org.apache.xml.utils.XMLString;
import org.apache.xml.utils.XMLStringDefault;
import org.apache.xml.utils.XMLStringFactory;
import org.apache.xml.res.XMLMessages;
import org.apache.xml.res.XMLErrorResources;
import org.apache.xml.serializer.SerializationHandler;
import javax.xml.transform.Source;
import java.util.Vector;
import org.apache.xml.utils.SuballocatedIntVector;
import org.xml.sax.*;
SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
are also overridden in SAX2DTM2 for performance reasons.
Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
SuballocatedIntVectors.
The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
SAX2DTM model, please extend from SAX2DTM instead of this class.
TODO: This class is currently only used by XSLTC. We need to investigate the possibility
of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
%MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
when making changes here!
/**
* SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
* It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
* and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
* access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
* are also overridden in SAX2DTM2 for performance reasons.
* <p>
* Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
* efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
* use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
* a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
* SuballocatedIntVectors.
* <p>
* The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
* SAX2DTM model, please extend from SAX2DTM instead of this class.
* <p>
* TODO: This class is currently only used by XSLTC. We need to investigate the possibility
* of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
* boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
* <p>
* %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
* when making changes here!
*/
public class SAX2DTM2 extends SAX2DTM
{
/****************************************************************
* Optimized version of the nested iterators
****************************************************************/
Iterator that returns all immediate children of a given node
/**
* Iterator that returns all immediate children of a given node
*/
public final class ChildrenIterator extends InternalAxisIteratorBase
{
Setting start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
If the iterator is not restartable, this has no effect.
%REVIEW% Should it return/throw something in that case,
or set current node to END, to indicate request-not-honored?
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Setting start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
* <p>
* If the iterator is not restartable, this has no effect.
* %REVIEW% Should it return/throw something in that case,
* or set current node to END, to indicate request-not-honored?
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
_currentNode = (node == DTM.NULL) ? DTM.NULL
: _firstch2(makeNodeIdentity(node));
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END if no more
are available.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END if no more
* are available.
*/
public int next()
{
if (_currentNode != NULL) {
int node = _currentNode;
_currentNode = _nextsib2(node);
return returnNode(makeNodeHandle(node));
}
return END;
}
} // end of ChildrenIterator
Iterator that returns the parent of a given node. Note that
this delivers only a single node; if you want all the ancestors,
see AncestorIterator.
/**
* Iterator that returns the parent of a given node. Note that
* this delivers only a single node; if you want all the ancestors,
* see AncestorIterator.
*/
public final class ParentIterator extends InternalAxisIteratorBase
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private int _nodeType = DTM.NULL;
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
if (node != DTM.NULL)
_currentNode = _parent2(makeNodeIdentity(node));
else
_currentNode = DTM.NULL;
return resetPosition();
}
return this;
}
Set the node type of the parent that we're looking for.
Note that this does _not_ mean "find the nearest ancestor of
this type", but "yield the parent if it is of this type".
Params: - type – extended type ID.
Returns: ParentIterator configured with the type filter set.
/**
* Set the node type of the parent that we're looking for.
* Note that this does _not_ mean "find the nearest ancestor of
* this type", but "yield the parent if it is of this type".
*
*
* @param type extended type ID.
*
* @return ParentIterator configured with the type filter set.
*/
public DTMAxisIterator setNodeType(final int type)
{
_nodeType = type;
return this;
}
Get the next node in the iteration. In this case, we return
only the immediate parent, _if_ it matches the requested nodeType.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration. In this case, we return
* only the immediate parent, _if_ it matches the requested nodeType.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int result = _currentNode;
if (result == END)
return DTM.NULL;
// %OPT% The most common case is handled first.
if (_nodeType == NULL) {
_currentNode = END;
return returnNode(makeNodeHandle(result));
}
else if (_nodeType >= DTM.NTYPES) {
if (_nodeType == _exptype2(result)) {
_currentNode = END;
return returnNode(makeNodeHandle(result));
}
}
else {
if (_nodeType == _type2(result)) {
_currentNode = END;
return returnNode(makeNodeHandle(result));
}
}
return DTM.NULL;
}
} // end of ParentIterator
Iterator that returns children of a given type for a given node.
The functionality chould be achieved by putting a filter on top
of a basic child iterator, but a specialised iterator is used
for efficiency (both speed and size of translet).
/**
* Iterator that returns children of a given type for a given node.
* The functionality chould be achieved by putting a filter on top
* of a basic child iterator, but a specialised iterator is used
* for efficiency (both speed and size of translet).
*/
public final class TypedChildrenIterator extends InternalAxisIteratorBase
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedChildrenIterator
Params: - nodeType – The extended type ID being requested.
/**
* Constructor TypedChildrenIterator
*
*
* @param nodeType The extended type ID being requested.
*/
public TypedChildrenIterator(int nodeType)
{
_nodeType = nodeType;
}
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
_currentNode = (node == DTM.NULL)
? DTM.NULL
: _firstch2(makeNodeIdentity(_startNode));
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int node = _currentNode;
if (node == DTM.NULL)
return DTM.NULL;
final int nodeType = _nodeType;
if (nodeType != DTM.ELEMENT_NODE) {
while (node != DTM.NULL && _exptype2(node) != nodeType) {
node = _nextsib2(node);
}
}
// %OPT% If the nodeType is element (matching child::*), we only
// need to compare the expType with DTM.NTYPES. A child node of
// an element can be either an element, text, comment or
// processing instruction node. Only element node has an extended
// type greater than or equal to DTM.NTYPES.
else {
int eType;
while (node != DTM.NULL) {
eType = _exptype2(node);
if (eType >= DTM.NTYPES)
break;
else
node = _nextsib2(node);
}
}
if (node == DTM.NULL) {
_currentNode = DTM.NULL;
return DTM.NULL;
} else {
_currentNode = _nextsib2(node);
return returnNode(makeNodeHandle(node));
}
}
Return the node at the given position.
/**
* Return the node at the given position.
*/
public int getNodeByPosition(int position)
{
if (position <= 0)
return DTM.NULL;
int node = _currentNode;
int pos = 0;
final int nodeType = _nodeType;
if (nodeType != DTM.ELEMENT_NODE) {
while (node != DTM.NULL) {
if (_exptype2(node) == nodeType) {
pos++;
if (pos == position)
return makeNodeHandle(node);
}
node = _nextsib2(node);
}
return NULL;
}
else {
while (node != DTM.NULL) {
if (_exptype2(node) >= DTM.NTYPES) {
pos++;
if (pos == position)
return makeNodeHandle(node);
}
node = _nextsib2(node);
}
return NULL;
}
}
} // end of TypedChildrenIterator
Iterator that returns the namespace nodes as defined by the XPath data model
for a given node, filtered by extended type ID.
/**
* Iterator that returns the namespace nodes as defined by the XPath data model
* for a given node, filtered by extended type ID.
*/
public class TypedRootIterator extends RootIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedRootIterator
Params: - nodeType – The extended type ID being requested.
/**
* Constructor TypedRootIterator
*
* @param nodeType The extended type ID being requested.
*/
public TypedRootIterator(int nodeType)
{
super();
_nodeType = nodeType;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
if(_startNode == _currentNode)
return NULL;
final int node = _startNode;
int expType = _exptype2(makeNodeIdentity(node));
_currentNode = node;
if (_nodeType >= DTM.NTYPES) {
if (_nodeType == expType) {
return returnNode(node);
}
}
else {
if (expType < DTM.NTYPES) {
if (expType == _nodeType) {
return returnNode(node);
}
}
else {
if (m_extendedTypes[expType].getNodeType() == _nodeType) {
return returnNode(node);
}
}
}
return NULL;
}
} // end of TypedRootIterator
Iterator that returns all siblings of a given node.
/**
* Iterator that returns all siblings of a given node.
*/
public class FollowingSiblingIterator extends InternalAxisIteratorBase
{
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
_currentNode = makeNodeIdentity(node);
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
_currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
: _nextsib2(_currentNode);
return returnNode(makeNodeHandle(_currentNode));
}
} // end of FollowingSiblingIterator
Iterator that returns all following siblings of a given node.
/**
* Iterator that returns all following siblings of a given node.
*/
public final class TypedFollowingSiblingIterator
extends FollowingSiblingIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedFollowingSiblingIterator
Params: - type – The extended type ID being requested.
/**
* Constructor TypedFollowingSiblingIterator
*
*
* @param type The extended type ID being requested.
*/
public TypedFollowingSiblingIterator(int type)
{
_nodeType = type;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
if (_currentNode == DTM.NULL) {
return DTM.NULL;
}
int node = _currentNode;
final int nodeType = _nodeType;
if (nodeType != DTM.ELEMENT_NODE) {
while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {}
}
else {
while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {}
}
_currentNode = node;
return (node == DTM.NULL)
? DTM.NULL
: returnNode(makeNodeHandle(node));
}
} // end of TypedFollowingSiblingIterator
Iterator that returns attribute nodes (of what nodes?)
/**
* Iterator that returns attribute nodes (of what nodes?)
*/
public final class AttributeIterator extends InternalAxisIteratorBase
{
// assumes caller will pass element nodes
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
_currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
final int node = _currentNode;
if (node != NULL) {
_currentNode = getNextAttributeIdentity(node);
return returnNode(makeNodeHandle(node));
}
return NULL;
}
} // end of AttributeIterator
Iterator that returns attribute nodes of a given type
/**
* Iterator that returns attribute nodes of a given type
*/
public final class TypedAttributeIterator extends InternalAxisIteratorBase
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedAttributeIterator
Params: - nodeType – The extended type ID that is requested.
/**
* Constructor TypedAttributeIterator
*
*
* @param nodeType The extended type ID that is requested.
*/
public TypedAttributeIterator(int nodeType)
{
_nodeType = nodeType;
}
// assumes caller will pass element nodes
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
if (_isRestartable)
{
_startNode = node;
_currentNode = getTypedAttribute(node, _nodeType);
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
final int node = _currentNode;
// singleton iterator, since there can only be one attribute of
// a given type.
_currentNode = NULL;
return returnNode(node);
}
} // end of TypedAttributeIterator
Iterator that returns preceding siblings of a given node
/**
* Iterator that returns preceding siblings of a given node
*/
public class PrecedingSiblingIterator extends InternalAxisIteratorBase
{
The node identity of _startNode for this iterator
/**
* The node identity of _startNode for this iterator
*/
protected int _startNodeID;
True if this iterator has a reversed axis.
Returns: true.
/**
* True if this iterator has a reversed axis.
*
* @return true.
*/
public boolean isReverse()
{
return true;
}
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
node = _startNodeID = makeNodeIdentity(node);
if(node == NULL)
{
_currentNode = node;
return resetPosition();
}
int type = _type2(node);
if(ExpandedNameTable.ATTRIBUTE == type
|| ExpandedNameTable.NAMESPACE == type )
{
_currentNode = node;
}
else
{
// Be careful to handle the Document node properly
_currentNode = _parent2(node);
if(NULL!=_currentNode)
_currentNode = _firstch2(_currentNode);
else
_currentNode = node;
}
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
if (_currentNode == _startNodeID || _currentNode == DTM.NULL)
{
return NULL;
}
else
{
final int node = _currentNode;
_currentNode = _nextsib2(node);
return returnNode(makeNodeHandle(node));
}
}
} // end of PrecedingSiblingIterator
Iterator that returns preceding siblings of a given type for
a given node
/**
* Iterator that returns preceding siblings of a given type for
* a given node
*/
public final class TypedPrecedingSiblingIterator
extends PrecedingSiblingIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedPrecedingSiblingIterator
Params: - type – The extended type ID being requested.
/**
* Constructor TypedPrecedingSiblingIterator
*
*
* @param type The extended type ID being requested.
*/
public TypedPrecedingSiblingIterator(int type)
{
_nodeType = type;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int node = _currentNode;
final int nodeType = _nodeType;
final int startNodeID = _startNodeID;
if (nodeType != DTM.ELEMENT_NODE) {
while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) {
node = _nextsib2(node);
}
}
else {
while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) {
node = _nextsib2(node);
}
}
if (node == DTM.NULL || node == startNodeID) {
_currentNode = NULL;
return NULL;
}
else {
_currentNode = _nextsib2(node);
return returnNode(makeNodeHandle(node));
}
}
Return the index of the last node in this iterator.
/**
* Return the index of the last node in this iterator.
*/
public int getLast()
{
if (_last != -1)
return _last;
setMark();
int node = _currentNode;
final int nodeType = _nodeType;
final int startNodeID = _startNodeID;
int last = 0;
if (nodeType != DTM.ELEMENT_NODE) {
while (node != NULL && node != startNodeID) {
if (_exptype2(node) == nodeType) {
last++;
}
node = _nextsib2(node);
}
}
else {
while (node != NULL && node != startNodeID) {
if (_exptype2(node) >= DTM.NTYPES) {
last++;
}
node = _nextsib2(node);
}
}
gotoMark();
return (_last = last);
}
} // end of TypedPrecedingSiblingIterator
Iterator that returns preceding nodes of a given node.
This includes the node set {root+1, start-1}, but excludes
all ancestors, attributes, and namespace nodes.
/**
* Iterator that returns preceding nodes of a given node.
* This includes the node set {root+1, start-1}, but excludes
* all ancestors, attributes, and namespace nodes.
*/
public class PrecedingIterator extends InternalAxisIteratorBase
{
The max ancestors, but it can grow... /** The max ancestors, but it can grow... */
private final int _maxAncestors = 8;
The stack of start node + ancestors up to the root of the tree,
which we must avoid.
/**
* The stack of start node + ancestors up to the root of the tree,
* which we must avoid.
*/
protected int[] _stack = new int[_maxAncestors];
(not sure yet... -sb) /** (not sure yet... -sb) */
protected int _sp, _oldsp;
protected int _markedsp, _markedNode, _markedDescendant;
/* _currentNode precedes candidates. This is the identity, not the handle! */
True if this iterator has a reversed axis.
Returns: true since this iterator is a reversed axis.
/**
* True if this iterator has a reversed axis.
*
* @return true since this iterator is a reversed axis.
*/
public boolean isReverse()
{
return true;
}
Returns a deep copy of this iterator. The cloned iterator is not reset.
Returns: a deep copy of this iterator.
/**
* Returns a deep copy of this iterator. The cloned iterator is not reset.
*
* @return a deep copy of this iterator.
*/
public DTMAxisIterator cloneIterator()
{
_isRestartable = false;
try
{
final PrecedingIterator clone = (PrecedingIterator) super.clone();
final int[] stackCopy = new int[_stack.length];
System.arraycopy(_stack, 0, stackCopy, 0, _stack.length);
clone._stack = stackCopy;
// return clone.reset();
return clone;
}
catch (CloneNotSupportedException e)
{
throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
}
}
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
node = makeNodeIdentity(node);
// iterator is not a clone
int parent, index;
if (_type2(node) == DTM.ATTRIBUTE_NODE)
node = _parent2(node);
_startNode = node;
_stack[index = 0] = node;
parent=node;
while ((parent = _parent2(parent)) != NULL)
{
if (++index == _stack.length)
{
final int[] stack = new int[index*2];
System.arraycopy(_stack, 0, stack, 0, index);
_stack = stack;
}
_stack[index] = parent;
}
if(index>0)
--index; // Pop actual root node (if not start) back off the stack
_currentNode=_stack[index]; // Last parent before root node
_oldsp = _sp = index;
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
// Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
// Also recoded the loop controls for clarity and to flatten out
// the tail-recursion.
for(++_currentNode; _sp>=0; ++_currentNode)
{
if(_currentNode < _stack[_sp])
{
int type = _type2(_currentNode);
if(type != ATTRIBUTE_NODE && type != NAMESPACE_NODE)
return returnNode(makeNodeHandle(_currentNode));
}
else
--_sp;
}
return NULL;
}
// redefine DTMAxisIteratorBase's reset
Resets the iterator to the last start node.
Returns: A DTMAxisIterator, which may or may not be the same as this
iterator.
/**
* Resets the iterator to the last start node.
*
* @return A DTMAxisIterator, which may or may not be the same as this
* iterator.
*/
public DTMAxisIterator reset()
{
_sp = _oldsp;
return resetPosition();
}
public void setMark() {
_markedsp = _sp;
_markedNode = _currentNode;
_markedDescendant = _stack[0];
}
public void gotoMark() {
_sp = _markedsp;
_currentNode = _markedNode;
}
} // end of PrecedingIterator
Iterator that returns preceding nodes of agiven type for a
given node. This includes the node set {root+1, start-1}, but
excludes all ancestors.
/**
* Iterator that returns preceding nodes of agiven type for a
* given node. This includes the node set {root+1, start-1}, but
* excludes all ancestors.
*/
public final class TypedPrecedingIterator extends PrecedingIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedPrecedingIterator
Params: - type – The extended type ID being requested.
/**
* Constructor TypedPrecedingIterator
*
*
* @param type The extended type ID being requested.
*/
public TypedPrecedingIterator(int type)
{
_nodeType = type;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int node = _currentNode;
final int nodeType = _nodeType;
if (nodeType >= DTM.NTYPES) {
while (true) {
node++;
if (_sp < 0) {
node = NULL;
break;
}
else if (node >= _stack[_sp]) {
if (--_sp < 0) {
node = NULL;
break;
}
}
else if (_exptype2(node) == nodeType) {
break;
}
}
}
else {
int expType;
while (true) {
node++;
if (_sp < 0) {
node = NULL;
break;
}
else if (node >= _stack[_sp]) {
if (--_sp < 0) {
node = NULL;
break;
}
}
else {
expType = _exptype2(node);
if (expType < DTM.NTYPES) {
if (expType == nodeType) {
break;
}
}
else {
if (m_extendedTypes[expType].getNodeType() == nodeType) {
break;
}
}
}
}
}
_currentNode = node;
return (node == NULL) ? NULL : returnNode(makeNodeHandle(node));
}
} // end of TypedPrecedingIterator
Iterator that returns following nodes of for a given node.
/**
* Iterator that returns following nodes of for a given node.
*/
public class FollowingIterator extends InternalAxisIteratorBase
{
//DTMAxisTraverser m_traverser; // easier for now
public FollowingIterator()
{
//m_traverser = getAxisTraverser(Axis.FOLLOWING);
}
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
_startNode = node;
//_currentNode = m_traverser.first(node);
node = makeNodeIdentity(node);
int first;
int type = _type2(node);
if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
{
node = _parent2(node);
first = _firstch2(node);
if (NULL != first) {
_currentNode = makeNodeHandle(first);
return resetPosition();
}
}
do
{
first = _nextsib2(node);
if (NULL == first)
node = _parent2(node);
}
while (NULL == first && NULL != node);
_currentNode = makeNodeHandle(first);
// _currentNode precedes possible following(node) nodes
return resetPosition();
}
return this;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int node = _currentNode;
//_currentNode = m_traverser.next(_startNode, _currentNode);
int current = makeNodeIdentity(node);
while (true)
{
current++;
int type = _type2(current);
if (NULL == type) {
_currentNode = NULL;
return returnNode(node);
}
if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
continue;
_currentNode = makeNodeHandle(current);
return returnNode(node);
}
}
} // end of FollowingIterator
Iterator that returns following nodes of a given type for a given node.
/**
* Iterator that returns following nodes of a given type for a given node.
*/
public final class TypedFollowingIterator extends FollowingIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedFollowingIterator
Params: - type – The extended type ID being requested.
/**
* Constructor TypedFollowingIterator
*
*
* @param type The extended type ID being requested.
*/
public TypedFollowingIterator(int type)
{
_nodeType = type;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int current;
int node;
int type;
final int nodeType = _nodeType;
int currentNodeID = makeNodeIdentity(_currentNode);
if (nodeType >= DTM.NTYPES) {
do {
node = currentNodeID;
current = node;
do {
current++;
type = _type2(current);
}
while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
currentNodeID = (type != NULL) ? current : NULL;
}
while (node != DTM.NULL && _exptype2(node) != nodeType);
}
else {
do {
node = currentNodeID;
current = node;
do {
current++;
type = _type2(current);
}
while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
currentNodeID = (type != NULL) ? current : NULL;
}
while (node != DTM.NULL
&& (_exptype2(node) != nodeType && _type2(node) != nodeType));
}
_currentNode = makeNodeHandle(currentNodeID);
return (node == DTM.NULL ? DTM.NULL :returnNode(makeNodeHandle(node)));
}
} // end of TypedFollowingIterator
Iterator that returns the ancestors of a given node in document
order. (NOTE! This was changed from the XSLTC code!)
/**
* Iterator that returns the ancestors of a given node in document
* order. (NOTE! This was changed from the XSLTC code!)
*/
public class AncestorIterator extends InternalAxisIteratorBase
{
// The initial size of the ancestor array
private static final int m_blocksize = 32;
// The array for ancestor nodes. This array will grow dynamically.
int[] m_ancestors = new int[m_blocksize];
// Number of ancestor nodes in the array
int m_size = 0;
int m_ancestorsPos;
int m_markedPos;
The real start node for this axes, since _startNode will be adjusted. /** The real start node for this axes, since _startNode will be adjusted. */
int m_realStartNode;
Get start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Returns: The root node of the iteration.
/**
* Get start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @return The root node of the iteration.
*/
public int getStartNode()
{
return m_realStartNode;
}
True if this iterator has a reversed axis.
Returns: true since this iterator is a reversed axis.
/**
* True if this iterator has a reversed axis.
*
* @return true since this iterator is a reversed axis.
*/
public final boolean isReverse()
{
return true;
}
Returns a deep copy of this iterator. The cloned iterator is not reset.
Returns: a deep copy of this iterator.
/**
* Returns a deep copy of this iterator. The cloned iterator is not reset.
*
* @return a deep copy of this iterator.
*/
public DTMAxisIterator cloneIterator()
{
_isRestartable = false; // must set to false for any clone
try
{
final AncestorIterator clone = (AncestorIterator) super.clone();
clone._startNode = _startNode;
// return clone.reset();
return clone;
}
catch (CloneNotSupportedException e)
{
throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
}
}
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
m_realStartNode = node;
if (_isRestartable)
{
int nodeID = makeNodeIdentity(node);
m_size = 0;
if (nodeID == DTM.NULL) {
_currentNode = DTM.NULL;
m_ancestorsPos = 0;
return this;
}
// Start from the current node's parent if
// _includeSelf is false.
if (!_includeSelf) {
nodeID = _parent2(nodeID);
node = makeNodeHandle(nodeID);
}
_startNode = node;
while (nodeID != END) {
//m_ancestors.addElement(node);
if (m_size >= m_ancestors.length)
{
int[] newAncestors = new int[m_size * 2];
System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
m_ancestors = newAncestors;
}
m_ancestors[m_size++] = node;
nodeID = _parent2(nodeID);
node = makeNodeHandle(nodeID);
}
m_ancestorsPos = m_size - 1;
_currentNode = (m_ancestorsPos>=0)
? m_ancestors[m_ancestorsPos]
: DTM.NULL;
return resetPosition();
}
return this;
}
Resets the iterator to the last start node.
Returns: A DTMAxisIterator, which may or may not be the same as this
iterator.
/**
* Resets the iterator to the last start node.
*
* @return A DTMAxisIterator, which may or may not be the same as this
* iterator.
*/
public DTMAxisIterator reset()
{
m_ancestorsPos = m_size - 1;
_currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
: DTM.NULL;
return resetPosition();
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
int next = _currentNode;
int pos = --m_ancestorsPos;
_currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
: DTM.NULL;
return returnNode(next);
}
public void setMark() {
m_markedPos = m_ancestorsPos;
}
public void gotoMark() {
m_ancestorsPos = m_markedPos;
_currentNode = m_ancestorsPos>=0 ? m_ancestors[m_ancestorsPos]
: DTM.NULL;
}
} // end of AncestorIterator
Typed iterator that returns the ancestors of a given node.
/**
* Typed iterator that returns the ancestors of a given node.
*/
public final class TypedAncestorIterator extends AncestorIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedAncestorIterator
Params: - type – The extended type ID being requested.
/**
* Constructor TypedAncestorIterator
*
*
* @param type The extended type ID being requested.
*/
public TypedAncestorIterator(int type)
{
_nodeType = type;
}
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
m_realStartNode = node;
if (_isRestartable)
{
int nodeID = makeNodeIdentity(node);
m_size = 0;
if (nodeID == DTM.NULL) {
_currentNode = DTM.NULL;
m_ancestorsPos = 0;
return this;
}
final int nodeType = _nodeType;
if (!_includeSelf) {
nodeID = _parent2(nodeID);
node = makeNodeHandle(nodeID);
}
_startNode = node;
if (nodeType >= DTM.NTYPES) {
while (nodeID != END) {
int eType = _exptype2(nodeID);
if (eType == nodeType) {
if (m_size >= m_ancestors.length)
{
int[] newAncestors = new int[m_size * 2];
System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
m_ancestors = newAncestors;
}
m_ancestors[m_size++] = makeNodeHandle(nodeID);
}
nodeID = _parent2(nodeID);
}
}
else {
while (nodeID != END) {
int eType = _exptype2(nodeID);
if ((eType < DTM.NTYPES && eType == nodeType)
|| (eType >= DTM.NTYPES
&& m_extendedTypes[eType].getNodeType() == nodeType)) {
if (m_size >= m_ancestors.length)
{
int[] newAncestors = new int[m_size * 2];
System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
m_ancestors = newAncestors;
}
m_ancestors[m_size++] = makeNodeHandle(nodeID);
}
nodeID = _parent2(nodeID);
}
}
m_ancestorsPos = m_size - 1;
_currentNode = (m_ancestorsPos>=0)
? m_ancestors[m_ancestorsPos]
: DTM.NULL;
return resetPosition();
}
return this;
}
Return the node at the given position.
/**
* Return the node at the given position.
*/
public int getNodeByPosition(int position)
{
if (position > 0 && position <= m_size) {
return m_ancestors[position-1];
}
else
return DTM.NULL;
}
Returns the position of the last node within the iteration, as
defined by XPath.
/**
* Returns the position of the last node within the iteration, as
* defined by XPath.
*/
public int getLast() {
return m_size;
}
} // end of TypedAncestorIterator
Iterator that returns the descendants of a given node.
/**
* Iterator that returns the descendants of a given node.
*/
public class DescendantIterator extends InternalAxisIteratorBase
{
Set start to END should 'close' the iterator,
i.e. subsequent call to next() should return END.
Params: - node – Sets the root of the iteration.
Returns: A DTMAxisIterator set to the start of the iteration.
/**
* Set start to END should 'close' the iterator,
* i.e. subsequent call to next() should return END.
*
* @param node Sets the root of the iteration.
*
* @return A DTMAxisIterator set to the start of the iteration.
*/
public DTMAxisIterator setStartNode(int node)
{
//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
if (node == DTMDefaultBase.ROOTNODE)
node = getDocument();
if (_isRestartable)
{
node = makeNodeIdentity(node);
_startNode = node;
if (_includeSelf)
node--;
_currentNode = node;
return resetPosition();
}
return this;
}
Tell if this node identity is a descendant. Assumes that
the node info for the element has already been obtained.
This one-sided test works only if the parent has been
previously tested and is known to be a descendent. It fails if
the parent is the _startNode's next sibling, or indeed any node
that follows _startNode in document order. That may suffice
for this iterator, but it's not really an isDescendent() test.
%REVIEW% rename?
Params: - identity – The index number of the node in question.
Returns: true if the index is a descendant of _startNode.
/**
* Tell if this node identity is a descendant. Assumes that
* the node info for the element has already been obtained.
*
* This one-sided test works only if the parent has been
* previously tested and is known to be a descendent. It fails if
* the parent is the _startNode's next sibling, or indeed any node
* that follows _startNode in document order. That may suffice
* for this iterator, but it's not really an isDescendent() test.
* %REVIEW% rename?
*
* @param identity The index number of the node in question.
* @return true if the index is a descendant of _startNode.
*/
protected final boolean isDescendant(int identity)
{
return (_parent2(identity) >= _startNode) || (_startNode == identity);
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
final int startNode = _startNode;
if (startNode == NULL) {
return NULL;
}
if (_includeSelf && (_currentNode + 1) == startNode)
return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
int node = _currentNode;
int type;
// %OPT% If the startNode is the root node, do not need
// to do the isDescendant() check.
if (startNode == ROOTNODE) {
int eType;
do {
node++;
eType = _exptype2(node);
if (NULL == eType) {
_currentNode = NULL;
return END;
}
} while (eType == TEXT_NODE
|| (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
|| type == NAMESPACE_NODE);
}
else {
do {
node++;
type = _type2(node);
if (NULL == type ||!isDescendant(node)) {
_currentNode = NULL;
return END;
}
} while(ATTRIBUTE_NODE == type || TEXT_NODE == type
|| NAMESPACE_NODE == type);
}
_currentNode = node;
return returnNode(makeNodeHandle(node)); // make handle.
}
Reset.
/**
* Reset.
*
*/
public DTMAxisIterator reset()
{
final boolean temp = _isRestartable;
_isRestartable = true;
setStartNode(makeNodeHandle(_startNode));
_isRestartable = temp;
return this;
}
} // end of DescendantIterator
Typed iterator that returns the descendants of a given node.
/**
* Typed iterator that returns the descendants of a given node.
*/
public final class TypedDescendantIterator extends DescendantIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedDescendantIterator
Params: - nodeType – Extended type ID being requested.
/**
* Constructor TypedDescendantIterator
*
*
* @param nodeType Extended type ID being requested.
*/
public TypedDescendantIterator(int nodeType)
{
_nodeType = nodeType;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
final int startNode = _startNode;
if (_startNode == NULL) {
return NULL;
}
int node = _currentNode;
int expType;
final int nodeType = _nodeType;
if (nodeType != DTM.ELEMENT_NODE)
{
do
{
node++;
expType = _exptype2(node);
if (NULL == expType || _parent2(node) < startNode && startNode != node) {
_currentNode = NULL;
return END;
}
}
while (expType != nodeType);
}
// %OPT% If the start node is root (e.g. in the case of //node),
// we can save the isDescendant() check, because all nodes are
// descendants of root.
else if (startNode == DTMDefaultBase.ROOTNODE)
{
do
{
node++;
expType = _exptype2(node);
if (NULL == expType) {
_currentNode = NULL;
return END;
}
} while (expType < DTM.NTYPES
|| m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
}
else
{
do
{
node++;
expType = _exptype2(node);
if (NULL == expType || _parent2(node) < startNode && startNode != node) {
_currentNode = NULL;
return END;
}
}
while (expType < DTM.NTYPES
|| m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
}
_currentNode = node;
return returnNode(makeNodeHandle(node));
}
} // end of TypedDescendantIterator
Iterator that returns a given node only if it is of a given type.
/**
* Iterator that returns a given node only if it is of a given type.
*/
public final class TypedSingletonIterator extends SingletonIterator
{
The extended type ID that was requested. /** The extended type ID that was requested. */
private final int _nodeType;
Constructor TypedSingletonIterator
Params: - nodeType – The extended type ID being requested.
/**
* Constructor TypedSingletonIterator
*
*
* @param nodeType The extended type ID being requested.
*/
public TypedSingletonIterator(int nodeType)
{
_nodeType = nodeType;
}
Get the next node in the iteration.
Returns: The next node handle in the iteration, or END.
/**
* Get the next node in the iteration.
*
* @return The next node handle in the iteration, or END.
*/
public int next()
{
final int result = _currentNode;
if (result == END)
return DTM.NULL;
_currentNode = END;
if (_nodeType >= DTM.NTYPES) {
if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
return returnNode(result);
}
}
else {
if (_type2(makeNodeIdentity(result)) == _nodeType) {
return returnNode(result);
}
}
return NULL;
}
} // end of TypedSingletonIterator
End of nested iterators
/*******************************************************************
* End of nested iterators
*******************************************************************/
// %OPT% Array references which are used to cache the map0 arrays in
// SuballocatedIntVectors. Using the cached arrays reduces the level
// of indirection and results in better performance than just calling
// SuballocatedIntVector.elementAt().
private int[] m_exptype_map0;
private int[] m_nextsib_map0;
private int[] m_firstch_map0;
private int[] m_parent_map0;
// Double array references to the map arrays in SuballocatedIntVectors.
private int[][] m_exptype_map;
private int[][] m_nextsib_map;
private int[][] m_firstch_map;
private int[][] m_parent_map;
// %OPT% Cache the array of extended types in this class
protected ExtendedType[] m_extendedTypes;
// A Vector which is used to store the values of attribute, namespace,
// comment and PI nodes.
//
// %OPT% These values are unlikely to be equal. Storing
// them in a plain Vector is more efficient than storing in the
// DTMStringPool because we can save the cost for hash calculation.
//
// %REVISIT% Do we need a custom class (e.g. StringVector) here?
protected Vector m_values;
// The current index into the m_values Vector.
private int m_valueIndex = 0;
// The maximum value of the current node index.
private int m_maxNodeIndex;
// Cache the shift and mask values for the SuballocatedIntVectors.
protected int m_SHIFT;
protected int m_MASK;
protected int m_blocksize;
%OPT% If the offset and length of a Text node are within certain limits,
we store a bitwise encoded value into an int, using 10 bits (max. 1024)
for length and 21 bits for offset. We can save two SuballocatedIntVector
calls for each getStringValueX() and dispatchCharacterEvents() call by
doing this.
/** %OPT% If the offset and length of a Text node are within certain limits,
* we store a bitwise encoded value into an int, using 10 bits (max. 1024)
* for length and 21 bits for offset. We can save two SuballocatedIntVector
* calls for each getStringValueX() and dispatchCharacterEvents() call by
* doing this.
*/
// The number of bits for the length of a Text node.
protected final static int TEXT_LENGTH_BITS = 10;
// The number of bits for the offset of a Text node.
protected final static int TEXT_OFFSET_BITS = 21;
// The maximum length value
protected final static int TEXT_LENGTH_MAX = (1<<TEXT_LENGTH_BITS) - 1;
// The maximum offset value
protected final static int TEXT_OFFSET_MAX = (1<<TEXT_OFFSET_BITS) - 1;
// True if we want to build the ID index table.
protected boolean m_buildIdIndex = true;
// Constant for empty String
private static final String EMPTY_STR = "";
// Constant for empty XMLString
private static final XMLString EMPTY_XML_STR = new XMLStringDefault("");
Construct a SAX2DTM2 object using the default block size.
/**
* Construct a SAX2DTM2 object using the default block size.
*/
public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
DTMWSFilter whiteSpaceFilter,
XMLStringFactory xstringfactory,
boolean doIndexing)
{
this(mgr, source, dtmIdentity, whiteSpaceFilter,
xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, true, false);
}
Construct a SAX2DTM2 object using the given block size.
/**
* Construct a SAX2DTM2 object using the given block size.
*/
public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
DTMWSFilter whiteSpaceFilter,
XMLStringFactory xstringfactory,
boolean doIndexing,
int blocksize,
boolean usePrevsib,
boolean buildIdIndex,
boolean newNameTable)
{
super(mgr, source, dtmIdentity, whiteSpaceFilter,
xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
// Initialize the values of m_SHIFT and m_MASK.
int shift;
for(shift=0; (blocksize>>>=1) != 0; ++shift);
m_blocksize = 1<<shift;
m_SHIFT = shift;
m_MASK = m_blocksize - 1;
m_buildIdIndex = buildIdIndex;
// Some documents do not have attribute nodes. That is why
// we set the initial size of this Vector to be small and set
// the increment to a bigger number.
m_values = new Vector(32, 512);
m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
// Set the map0 values in the constructor.
m_exptype_map0 = m_exptype.getMap0();
m_nextsib_map0 = m_nextsib.getMap0();
m_firstch_map0 = m_firstch.getMap0();
m_parent_map0 = m_parent.getMap0();
}
Override DTMDefaultBase._exptype() by dropping the incremental code.
This one is less efficient than _exptype2. It is only used during
DTM building. _exptype2 is used after the document is fully built.
/**
* Override DTMDefaultBase._exptype() by dropping the incremental code.
*
* <p>This one is less efficient than _exptype2. It is only used during
* DTM building. _exptype2 is used after the document is fully built.
*/
public final int _exptype(int identity)
{
return m_exptype.elementAt(identity);
}
/************************************************************************
* DTM base accessor interfaces
*
* %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
* very important to the DTM performance. To have the best performace,
* these several interfaces have direct access to the internal arrays of
* the SuballocatedIntVectors. The final modifier also has a noticeable
* impact on performance.
***********************************************************************/
The optimized version of DTMDefaultBase._exptype().
Params: - identity – A node identity, which must not be equal to
DTM.NULL
/**
* The optimized version of DTMDefaultBase._exptype().
*
* @param identity A node identity, which <em>must not</em> be equal to
* <code>DTM.NULL</code>
*/
public final int _exptype2(int identity)
{
//return m_exptype.elementAt(identity);
if (identity < m_blocksize)
return m_exptype_map0[identity];
else
return m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
}
The optimized version of DTMDefaultBase._nextsib().
Params: - identity – A node identity, which must not be equal to
DTM.NULL
/**
* The optimized version of DTMDefaultBase._nextsib().
*
* @param identity A node identity, which <em>must not</em> be equal to
* <code>DTM.NULL</code>
*/
public final int _nextsib2(int identity)
{
//return m_nextsib.elementAt(identity);
if (identity < m_blocksize)
return m_nextsib_map0[identity];
else
return m_nextsib_map[identity>>>m_SHIFT][identity&m_MASK];
}
The optimized version of DTMDefaultBase._firstch().
Params: - identity – A node identity, which must not be equal to
DTM.NULL
/**
* The optimized version of DTMDefaultBase._firstch().
*
* @param identity A node identity, which <em>must not</em> be equal to
* <code>DTM.NULL</code>
*/
public final int _firstch2(int identity)
{
//return m_firstch.elementAt(identity);
if (identity < m_blocksize)
return m_firstch_map0[identity];
else
return m_firstch_map[identity>>>m_SHIFT][identity&m_MASK];
}
The optimized version of DTMDefaultBase._parent().
Params: - identity – A node identity, which must not be equal to
DTM.NULL
/**
* The optimized version of DTMDefaultBase._parent().
*
* @param identity A node identity, which <em>must not</em> be equal to
* <code>DTM.NULL</code>
*/
public final int _parent2(int identity)
{
//return m_parent.elementAt(identity);
if (identity < m_blocksize)
return m_parent_map0[identity];
else
return m_parent_map[identity>>>m_SHIFT][identity&m_MASK];
}
The optimized version of DTMDefaultBase._type().
Params: - identity – A node identity, which must not be equal to
DTM.NULL
/**
* The optimized version of DTMDefaultBase._type().
*
* @param identity A node identity, which <em>must not</em> be equal to
* <code>DTM.NULL</code>
*/
public final int _type2(int identity)
{
//int eType = _exptype2(identity);
int eType;
if (identity < m_blocksize)
eType = m_exptype_map0[identity];
else
eType = m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
if (NULL != eType)
return m_extendedTypes[eType].getNodeType();
else
return NULL;
}
The optimized version of DTMDefaultBase.getExpandedTypeID(int).
This one is only used by DOMAdapter.getExpandedTypeID(int), which
is mostly called from the compiled translets.
/**
* The optimized version of DTMDefaultBase.getExpandedTypeID(int).
*
* <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
* is mostly called from the compiled translets.
*/
public final int getExpandedTypeID2(int nodeHandle)
{
int nodeID = makeNodeIdentity(nodeHandle);
//return (nodeID != NULL) ? _exptype2(nodeID) : NULL;
if (nodeID != NULL) {
if (nodeID < m_blocksize)
return m_exptype_map0[nodeID];
else
return m_exptype_map[nodeID>>>m_SHIFT][nodeID&m_MASK];
}
else
return NULL;
}
/*************************************************************************
* END of DTM base accessor interfaces
*************************************************************************/
Return the node type from the expanded type
/**
* Return the node type from the expanded type
*/
public final int _exptype2Type(int exptype)
{
if (NULL != exptype)
return m_extendedTypes[exptype].getNodeType();
else
return NULL;
}
Get a prefix either from the uri mapping, or just make
one up!
Params: - uri – The namespace URI, which may be null.
Returns: The prefix if there is one, or null.
/**
* Get a prefix either from the uri mapping, or just make
* one up!
*
* @param uri The namespace URI, which may be null.
*
* @return The prefix if there is one, or null.
*/
public int getIdForNamespace(String uri)
{
int index = m_values.indexOf(uri);
if (index < 0)
{
m_values.addElement(uri);
return m_valueIndex++;
}
else
return index;
}
Override SAX2DTM.startElement()
Receive notification of the start of an element.
By default, do nothing. Application writers may override this
method in a subclass to take specific actions at the start of
each element (such as allocating a new tree node or writing
output to a file).
Params: - uri – The Namespace URI, or the empty string if the
element has no Namespace URI or if Namespace
processing is not being performed.
- localName – The local name (without prefix), or the
empty string if Namespace processing is not being
performed.
- qName – The qualified name (with prefix), or the
empty string if qualified names are not available.
- attributes – The specified or defaulted attributes.
Throws: - SAXException – Any SAX exception, possibly
wrapping another exception.
See Also:
/**
* Override SAX2DTM.startElement()
*
* <p>Receive notification of the start of an element.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the start of
* each element (such as allocating a new tree node or writing
* output to a file).</p>
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @param attributes The specified or defaulted attributes.
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startElement
*/
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException
{
charactersFlush();
int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE);
int prefixIndex = (qName.length() != localName.length())
? m_valuesOrPrefixes.stringToIndex(qName) : 0;
int elemNode = addNode(DTM.ELEMENT_NODE, exName,
m_parents.peek(), m_previous, prefixIndex, true);
if(m_indexing)
indexNode(exName, elemNode);
m_parents.push(elemNode);
int startDecls = m_contextIndexes.peek();
int nDecls = m_prefixMappings.size();
String prefix;
if(!m_pastFirstElement)
{
// SPECIAL CASE: Implied declaration at root element
prefix="xml";
String declURL = "http://www.w3.org/XML/1998/namespace";
exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
m_values.addElement(declURL);
int val = m_valueIndex++;
addNode(DTM.NAMESPACE_NODE, exName, elemNode,
DTM.NULL, val, false);
m_pastFirstElement=true;
}
for (int i = startDecls; i < nDecls; i += 2)
{
prefix = (String) m_prefixMappings.elementAt(i);
if (prefix == null)
continue;
String declURL = (String) m_prefixMappings.elementAt(i + 1);
exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
m_values.addElement(declURL);
int val = m_valueIndex++;
addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false);
}
int n = attributes.getLength();
for (int i = 0; i < n; i++)
{
String attrUri = attributes.getURI(i);
String attrQName = attributes.getQName(i);
String valString = attributes.getValue(i);
int nodeType;
String attrLocalName = attributes.getLocalName(i);
if ((null != attrQName)
&& (attrQName.equals("xmlns")
|| attrQName.startsWith("xmlns:")))
{
prefix = getPrefix(attrQName, attrUri);
if (declAlreadyDeclared(prefix))
continue; // go to the next attribute.
nodeType = DTM.NAMESPACE_NODE;
}
else
{
nodeType = DTM.ATTRIBUTE_NODE;
if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID"))
setIDAttribute(valString, elemNode);
}
// Bit of a hack... if somehow valString is null, stringToIndex will
// return -1, which will make things very unhappy.
if(null == valString)
valString = "";
m_values.addElement(valString);
int val = m_valueIndex++;
if (attrLocalName.length() != attrQName.length())
{
prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
int dataIndex = m_data.size();
m_data.addElement(prefixIndex);
m_data.addElement(val);
val = -dataIndex;
}
exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType);
addNode(nodeType, exName, elemNode, DTM.NULL, val,
false);
}
if (null != m_wsfilter)
{
short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this);
boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
? getShouldStripWhitespace()
: (DTMWSFilter.STRIP == wsv);
pushShouldStripWhitespace(shouldStrip);
}
m_previous = DTM.NULL;
m_contextIndexes.push(m_prefixMappings.size()); // for the children.
}
Receive notification of the end of an element.
By default, do nothing. Application writers may override this
method in a subclass to take specific actions at the end of
each element (such as finalising a tree node or writing
output to a file).
Params: - uri – The Namespace URI, or the empty string if the
element has no Namespace URI or if Namespace
processing is not being performed.
- localName – The local name (without prefix), or the
empty string if Namespace processing is not being
performed.
- qName – The qualified XML 1.0 name (with prefix), or the
empty string if qualified names are not available.
Throws: - SAXException – Any SAX exception, possibly
wrapping another exception.
See Also:
/**
* Receive notification of the end of an element.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end of
* each element (such as finalising a tree node or writing
* output to a file).</p>
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified XML 1.0 name (with prefix), or the
* empty string if qualified names are not available.
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endElement
*/
public void endElement(String uri, String localName, String qName)
throws SAXException
{
charactersFlush();
// If no one noticed, startPrefixMapping is a drag.
// Pop the context for the last child (the one pushed by startElement)
m_contextIndexes.quickPop(1);
// Do it again for this one (the one pushed by the last endElement).
int topContextIndex = m_contextIndexes.peek();
if (topContextIndex != m_prefixMappings.size()) {
m_prefixMappings.setSize(topContextIndex);
}
m_previous = m_parents.pop();
popShouldStripWhitespace();
}
Report an XML comment anywhere in the document.
This callback will be used for comments inside or outside the
document element, including comments in the external DTD
subset (if read).
Params: - ch – An array holding the characters in the comment.
- start – The starting position in the array.
- length – The number of characters to use from the array.
Throws: - SAXException – The application may raise an exception.
/**
* Report an XML comment anywhere in the document.
*
* <p>This callback will be used for comments inside or outside the
* document element, including comments in the external DTD
* subset (if read).</p>
*
* @param ch An array holding the characters in the comment.
* @param start The starting position in the array.
* @param length The number of characters to use from the array.
* @throws SAXException The application may raise an exception.
*/
public void comment(char ch[], int start, int length) throws SAXException
{
if (m_insideDTD) // ignore comments if we're inside the DTD
return;
charactersFlush();
// %OPT% Saving the comment string in a Vector has a lower cost than
// saving it in DTMStringPool.
m_values.addElement(new String(ch, start, length));
int dataIndex = m_valueIndex++;
m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
m_parents.peek(), m_previous, dataIndex, false);
}
Receive notification of the beginning of the document.
Throws: - SAXException – Any SAX exception, possibly
wrapping another exception.
See Also:
/**
* Receive notification of the beginning of the document.
*
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startDocument
*/
public void startDocument() throws SAXException
{
int doc = addNode(DTM.DOCUMENT_NODE,
DTM.DOCUMENT_NODE,
DTM.NULL, DTM.NULL, 0, true);
m_parents.push(doc);
m_previous = DTM.NULL;
m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
}
Receive notification of the end of the document.
Throws: - SAXException – Any SAX exception, possibly
wrapping another exception.
See Also:
/**
* Receive notification of the end of the document.
*
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endDocument
*/
public void endDocument() throws SAXException
{
super.endDocument();
// Add a NULL entry to the end of the node arrays as
// the end indication.
m_exptype.addElement(NULL);
m_parent.addElement(NULL);
m_nextsib.addElement(NULL);
m_firstch.addElement(NULL);
// Set the cached references after the document is built.
m_extendedTypes = m_expandedNameTable.getExtendedTypes();
m_exptype_map = m_exptype.getMap();
m_nextsib_map = m_nextsib.getMap();
m_firstch_map = m_firstch.getMap();
m_parent_map = m_parent.getMap();
}
Construct the node map from the node.
Params: - type – raw type ID, one of DTM.XXX_NODE.
- expandedTypeID – The expended type ID.
- parentIndex – The current parent index.
- previousSibling – The previous sibling index.
- dataOrPrefix – index into m_data table, or string handle.
- canHaveFirstChild – true if the node can have a first child, false
if it is atomic.
Returns: The index identity of the node that was added.
/**
* Construct the node map from the node.
*
* @param type raw type ID, one of DTM.XXX_NODE.
* @param expandedTypeID The expended type ID.
* @param parentIndex The current parent index.
* @param previousSibling The previous sibling index.
* @param dataOrPrefix index into m_data table, or string handle.
* @param canHaveFirstChild true if the node can have a first child, false
* if it is atomic.
*
* @return The index identity of the node that was added.
*/
protected final int addNode(int type, int expandedTypeID,
int parentIndex, int previousSibling,
int dataOrPrefix, boolean canHaveFirstChild)
{
// Common to all nodes:
int nodeIndex = m_size++;
// Have we overflowed a DTM Identity's addressing range?
//if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
if (nodeIndex == m_maxNodeIndex)
{
addNewDTMID(nodeIndex);
m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
}
m_firstch.addElement(DTM.NULL);
m_nextsib.addElement(DTM.NULL);
m_parent.addElement(parentIndex);
m_exptype.addElement(expandedTypeID);
m_dataOrQName.addElement(dataOrPrefix);
if (m_prevsib != null) {
m_prevsib.addElement(previousSibling);
}
if (m_locator != null && m_useSourceLocationProperty) {
setSourceLocation();
}
// Note that nextSibling is not processed until charactersFlush()
// is called, to handle successive characters() events.
// Special handling by type: Declare namespaces, attach first child
switch(type)
{
case DTM.NAMESPACE_NODE:
declareNamespaceInContext(parentIndex,nodeIndex);
break;
case DTM.ATTRIBUTE_NODE:
break;
default:
if (DTM.NULL != previousSibling) {
m_nextsib.setElementAt(nodeIndex,previousSibling);
}
else if (DTM.NULL != parentIndex) {
m_firstch.setElementAt(nodeIndex,parentIndex);
}
break;
}
return nodeIndex;
}
Check whether accumulated text should be stripped; if not,
append the appropriate flavor of text/cdata node.
/**
* Check whether accumulated text should be stripped; if not,
* append the appropriate flavor of text/cdata node.
*/
protected final void charactersFlush()
{
if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
{
int length = m_chars.size() - m_textPendingStart;
boolean doStrip = false;
if (getShouldStripWhitespace())
{
doStrip = m_chars.isWhitespace(m_textPendingStart, length);
}
if (doStrip) {
m_chars.setLength(m_textPendingStart); // Discard accumulated text
} else {
// Guard against characters/ignorableWhitespace events that
// contained no characters. They should not result in a node.
if (length > 0) {
// If the offset and length do not exceed the given limits
// (offset < 2^21 and length < 2^10), then save both the offset
// and length in a bitwise encoded value.
if (length <= TEXT_LENGTH_MAX
&& m_textPendingStart <= TEXT_OFFSET_MAX) {
m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
m_parents.peek(), m_previous,
length + (m_textPendingStart << TEXT_LENGTH_BITS),
false);
} else {
// Store offset and length in the m_data array if one exceeds
// the given limits. Use a negative dataIndex as an indication.
int dataIndex = m_data.size();
m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
m_parents.peek(), m_previous, -dataIndex, false);
m_data.addElement(m_textPendingStart);
m_data.addElement(length);
}
}
}
// Reset for next text block
m_textPendingStart = -1;
m_textType = m_coalescedTextType = DTM.TEXT_NODE;
}
}
Override the processingInstruction() interface in SAX2DTM2.
%OPT% This one is different from SAX2DTM.processingInstruction()
in that we do not use extended types for PI nodes. The name of
the PI is saved in the DTMStringPool.
Receive notification of a processing instruction.
Params: - target – The processing instruction target.
- data – The processing instruction data, or null if
none is supplied.
Throws: - SAXException – Any SAX exception, possibly
wrapping another exception.
See Also:
/**
* Override the processingInstruction() interface in SAX2DTM2.
* <p>
* %OPT% This one is different from SAX2DTM.processingInstruction()
* in that we do not use extended types for PI nodes. The name of
* the PI is saved in the DTMStringPool.
*
* Receive notification of a processing instruction.
*
* @param target The processing instruction target.
* @param data The processing instruction data, or null if
* none is supplied.
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#processingInstruction
*/
public void processingInstruction(String target, String data)
throws SAXException
{
charactersFlush();
int dataIndex = m_data.size();
m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
DTM.PROCESSING_INSTRUCTION_NODE,
m_parents.peek(), m_previous,
-dataIndex, false);
m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
m_values.addElement(data);
m_data.addElement(m_valueIndex++);
}
The optimized version of DTMDefaultBase.getFirstAttribute().
Given a node handle, get the index of the node's first attribute.
Params: - nodeHandle – int Handle of the node.
Returns: Handle of first attribute, or DTM.NULL to indicate none exists.
/**
* The optimized version of DTMDefaultBase.getFirstAttribute().
* <p>
* Given a node handle, get the index of the node's first attribute.
*
* @param nodeHandle int Handle of the node.
* @return Handle of first attribute, or DTM.NULL to indicate none exists.
*/
public final int getFirstAttribute(int nodeHandle)
{
int nodeID = makeNodeIdentity(nodeHandle);
if (nodeID == DTM.NULL)
return DTM.NULL;
int type = _type2(nodeID);
if (DTM.ELEMENT_NODE == type)
{
// Assume that attributes and namespaces immediately follow the element.
while (true)
{
nodeID++;
// Assume this can not be null.
type = _type2(nodeID);
if (type == DTM.ATTRIBUTE_NODE)
{
return makeNodeHandle(nodeID);
}
else if (DTM.NAMESPACE_NODE != type)
{
break;
}
}
}
return DTM.NULL;
}
The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
Given a node identity, get the index of the node's first attribute.
Params: - identity – int identity of the node.
Returns: Identity of first attribute, or DTM.NULL to indicate none exists.
/**
* The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
* <p>
* Given a node identity, get the index of the node's first attribute.
*
* @param identity int identity of the node.
* @return Identity of first attribute, or DTM.NULL to indicate none exists.
*/
protected int getFirstAttributeIdentity(int identity) {
if (identity == NULL) {
return NULL;
}
int type = _type2(identity);
if (DTM.ELEMENT_NODE == type)
{
// Assume that attributes and namespaces immediately follow the element.
while (true)
{
identity++;
// Assume this can not be null.
type = _type2(identity);
if (type == DTM.ATTRIBUTE_NODE)
{
return identity;
}
else if (DTM.NAMESPACE_NODE != type)
{
break;
}
}
}
return DTM.NULL;
}
The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
Given a node identity for an attribute, advance to the next attribute.
Params: - identity – int identity of the attribute node. This
must be an attribute node.
Returns: int DTM node-identity of the resolved attr,
or DTM.NULL to indicate none exists.
/**
* The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
* <p>
* Given a node identity for an attribute, advance to the next attribute.
*
* @param identity int identity of the attribute node. This
* <strong>must</strong> be an attribute node.
*
* @return int DTM node-identity of the resolved attr,
* or DTM.NULL to indicate none exists.
*
*/
protected int getNextAttributeIdentity(int identity) {
// Assume that attributes and namespace nodes immediately follow the element
while (true) {
identity++;
int type = _type2(identity);
if (type == DTM.ATTRIBUTE_NODE) {
return identity;
} else if (type != DTM.NAMESPACE_NODE) {
break;
}
}
return DTM.NULL;
}
The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
Given a node handle and an expanded type ID, get the index of the node's
attribute of that type, if any.
Params: - nodeHandle – int Handle of the node.
- attType – int expanded type ID of the required attribute.
Returns: Handle of attribute of the required type, or DTM.NULL to indicate
none exists.
/**
* The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
* <p>
* Given a node handle and an expanded type ID, get the index of the node's
* attribute of that type, if any.
*
* @param nodeHandle int Handle of the node.
* @param attType int expanded type ID of the required attribute.
* @return Handle of attribute of the required type, or DTM.NULL to indicate
* none exists.
*/
protected final int getTypedAttribute(int nodeHandle, int attType)
{
int nodeID = makeNodeIdentity(nodeHandle);
if (nodeID == DTM.NULL)
return DTM.NULL;
int type = _type2(nodeID);
if (DTM.ELEMENT_NODE == type)
{
int expType;
while (true)
{
nodeID++;
expType = _exptype2(nodeID);
if (expType != DTM.NULL)
type = m_extendedTypes[expType].getNodeType();
else
return DTM.NULL;
if (type == DTM.ATTRIBUTE_NODE)
{
if (expType == attType) return makeNodeHandle(nodeID);
}
else if (DTM.NAMESPACE_NODE != type)
{
break;
}
}
}
return DTM.NULL;
}
Override SAX2DTM.getLocalName() in SAX2DTM2.
Processing for PIs is different.
Given a node handle, return its XPath- style localname. (As defined in
Namespaces, this is the portion of the name after any colon character).
Params: - nodeHandle – the id of the node.
Returns: String Local name of this node.
/**
* Override SAX2DTM.getLocalName() in SAX2DTM2.
* <p>Processing for PIs is different.
*
* Given a node handle, return its XPath- style localname. (As defined in
* Namespaces, this is the portion of the name after any colon character).
*
* @param nodeHandle the id of the node.
* @return String Local name of this node.
*/
public String getLocalName(int nodeHandle)
{
int expType = _exptype(makeNodeIdentity(nodeHandle));
if (expType == DTM.PROCESSING_INSTRUCTION_NODE)
{
int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
dataIndex = m_data.elementAt(-dataIndex);
return m_valuesOrPrefixes.indexToString(dataIndex);
}
else
return m_expandedNameTable.getLocalName(expType);
}
The optimized version of SAX2DTM.getNodeNameX().
Given a node handle, return the XPath node name. This should be the name
as described by the XPath data model, NOT the DOM- style name.
Params: - nodeHandle – the id of the node.
Returns: String Name of this node, which may be an empty string.
/**
* The optimized version of SAX2DTM.getNodeNameX().
* <p>
* Given a node handle, return the XPath node name. This should be the name
* as described by the XPath data model, NOT the DOM- style name.
*
* @param nodeHandle the id of the node.
* @return String Name of this node, which may be an empty string.
*/
public final String getNodeNameX(int nodeHandle)
{
int nodeID = makeNodeIdentity(nodeHandle);
int eType = _exptype2(nodeID);
if (eType == DTM.PROCESSING_INSTRUCTION_NODE)
{
int dataIndex = _dataOrQName(nodeID);
dataIndex = m_data.elementAt(-dataIndex);
return m_valuesOrPrefixes.indexToString(dataIndex);
}
final ExtendedType extType = m_extendedTypes[eType];
if (extType.getNamespace().length() == 0)
{
return extType.getLocalName();
}
else
{
int qnameIndex = m_dataOrQName.elementAt(nodeID);
if (qnameIndex == 0)
return extType.getLocalName();
if (qnameIndex < 0)
{
qnameIndex = -qnameIndex;
qnameIndex = m_data.elementAt(qnameIndex);
}
return m_valuesOrPrefixes.indexToString(qnameIndex);
}
}
The optimized version of SAX2DTM.getNodeName().
Given a node handle, return its DOM-style node name. This will include
names such as #text or #document.
Params: - nodeHandle – the id of the node.
Returns: String Name of this node, which may be an empty string.
%REVIEW% Document when empty string is possible...
%REVIEW-COMMENT% It should never be empty, should it?
/**
* The optimized version of SAX2DTM.getNodeName().
* <p>
* Given a node handle, return its DOM-style node name. This will include
* names such as #text or #document.
*
* @param nodeHandle the id of the node.
* @return String Name of this node, which may be an empty string.
* %REVIEW% Document when empty string is possible...
* %REVIEW-COMMENT% It should never be empty, should it?
*/
public String getNodeName(int nodeHandle)
{
int nodeID = makeNodeIdentity(nodeHandle);
int eType = _exptype2(nodeID);
final ExtendedType extType = m_extendedTypes[eType];
if (extType.getNamespace().length() == 0)
{
int type = extType.getNodeType();
String localName = extType.getLocalName();
if (type == DTM.NAMESPACE_NODE)
{
if (localName.length() == 0)
return "xmlns";
else
return "xmlns:" + localName;
}
else if (type == DTM.PROCESSING_INSTRUCTION_NODE)
{
int dataIndex = _dataOrQName(nodeID);
dataIndex = m_data.elementAt(-dataIndex);
return m_valuesOrPrefixes.indexToString(dataIndex);
}
else if (localName.length() == 0)
{
return getFixedNames(type);
}
else
return localName;
}
else
{
int qnameIndex = m_dataOrQName.elementAt(nodeID);
if (qnameIndex == 0)
return extType.getLocalName();
if (qnameIndex < 0)
{
qnameIndex = -qnameIndex;
qnameIndex = m_data.elementAt(qnameIndex);
}
return m_valuesOrPrefixes.indexToString(qnameIndex);
}
}
Override SAX2DTM.getStringValue(int)
This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
If the caller supplies an XMLStringFactory, the getStringValue() interface
in SAX2DTM will be called. Otherwise just calls getStringValueX() and
wraps the returned String in an XMLString.
Get the string-value of a node as a String object
(see http://www.w3.org/TR/xpath#data-model
for the definition of a node's string-value).
Params: - nodeHandle – The node ID.
Returns: A string object that represents the string-value of the given node.
/**
* Override SAX2DTM.getStringValue(int)
* <p>
* This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
* <p>
* If the caller supplies an XMLStringFactory, the getStringValue() interface
* in SAX2DTM will be called. Otherwise just calls getStringValueX() and
* wraps the returned String in an XMLString.
*
* Get the string-value of a node as a String object
* (see http://www.w3.org/TR/xpath#data-model
* for the definition of a node's string-value).
*
* @param nodeHandle The node ID.
*
* @return A string object that represents the string-value of the given node.
*/
public XMLString getStringValue(int nodeHandle)
{
int identity = makeNodeIdentity(nodeHandle);
if (identity == DTM.NULL)
return EMPTY_XML_STR;
int type= _type2(identity);
if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
{
int startNode = identity;
identity = _firstch2(identity);
if (DTM.NULL != identity)
{
int offset = -1;
int length = 0;
do
{
type = _exptype2(identity);
if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex >= 0)
{
if (-1 == offset)
{
offset = dataIndex >>> TEXT_LENGTH_BITS;
}
length += dataIndex & TEXT_LENGTH_MAX;
}
else
{
if (-1 == offset)
{
offset = m_data.elementAt(-dataIndex);
}
length += m_data.elementAt(-dataIndex + 1);
}
}
identity++;
} while (_parent2(identity) >= startNode);
if (length > 0)
{
if (m_xstrf != null)
return m_xstrf.newstr(m_chars, offset, length);
else
return new XMLStringDefault(m_chars.getString(offset, length));
}
else
return EMPTY_XML_STR;
}
else
return EMPTY_XML_STR;
}
else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex >= 0)
{
if (m_xstrf != null)
return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX);
else
return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX));
}
else
{
if (m_xstrf != null)
return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1));
else
return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1)));
}
}
else
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex < 0)
{
dataIndex = -dataIndex;
dataIndex = m_data.elementAt(dataIndex + 1);
}
if (m_xstrf != null)
return m_xstrf.newstr((String)m_values.elementAt(dataIndex));
else
return new XMLStringDefault((String)m_values.elementAt(dataIndex));
}
}
The optimized version of SAX2DTM.getStringValue(int).
%OPT% This is one of the most often used interfaces. Performance is
critical here. This one is different from SAX2DTM.getStringValue(int) in
that it returns a String instead of a XMLString.
Get the string- value of a node as a String object (see http: //www. w3.
org/TR/xpath#data- model for the definition of a node's string- value).
Params: - nodeHandle – The node ID.
Returns: A string object that represents the string-value of the given node.
/**
* The optimized version of SAX2DTM.getStringValue(int).
* <p>
* %OPT% This is one of the most often used interfaces. Performance is
* critical here. This one is different from SAX2DTM.getStringValue(int) in
* that it returns a String instead of a XMLString.
*
* Get the string- value of a node as a String object (see http: //www. w3.
* org/TR/xpath#data- model for the definition of a node's string- value).
*
* @param nodeHandle The node ID.
*
* @return A string object that represents the string-value of the given node.
*/
public final String getStringValueX(final int nodeHandle)
{
int identity = makeNodeIdentity(nodeHandle);
if (identity == DTM.NULL)
return EMPTY_STR;
int type= _type2(identity);
if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
{
int startNode = identity;
identity = _firstch2(identity);
if (DTM.NULL != identity)
{
int offset = -1;
int length = 0;
do
{
type = _exptype2(identity);
if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex >= 0)
{
if (-1 == offset)
{
offset = dataIndex >>> TEXT_LENGTH_BITS;
}
length += dataIndex & TEXT_LENGTH_MAX;
}
else
{
if (-1 == offset)
{
offset = m_data.elementAt(-dataIndex);
}
length += m_data.elementAt(-dataIndex + 1);
}
}
identity++;
} while (_parent2(identity) >= startNode);
if (length > 0)
{
return m_chars.getString(offset, length);
}
else
return EMPTY_STR;
}
else
return EMPTY_STR;
}
else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex >= 0)
{
return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX);
}
else
{
return m_chars.getString(m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1));
}
}
else
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex < 0)
{
dataIndex = -dataIndex;
dataIndex = m_data.elementAt(dataIndex + 1);
}
return (String)m_values.elementAt(dataIndex);
}
}
Returns the string value of the entire tree
/**
* Returns the string value of the entire tree
*/
public String getStringValue()
{
int child = _firstch2(ROOTNODE);
if (child == DTM.NULL) return EMPTY_STR;
// optimization: only create StringBuffer if > 1 child
if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL))
{
int dataIndex = m_dataOrQName.elementAt(child);
if (dataIndex >= 0)
return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX);
else
return m_chars.getString(m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex + 1));
}
else
return getStringValueX(getDocument());
}
The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
Directly call the
characters method on the passed ContentHandler for the
string-value of the given node (see http://www.w3.org/TR/xpath#data-model
for the definition of a node's string-value). Multiple calls to the
ContentHandler's characters methods may well occur for a single call to
this method.
Params: - nodeHandle – The node ID.
- ch – A non-null reference to a ContentHandler.
- normalize – true if the content should be normalized according to
the rules for the XPath
normalize-space
function.
Throws:
/**
* The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
* <p>
* Directly call the
* characters method on the passed ContentHandler for the
* string-value of the given node (see http://www.w3.org/TR/xpath#data-model
* for the definition of a node's string-value). Multiple calls to the
* ContentHandler's characters methods may well occur for a single call to
* this method.
*
* @param nodeHandle The node ID.
* @param ch A non-null reference to a ContentHandler.
* @param normalize true if the content should be normalized according to
* the rules for the XPath
* <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
* function.
*
* @throws SAXException
*/
public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
boolean normalize)
throws SAXException
{
int identity = makeNodeIdentity(nodeHandle);
if (identity == DTM.NULL)
return;
int type = _type2(identity);
if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
{
int startNode = identity;
identity = _firstch2(identity);
if (DTM.NULL != identity)
{
int offset = -1;
int length = 0;
do
{
type = _exptype2(identity);
if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex >= 0)
{
if (-1 == offset)
{
offset = dataIndex >>> TEXT_LENGTH_BITS;
}
length += dataIndex & TEXT_LENGTH_MAX;
}
else
{
if (-1 == offset)
{
offset = m_data.elementAt(-dataIndex);
}
length += m_data.elementAt(-dataIndex + 1);
}
}
identity++;
} while (_parent2(identity) >= startNode);
if (length > 0)
{
if(normalize)
m_chars.sendNormalizedSAXcharacters(ch, offset, length);
else
m_chars.sendSAXcharacters(ch, offset, length);
}
}
}
else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex >= 0)
{
if (normalize)
m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX);
else
m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX);
}
else
{
if (normalize)
m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1));
else
m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1));
}
}
else
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex < 0)
{
dataIndex = -dataIndex;
dataIndex = m_data.elementAt(dataIndex + 1);
}
String str = (String)m_values.elementAt(dataIndex);
if(normalize)
FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
0, str.length(), ch);
else
ch.characters(str.toCharArray(), 0, str.length());
}
}
Given a node handle, return its node value. This is mostly
as defined by the DOM, but may ignore some conveniences.
Params: - nodeHandle – The node id.
Returns: String Value of this node, or null if not
meaningful for this node type.
/**
* Given a node handle, return its node value. This is mostly
* as defined by the DOM, but may ignore some conveniences.
* <p>
*
* @param nodeHandle The node id.
* @return String Value of this node, or null if not
* meaningful for this node type.
*/
public String getNodeValue(int nodeHandle)
{
int identity = makeNodeIdentity(nodeHandle);
int type = _type2(identity);
if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
{
int dataIndex = _dataOrQName(identity);
if (dataIndex > 0)
{
return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX);
}
else
{
return m_chars.getString(m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1));
}
}
else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
|| DTM.DOCUMENT_NODE == type)
{
return null;
}
else
{
int dataIndex = m_dataOrQName.elementAt(identity);
if (dataIndex < 0)
{
dataIndex = -dataIndex;
dataIndex = m_data.elementAt(dataIndex + 1);
}
return (String)m_values.elementAt(dataIndex);
}
}
Copy the String value of a Text node to a SerializationHandler
/**
* Copy the String value of a Text node to a SerializationHandler
*/
protected final void copyTextNode(final int nodeID, SerializationHandler handler)
throws SAXException
{
if (nodeID != DTM.NULL) {
int dataIndex = m_dataOrQName.elementAt(nodeID);
if (dataIndex >= 0) {
m_chars.sendSAXcharacters(handler,
dataIndex >>> TEXT_LENGTH_BITS,
dataIndex & TEXT_LENGTH_MAX);
} else {
m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex),
m_data.elementAt(-dataIndex+1));
}
}
}
Copy an Element node to a SerializationHandler.
Params: - nodeID – The node identity
- exptype – The expanded type of the Element node
- handler – The SerializationHandler
Returns: The qualified name of the Element node.
/**
* Copy an Element node to a SerializationHandler.
*
* @param nodeID The node identity
* @param exptype The expanded type of the Element node
* @param handler The SerializationHandler
* @return The qualified name of the Element node.
*/
protected final String copyElement(int nodeID, int exptype,
SerializationHandler handler)
throws SAXException
{
final ExtendedType extType = m_extendedTypes[exptype];
String uri = extType.getNamespace();
String name = extType.getLocalName();
if (uri.length() == 0) {
handler.startElement(name);
return name;
}
else {
int qnameIndex = m_dataOrQName.elementAt(nodeID);
if (qnameIndex == 0) {
handler.startElement(name);
handler.namespaceAfterStartElement(EMPTY_STR, uri);
return name;
}
if (qnameIndex < 0) {
qnameIndex = -qnameIndex;
qnameIndex = m_data.elementAt(qnameIndex);
}
String qName = m_valuesOrPrefixes.indexToString(qnameIndex);
handler.startElement(qName);
int prefixIndex = qName.indexOf(':');
String prefix;
if (prefixIndex > 0) {
prefix = qName.substring(0, prefixIndex);
}
else {
prefix = null;
}
handler.namespaceAfterStartElement(prefix, uri);
return qName;
}
}
Copy namespace nodes.
Params: - nodeID – The Element node identity
- handler – The SerializationHandler
- inScope – true if all namespaces in scope should be copied,
false if only the namespace declarations should be copied.
/**
* Copy namespace nodes.
*
* @param nodeID The Element node identity
* @param handler The SerializationHandler
* @param inScope true if all namespaces in scope should be copied,
* false if only the namespace declarations should be copied.
*/
protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope)
throws SAXException
{
// %OPT% Optimization for documents which does not have any explicit
// namespace nodes. For these documents, there is an implicit
// namespace node (xmlns:xml="http://www.w3.org/XML/1998/namespace")
// declared on the root element node. In this case, there is no
// need to do namespace copying. We can safely return without
// doing anything.
if (m_namespaceDeclSetElements != null &&
m_namespaceDeclSetElements.size() == 1 &&
m_namespaceDeclSets != null &&
((SuballocatedIntVector)m_namespaceDeclSets.elementAt(0))
.size() == 1)
return;
SuballocatedIntVector nsContext = null;
int nextNSNode;
// Find the first namespace node
if (inScope) {
nsContext = findNamespaceContext(nodeID);
if (nsContext == null || nsContext.size() < 1)
return;
else
nextNSNode = makeNodeIdentity(nsContext.elementAt(0));
}
else
nextNSNode = getNextNamespaceNode2(nodeID);
int nsIndex = 1;
while (nextNSNode != DTM.NULL) {
// Retrieve the name of the namespace node
int eType = _exptype2(nextNSNode);
String nodeName = m_extendedTypes[eType].getLocalName();
// Retrieve the node value of the namespace node
int dataIndex = m_dataOrQName.elementAt(nextNSNode);
if (dataIndex < 0) {
dataIndex = -dataIndex;
dataIndex = m_data.elementAt(dataIndex + 1);
}
String nodeValue = (String)m_values.elementAt(dataIndex);
handler.namespaceAfterStartElement(nodeName, nodeValue);
if (inScope) {
if (nsIndex < nsContext.size()) {
nextNSNode = makeNodeIdentity(nsContext.elementAt(nsIndex));
nsIndex++;
}
else
return;
}
else
nextNSNode = getNextNamespaceNode2(nextNSNode);
}
}
Return the next namespace node following the given base node.
@baseID The node identity of the base node, which can be an
element, attribute or namespace node. Returns: The namespace node immediately following the base node.
/**
* Return the next namespace node following the given base node.
*
* @baseID The node identity of the base node, which can be an
* element, attribute or namespace node.
* @return The namespace node immediately following the base node.
*/
protected final int getNextNamespaceNode2(int baseID) {
int type;
while ((type = _type2(++baseID)) == DTM.ATTRIBUTE_NODE);
if (type == DTM.NAMESPACE_NODE)
return baseID;
else
return NULL;
}
Copy attribute nodes from an element .
Params: - nodeID – The Element node identity
- handler – The SerializationHandler
/**
* Copy attribute nodes from an element .
*
* @param nodeID The Element node identity
* @param handler The SerializationHandler
*/
protected final void copyAttributes(final int nodeID, SerializationHandler handler)
throws SAXException{
for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){
int eType = _exptype2(current);
copyAttribute(current, eType, handler);
}
}
Copy an Attribute node to a SerializationHandler
Params: - nodeID – The node identity
- exptype – The expanded type of the Element node
- handler – The SerializationHandler
/**
* Copy an Attribute node to a SerializationHandler
*
* @param nodeID The node identity
* @param exptype The expanded type of the Element node
* @param handler The SerializationHandler
*/
protected final void copyAttribute(int nodeID, int exptype,
SerializationHandler handler)
throws SAXException
{
/*
final String uri = getNamespaceName(node);
if (uri.length() != 0) {
final String prefix = getPrefix(node);
handler.namespaceAfterStartElement(prefix, uri);
}
handler.addAttribute(getNodeName(node), getNodeValue(node));
*/
final ExtendedType extType = m_extendedTypes[exptype];
final String uri = extType.getNamespace();
final String localName = extType.getLocalName();
String prefix = null;
String qname = null;
int dataIndex = _dataOrQName(nodeID);
int valueIndex = dataIndex;
if (dataIndex <= 0) {
int prefixIndex = m_data.elementAt(-dataIndex);
valueIndex = m_data.elementAt(-dataIndex+1);
qname = m_valuesOrPrefixes.indexToString(prefixIndex);
int colonIndex = qname.indexOf(':');
if (colonIndex > 0) {
prefix = qname.substring(0, colonIndex);
}
}
if (uri.length() != 0) {
handler.namespaceAfterStartElement(prefix, uri);
}
String nodeName = (prefix != null) ? qname : localName;
String nodeValue = (String)m_values.elementAt(valueIndex);
handler.addAttribute(nodeName, nodeValue);
}
}