blob: c4a278b6946e1505a865a59e45d51746ef519c5f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.xml.core.internal.document;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.NodeIterator;
/**
* NodeIteratorImpl class
*/
public class NodeIteratorImpl implements NodeIterator {
private NodeFilter filter = null;
private Node nextNode = null;
private Node rootNode = null;
private int whatToShow = NodeFilter.SHOW_ALL;
/**
* NodeIteratorImpl constructor
*
* @param rootNode
* org.w3c.dom.Node
*/
NodeIteratorImpl(Node rootNode, int whatToShow, NodeFilter filter) {
this.rootNode = rootNode;
this.nextNode = rootNode;
this.whatToShow = whatToShow;
this.filter = filter;
}
/**
*/
private final boolean acceptNode(Node node) {
if (this.whatToShow != NodeFilter.SHOW_ALL) {
if (node == null)
return false;
short nodeType = node.getNodeType();
switch (this.whatToShow) {
case NodeFilter.SHOW_ELEMENT :
if (nodeType != Node.ELEMENT_NODE)
return false;
break;
case NodeFilter.SHOW_ATTRIBUTE :
if (nodeType != Node.ATTRIBUTE_NODE)
return false;
break;
case NodeFilter.SHOW_TEXT :
if (nodeType != Node.TEXT_NODE)
return false;
break;
case NodeFilter.SHOW_CDATA_SECTION :
if (nodeType != Node.CDATA_SECTION_NODE)
return false;
break;
case NodeFilter.SHOW_ENTITY_REFERENCE :
if (nodeType != Node.ENTITY_REFERENCE_NODE)
return false;
break;
case NodeFilter.SHOW_ENTITY :
if (nodeType != Node.ENTITY_NODE)
return false;
break;
case NodeFilter.SHOW_PROCESSING_INSTRUCTION :
if (nodeType != Node.PROCESSING_INSTRUCTION_NODE)
return false;
break;
case NodeFilter.SHOW_COMMENT :
if (nodeType != Node.COMMENT_NODE)
return false;
break;
case NodeFilter.SHOW_DOCUMENT :
if (nodeType != Node.DOCUMENT_NODE)
return false;
break;
case NodeFilter.SHOW_DOCUMENT_TYPE :
if (nodeType != Node.DOCUMENT_TYPE_NODE)
return false;
break;
case NodeFilter.SHOW_DOCUMENT_FRAGMENT :
if (nodeType != Node.DOCUMENT_FRAGMENT_NODE)
return false;
break;
case NodeFilter.SHOW_NOTATION :
if (nodeType != Node.NOTATION_NODE)
return false;
break;
default :
return false;
}
}
if (this.filter != null) {
return (this.filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT);
}
return true;
}
/**
* Detaches the <code>NodeIterator</code> from the set which it iterated
* over, releasing any computational resources and placing the iterator in
* the INVALID state. After <code>detach</code> has been invoked, calls
* to <code>nextNode</code> or <code>previousNode</code> will raise
* the exception INVALID_STATE_ERR.
*/
public void detach() {
this.rootNode = null;
this.nextNode = null;
this.filter = null;
}
/**
* The value of this flag determines whether the children of entity
* reference nodes are visible to the iterator. If false, they and their
* descendants will be rejected. Note that this rejection takes precedence
* over <code>whatToShow</code> and the filter. Also note that this is
* currently the only situation where <code>NodeIterators</code> may
* reject a complete subtree rather than skipping individual nodes. <br>
* <br>
* To produce a view of the document that has entity references expanded
* and does not expose the entity reference node itself, use the
* <code>whatToShow</code> flags to hide the entity reference node and
* set <code>expandEntityReferences</code> to true when creating the
* iterator. To produce a view of the document that has entity reference
* nodes but no entity expansion, use the <code>whatToShow</code> flags
* to show the entity reference node and set
* <code>expandEntityReferences</code> to false.
*/
public boolean getExpandEntityReferences() {
// not supported
return false;
}
/**
* The <code>NodeFilter</code> used to screen nodes.
*/
public NodeFilter getFilter() {
return this.filter;
}
/**
*/
private final Node getNextNode() {
if (this.nextNode == null)
return null;
Node oldNext = this.nextNode;
Node child = this.nextNode.getFirstChild();
if (child != null) {
this.nextNode = child;
return oldNext;
}
for (Node node = this.nextNode; node != null && node != this.rootNode; node = node.getParentNode()) {
Node next = node.getNextSibling();
if (next != null) {
this.nextNode = next;
return oldNext;
}
}
this.nextNode = null;
return oldNext;
}
/**
*/
private final Node getPreviousNode() {
if (this.nextNode == this.rootNode)
return null;
Node prev = null;
if (this.nextNode == null) {
prev = this.rootNode; // never null
} else {
prev = this.nextNode.getPreviousSibling();
if (prev == null) {
this.nextNode = this.nextNode.getParentNode();
return this.nextNode;
}
}
Node last = prev.getLastChild();
while (last != null) {
prev = last;
last = prev.getLastChild();
}
this.nextNode = prev;
return this.nextNode;
}
/**
* The root node of the <code>NodeIterator</code>, as specified when it
* was created.
*/
public Node getRoot() {
return this.rootNode;
}
/**
* This attribute determines which node types are presented via the
* iterator. The available set of constants is defined in the
* <code>NodeFilter</code> interface. Nodes not accepted by
* <code>whatToShow</code> will be skipped, but their children may still
* be considered. Note that this skip takes precedence over the filter, if
* any.
*/
public int getWhatToShow() {
return this.whatToShow;
}
/**
* Returns the next node in the set and advances the position of the
* iterator in the set. After a <code>NodeIterator</code> is created,
* the first call to <code>nextNode()</code> returns the first node in
* the set.
*
* @return The next <code>Node</code> in the set being iterated over, or
* <code>null</code> if there are no more members in that set.
* @exception DOMException
* INVALID_STATE_ERR: Raised if this method is called after
* the <code>detach</code> method was invoked.
*/
public Node nextNode() throws DOMException {
for (Node node = getNextNode(); node != null; node = getNextNode()) {
if (acceptNode(node))
return node;
}
return null;
}
/**
* Returns the previous node in the set and moves the position of the
* <code>NodeIterator</code> backwards in the set.
*
* @return The previous <code>Node</code> in the set being iterated
* over, or <code>null</code> if there are no more members in
* that set.
* @exception DOMException
* INVALID_STATE_ERR: Raised if this method is called after
* the <code>detach</code> method was invoked.
*/
public Node previousNode() throws DOMException {
for (Node node = getPreviousNode(); node != null; node = getPreviousNode()) {
if (acceptNode(node))
return node;
}
return null;
}
}