|
|
|
|
|
|
|
*/ |
|
/* |
|
* 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. |
|
*/ |
|
|
|
package com.sun.org.apache.xerces.internal.dom; |
|
|
|
import org.w3c.dom.DOMException; |
|
import org.w3c.dom.Node; |
|
import org.w3c.dom.traversal.NodeFilter; |
|
import org.w3c.dom.traversal.NodeIterator; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class NodeIteratorImpl implements NodeIterator { |
|
|
|
// |
|
// Data |
|
// |
|
|
|
|
|
private DocumentImpl fDocument; |
|
|
|
private Node fRoot; |
|
|
|
private int fWhatToShow = NodeFilter.SHOW_ALL; |
|
|
|
private NodeFilter fNodeFilter; |
|
|
|
private boolean fDetach = false; |
|
|
|
// |
|
// Iterator state - current node and direction. |
|
// |
|
// Note: The current node and direction are sufficient to implement |
|
// the desired behaviour of the current pointer being _between_ |
|
// two nodes. The fCurrentNode is actually the last node returned, |
|
// and the |
|
// direction is whether the pointer is in front or behind this node. |
|
// (usually akin to whether the node was returned via nextNode()) |
|
// (eg fForward = true) or previousNode() (eg fForward = false). |
|
// Note also, if removing a Node, the fCurrentNode |
|
// can be placed on a Node which would not pass filters. |
|
|
|
|
|
private Node fCurrentNode; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean fForward = true; |
|
|
|
|
|
private boolean fEntityReferenceExpansion; |
|
|
|
// |
|
// Constructor |
|
// |
|
|
|
|
|
public NodeIteratorImpl( DocumentImpl document, |
|
Node root, |
|
int whatToShow, |
|
NodeFilter nodeFilter, |
|
boolean entityReferenceExpansion) { |
|
fDocument = document; |
|
fRoot = root; |
|
fCurrentNode = null; |
|
fWhatToShow = whatToShow; |
|
fNodeFilter = nodeFilter; |
|
fEntityReferenceExpansion = entityReferenceExpansion; |
|
} |
|
|
|
public Node getRoot() { |
|
return fRoot; |
|
} |
|
|
|
// Implementation Note: Note that the iterator looks at whatToShow |
|
// and filter values at each call, and therefore one _could_ add |
|
// setters for these values and alter them while iterating! |
|
|
|
|
|
public int getWhatToShow() { |
|
return fWhatToShow; |
|
} |
|
|
|
|
|
public NodeFilter getFilter() { |
|
return fNodeFilter; |
|
} |
|
|
|
|
|
public boolean getExpandEntityReferences() { |
|
return fEntityReferenceExpansion; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Node nextNode() { |
|
|
|
if( fDetach) { |
|
throw new DOMException( |
|
DOMException.INVALID_STATE_ERR, |
|
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); |
|
} |
|
|
|
|
|
if (fRoot == null) return null; |
|
|
|
Node nextNode = fCurrentNode; |
|
boolean accepted = false; |
|
|
|
accepted_loop: |
|
while (!accepted) { |
|
|
|
|
|
if (!fForward && nextNode!=null) { |
|
|
|
nextNode = fCurrentNode; |
|
} else { |
|
|
|
if (!fEntityReferenceExpansion |
|
&& nextNode != null |
|
&& nextNode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { |
|
nextNode = nextNode(nextNode, false); |
|
} else { |
|
nextNode = nextNode(nextNode, true); |
|
} |
|
} |
|
|
|
fForward = true; |
|
|
|
|
|
if (nextNode == null) return null; |
|
|
|
|
|
accepted = acceptNode(nextNode); |
|
if (accepted) { |
|
|
|
fCurrentNode = nextNode; |
|
return fCurrentNode; |
|
} else |
|
continue accepted_loop; |
|
|
|
} // while (!accepted) { |
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
*/ |
|
public Node previousNode() { |
|
|
|
if( fDetach) { |
|
throw new DOMException( |
|
DOMException.INVALID_STATE_ERR, |
|
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); |
|
} |
|
|
|
|
|
if (fRoot == null || fCurrentNode == null) return null; |
|
|
|
Node previousNode = fCurrentNode; |
|
boolean accepted = false; |
|
|
|
accepted_loop: |
|
while (!accepted) { |
|
|
|
if (fForward && previousNode != null) { |
|
|
|
previousNode = fCurrentNode; |
|
} else { |
|
|
|
previousNode = previousNode(previousNode); |
|
} |
|
|
|
|
|
fForward = false; |
|
|
|
// if the new previous node is null, we're at head or past the root, |
|
|
|
if (previousNode == null) return null; |
|
|
|
|
|
accepted = acceptNode(previousNode); |
|
if (accepted) { |
|
|
|
fCurrentNode = previousNode; |
|
return fCurrentNode; |
|
} else |
|
continue accepted_loop; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
|
|
boolean acceptNode(Node node) { |
|
|
|
if (fNodeFilter == null) { |
|
return ( fWhatToShow & (1 << node.getNodeType()-1)) != 0 ; |
|
} else { |
|
return ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 ) |
|
&& fNodeFilter.acceptNode(node) == NodeFilter.FILTER_ACCEPT; |
|
} |
|
} |
|
|
|
|
|
Node matchNodeOrParent(Node node) { |
|
// Additions and removals in the underlying data structure may occur |
|
|
|
if (fCurrentNode == null) return null; |
|
|
|
// check if the removed node is an _ancestor_ of the |
|
|
|
for (Node n = fCurrentNode; n != fRoot; n = n.getParentNode()) { |
|
if (node == n) return n; |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
Node nextNode(Node node, boolean visitChildren) { |
|
|
|
if (node == null) return fRoot; |
|
|
|
Node result; |
|
|
|
if (visitChildren) { |
|
|
|
if (node.hasChildNodes()) { |
|
result = node.getFirstChild(); |
|
return result; |
|
} |
|
} |
|
|
|
if (node == fRoot) { |
|
return null; |
|
} |
|
|
|
|
|
result = node.getNextSibling(); |
|
if (result != null) return result; |
|
|
|
|
|
|
|
Node parent = node.getParentNode(); |
|
while (parent != null && parent != fRoot) { |
|
result = parent.getNextSibling(); |
|
if (result != null) { |
|
return result; |
|
} else { |
|
parent = parent.getParentNode(); |
|
} |
|
|
|
} // while (parent != null && parent != fRoot) { |
|
|
|
|
|
return null; |
|
} |
|
|
|
|
|
|
|
*/ |
|
Node previousNode(Node node) { |
|
|
|
Node result; |
|
|
|
|
|
if (node == fRoot) return null; |
|
|
|
|
|
result = node.getPreviousSibling(); |
|
if (result == null) { |
|
|
|
result = node.getParentNode(); |
|
return result; |
|
} |
|
|
|
|
|
if (result.hasChildNodes() |
|
&& !(!fEntityReferenceExpansion |
|
&& result != null |
|
&& result.getNodeType() == Node.ENTITY_REFERENCE_NODE)) |
|
|
|
{ |
|
while (result.hasChildNodes()) { |
|
result = result.getLastChild(); |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeNode(Node node) { |
|
|
|
// Implementation note: Fix-up means setting the current node properly |
|
// after a remove. |
|
|
|
if (node == null) return; |
|
|
|
Node deleted = matchNodeOrParent(node); |
|
|
|
if (deleted == null) return; |
|
|
|
if (fForward) { |
|
fCurrentNode = previousNode(deleted); |
|
} else |
|
|
|
{ |
|
Node next = nextNode(deleted, false); |
|
if (next!=null) { |
|
|
|
fCurrentNode = next; |
|
} else { |
|
// the last node in the iterator is to be removed, |
|
|
|
fCurrentNode = previousNode(deleted); |
|
fForward = true; |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
public void detach() { |
|
fDetach = true; |
|
fDocument.removeNodeIterator(this); |
|
} |
|
|
|
} |