blob: eec324b760fe7cb9e0796bc3998b91ff333c252e [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache\@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation, and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.ibm.com . For more information
* on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/**
* $Log$
* Revision 1.4 1999/11/30 21:16:25 roddey
* Changes to add the transcode() method to DOMString, which returns a transcoded
* version (to local code page) of the DOM string contents. And I changed all of the
* exception 'throw by pointer' to 'throw by value' style.
*
* Revision 1.3 1999/11/23 01:48:16 rahulj
* Changed 0L to 0. CC under HPUX is happy now.
*
* Revision 1.2 1999/11/20 00:56:39 rahulj
* Source files must end with an un-escaped newline.
*
* Revision 1.1.1.1 1999/11/09 01:09:15 twl
* Initial checkin
*
* Revision 1.2 1999/11/08 20:44:30 rahul
* Swat for adding in Product name and CVS comment log variable.
*
*/
// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////
#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
NodeIteratorImpl::NodeIteratorImpl ()
{
fDetached = false;
}
NodeIteratorImpl::~NodeIteratorImpl ()
{
fDetached = false;
}
void NodeIteratorImpl::detach ()
{
fDetached = true;
}
NodeIteratorImpl::NodeIteratorImpl (DOM_Node root, int whatToShow, DOM_NodeFilter nodeFilter, NodeFilterImpl* fi)
{
fDetached = false;
fRoot = root;
fCurrentNode = 0;
fWhatToShow = whatToShow;
fNodeFilter = nodeFilter;
if (fi != 0L) {
DOM_NodeFilter nf(fi);
fNodeFilter = nf;
}
fForward = true;
}
NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
fRoot = other.fRoot;
fCurrentNode = other.fRoot;
fWhatToShow = other.fWhatToShow;
fNodeFilter = other.fNodeFilter;
fForward = other.fForward;
fDetached = other.fDetached;
return *this;
}
// 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!
/** Return the whatToShow value */
int NodeIteratorImpl::getWhatToShow () {
return fWhatToShow;
}
/** Return the filter */
DOM_NodeFilter NodeIteratorImpl::getFilter () {
return fNodeFilter;
}
void NodeIteratorImpl::setWhatToShow (int what) {
fWhatToShow = what;
}
void NodeIteratorImpl::setFilter (DOM_NodeFilter filter) {
fNodeFilter = filter;
}
/** Return the next DOM_Node in the Iterator. The node is the next node in
* depth-first order which also passes the filter, and whatToShow.
* A null return means either that
*/
DOM_Node NodeIteratorImpl::nextNode () {
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
DOM_Node result;
// if root is null there is no next node.
if (fRoot.isNull())
return result;
DOM_Node aNextNode = fCurrentNode;
bool accepted = false; // the next node has not been accepted.
while (!accepted) {
// if last direction is not forward, repeat node.
if (!fForward && !aNextNode.isNull()) {
//System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
aNextNode = fCurrentNode;
} else {
// else get the next node via depth-first
aNextNode = nextNode(aNextNode, true);
}
fForward = true; //REVIST: should direction be set forward before null check?
// nothing in the list. return null.
if (aNextNode.isNull())
return result;
// does node pass the filters and whatToShow?
accepted = acceptNode(aNextNode);
if (accepted) {
// if so, then the node is the current node.
fCurrentNode = aNextNode;
return fCurrentNode;
}
}
// no nodes, or no accepted nodes.
return result;
}
/** Return the previous Node in the Iterator. The node is the next node in
* _backwards_ depth-first order which also passes the filter, and whatToShow.
*/
DOM_Node NodeIteratorImpl::previousNode () {
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
DOM_Node result;
// if the root is null, or the current node is null, return null.
if (fRoot.isNull() || fCurrentNode.isNull())
return result;
DOM_Node aPreviousNode = fCurrentNode;
bool accepted = false;
while (!accepted) {
if (fForward && ! aPreviousNode.isNull()) {
//repeat last node.
aPreviousNode = fCurrentNode;
} else {
// get previous node in backwards depth first order.
aPreviousNode = previousNode(aPreviousNode);
}
// we are going backwards
fForward = false;
// if the new previous node is null, we're at head or past the root,
// so return null.
if (aPreviousNode.isNull())
return result;
// check if node passes filters and whatToShow.
accepted = acceptNode(aPreviousNode);
if (accepted) {
// if accepted, update the current node, and return it.
fCurrentNode = aPreviousNode;
return fCurrentNode;
}
}
// there are no nodes?
return result;
}
/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
if (fNodeFilter == 0) {
return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
} else {
return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
&& fNodeFilter.acceptNode(node) == DOM_NodeFilter::ACCEPT;
}
}
/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
DOM_Node result;
for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
if (node == n) return n;
}
return result;
}
/** The method nextNode(DOM_Node, bool) returns the next node
* from the actual DOM tree.
*
* The bool visitChildren determines whether to visit the children.
* The result is the nextNode.
*/
DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
if (node.isNull()) return fRoot;
DOM_Node result;
// only check children if we visit children.
if (visitChildren) {
//if hasChildren, return 1st child.
if (node.hasChildNodes()) {
result = node.getFirstChild();
return result;
}
}
// if hasSibling, return sibling
result = node.getNextSibling();
if (! result.isNull()) return result;
// return parent's 1st sibling.
DOM_Node parent = node.getParentNode();
while (!parent.isNull() && parent != fRoot) {
result = parent.getNextSibling();
if (!result.isNull()) {
return result;
} else {
parent = parent.getParentNode();
}
} // while (parent != null && parent != fRoot) {
// end of list, return null
DOM_Node aNull;
return aNull;
}
/** The method previousNode(DOM_Node) returns the previous node
* from the actual DOM tree.
*/
DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
DOM_Node result;
// if we're at the root, return null.
if (node == fRoot)
return result;
// get sibling
result = node.getPreviousSibling();
if (result.isNull()) {
//if 1st sibling, return parent
result = node.getParentNode();
return result;
}
// if sibling has children, keep getting last child of child.
if (result.hasChildNodes()) {
while (result.hasChildNodes()) {
result = result.getLastChild();
}
}
return result;
}
/** Fix-up the iterator on a remove. Called by DOM or otherwise,
* before an actual DOM remove.
*/
void NodeIteratorImpl::removeNode (DOM_Node node) {
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
// Implementation note: Fix-up means setting the current node properly
// after a remove.
if (node.isNull())
return;
DOM_Node deleted = matchNodeOrParent(node);
if (deleted.isNull()) return;
if (fForward) {
fCurrentNode = previousNode(deleted);
} else
// if (!fForward)
{
DOM_Node next = nextNode(deleted, false);
if (! next.isNull()) {
// normal case: there _are_ nodes following this in the iterator.
fCurrentNode = next;
} else {
// the last node in the iterator is to be removed,
// so we set the current node to be the previous one.
fCurrentNode = previousNode(deleted);
fForward = true;
}
}
}
void NodeIteratorImpl::unreferenced()
{
DOM_Document doc = fRoot.getOwnerDocument();
DocumentImpl* impl;
if (! doc.isNull()) {
impl = (DocumentImpl *) doc.fImpl;
}
else
impl = (DocumentImpl *) fRoot.fImpl;
if (impl->iterators != 0L) {
int i;
int sz = impl->iterators->size();
for (i = 0; i < sz; i++)
if (impl->iterators->elementAt(i) == this) {
impl->iterators->removeElementAt(i);
break;
}
}
delete this;
}