mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-26 21:58:39 +01:00
303 lines
7.2 KiB
C++
303 lines
7.2 KiB
C++
#ifndef JEZUK_DOM_TRAVERSAL_TREEWALKER_IMPL_H
|
|
#define JEZUK_DOM_TRAVERSAL_TREEWALKER_IMPL_H
|
|
|
|
/////////////////////////////////////////
|
|
// C++ DOM Traversal Implementation
|
|
//
|
|
// $Id: TreeWalker.h 2 2002-06-21 11:16:28Z jez_higgins $
|
|
/////////////////////////////////////////
|
|
|
|
#include <DOM/Traversal/DocumentTraversal.hpp>
|
|
|
|
namespace Arabica
|
|
{
|
|
namespace DOM
|
|
{
|
|
namespace Traversal
|
|
{
|
|
|
|
template<class stringT, class string_adaptorT>
|
|
class TreeWalkerImpl : public TreeWalker_impl<stringT, string_adaptorT>
|
|
{
|
|
public:
|
|
typedef DOM::Node<stringT, string_adaptorT> node_t;
|
|
typedef NodeFilter<stringT, string_adaptorT> filter_t;
|
|
typedef typename filter_t::Result filter_result_t;
|
|
|
|
TreeWalkerImpl
|
|
(
|
|
node_t root,
|
|
unsigned long whatToShow,
|
|
filter_t* nodeFilter,
|
|
bool expandEntityRef
|
|
)
|
|
: root_(root),
|
|
currentNode_(root_),
|
|
whatToShow_(whatToShow),
|
|
nodeFilter_(nodeFilter),
|
|
expandEntityRef_(expandEntityRef)
|
|
{}
|
|
|
|
|
|
|
|
//todo: copy ctor, assignment op
|
|
//default ok?
|
|
|
|
node_t getRoot() { return root_; }
|
|
|
|
unsigned long getWhatToShow() { return whatToShow_; }
|
|
|
|
filter_t* getFilter() { return nodeFilter_; }
|
|
|
|
bool getExpandEntityReferences() { return expandEntityRef_; }
|
|
|
|
node_t getCurrentNode() { return currentNode_; }
|
|
|
|
void setCurrentNode(const node_t& currentNode) { currentNode_ = currentNode; }
|
|
|
|
node_t parentNode()
|
|
{
|
|
node_t n = getParentNodeImpl(currentNode_);
|
|
if(n != 0)
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
node_t firstChild()
|
|
{
|
|
node_t n = getFirstChildImpl(currentNode_);
|
|
if(n != 0)
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
node_t lastChild()
|
|
{
|
|
node_t n = getLastChildImpl(currentNode_);
|
|
if(n != 0)
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
node_t previousSibling()
|
|
{
|
|
node_t n = getPreviousSiblingImpl(currentNode_);
|
|
if(n != 0)
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
node_t nextSibling()
|
|
{
|
|
node_t n = getPreviousSiblingImpl(currentNode_);
|
|
if(n != 0)
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
node_t previousNode()
|
|
{
|
|
node_t n = getPreviousSiblingImpl(currentNode_);
|
|
if(n != 0)
|
|
{
|
|
node_t last_child = getLastChildImpl(n);
|
|
currentNode_ = (last_child != 0) ? last_child : n;
|
|
return currentNode_;
|
|
}
|
|
else
|
|
{
|
|
n = getParentNodeImpl(n);
|
|
if(n != 0)
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
}
|
|
|
|
node_t nextNode()
|
|
{
|
|
node_t n = getFirstChildImpl(currentNode_);
|
|
if(n != 0)
|
|
{
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
n = getNextSiblingImpl(currentNode_);
|
|
if(n != 0)
|
|
{
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
|
|
for(node_t parent = getParentNodeImpl(currentNode_); parent != 0; parent = getParentNodeImpl(parent))
|
|
{
|
|
n = getNextSiblingImpl(parent);
|
|
if(n != 0)
|
|
{
|
|
currentNode_ = n;
|
|
return n;
|
|
}
|
|
}
|
|
|
|
return empty_node();
|
|
}
|
|
|
|
static const node_t& empty_node()
|
|
{
|
|
static const node_t empty_node_;
|
|
return empty_node_;
|
|
}
|
|
|
|
protected:
|
|
node_t getParentNodeImpl(node_t& node)
|
|
{
|
|
if(node == 0 || node == root_)
|
|
return empty_node();
|
|
|
|
node_t new_node = node.getParentNode();
|
|
if (new_node == 0|| new_node == root_) //todo: check for root here?
|
|
return empty_node();
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_ACCEPT == accept)
|
|
return new_node;
|
|
else
|
|
return getParentNodeImpl(new_node);
|
|
}
|
|
|
|
node_t getNextSiblingImpl(node_t& node)
|
|
{
|
|
if(node == 0 || node == root_)
|
|
return empty_node();
|
|
|
|
node_t new_node = node.getNextSibling();
|
|
if (new_node == 0)
|
|
{
|
|
new_node = node.getParentNode();
|
|
if (new_node == 0 || new_node == root_)
|
|
return empty_node();
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_SKIP == accept)
|
|
return getNextSiblingImpl(new_node);
|
|
else
|
|
return empty_node();
|
|
}
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_ACCEPT == accept)
|
|
return new_node;
|
|
else if (filter_t::FILTER_SKIP == accept)
|
|
{
|
|
node_t child = getFirstChildImpl(new_node);
|
|
if (child == 0 && !new_node.hasChildNodes())
|
|
return getNextSiblingImpl(new_node);
|
|
else
|
|
return child;
|
|
}
|
|
else
|
|
return getNextSiblingImpl(new_node);
|
|
}
|
|
|
|
node_t getPreviousSiblingImpl(node_t& node)
|
|
{
|
|
if(node == 0 || node == root_)
|
|
return empty_node();
|
|
|
|
node_t new_node = node.getPreviousSibling();
|
|
if (new_node == 0)
|
|
{
|
|
new_node = node.getParentNode();
|
|
if (new_node == 0 || new_node == root_)
|
|
return empty_node();
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_SKIP == accept)
|
|
return getPreviousSiblingImpl(new_node);
|
|
else
|
|
return empty_node();
|
|
}
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_ACCEPT == accept)
|
|
return new_node;
|
|
else if (filter_t::FILTER_SKIP == accept)
|
|
{
|
|
node_t child = getLastChildImpl(new_node);
|
|
if (child == 0 && !new_node.hasChildNodes())
|
|
return getPreviousSiblingImpl(new_node);
|
|
else
|
|
return child;
|
|
}
|
|
else
|
|
return getPreviousSiblingImpl(new_node);
|
|
}
|
|
|
|
node_t getFirstChildImpl(node_t& node)
|
|
{
|
|
if(!expandEntityRef_ && node.getNodeType() == node_t::ENTITY_REFERENCE_NODE)
|
|
return empty_node();
|
|
|
|
node_t new_node = node.getFirstChild();
|
|
if (new_node == 0)
|
|
return empty_node();
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_ACCEPT == accept)
|
|
return new_node;
|
|
else if (filter_t::FILTER_SKIP == accept && new_node.hasChildNodes())
|
|
return getFirstChildImpl(new_node);
|
|
else
|
|
return getNextSiblingImpl(new_node);
|
|
}
|
|
|
|
node_t getLastChildImpl(node_t& node)
|
|
{
|
|
if(!expandEntityRef_ && node.getNodeType() == node_t::ENTITY_REFERENCE_NODE)
|
|
return empty_node();
|
|
|
|
node_t new_node = node.getLastChild();
|
|
if (new_node == 0)
|
|
return empty_node();
|
|
|
|
filter_result_t accept = acceptNode(new_node);
|
|
if (filter_t::FILTER_ACCEPT == accept)
|
|
return new_node;
|
|
else if (filter_t::FILTER_SKIP == accept && new_node.hasChildNodes())
|
|
return getLastChildImpl(new_node);
|
|
else
|
|
return getPreviousSiblingImpl(new_node);
|
|
}
|
|
|
|
//node-filter will only be checked if what-to-show succeeds
|
|
filter_result_t acceptNode(node_t const& node)
|
|
{
|
|
unsigned long f = 1 << (node.getNodeType() - 1);
|
|
filter_result_t accept =
|
|
((whatToShow_ & f) != 0) ?
|
|
filter_t::FILTER_ACCEPT :
|
|
filter_t::FILTER_SKIP;
|
|
|
|
if (filter_t::FILTER_ACCEPT == accept && nodeFilter_)
|
|
{
|
|
accept = nodeFilter_->acceptNode(node);
|
|
}
|
|
return accept;
|
|
}
|
|
|
|
|
|
private:
|
|
node_t root_;
|
|
node_t currentNode_;
|
|
unsigned long whatToShow_;
|
|
filter_t* nodeFilter_;
|
|
bool expandEntityRef_;
|
|
|
|
}; // class TreeWalkerImpl
|
|
|
|
|
|
} // namespace Traversal
|
|
} // namespace DOM
|
|
} // namespace Arabica
|
|
|
|
#endif //JEZUK_DOM_TRAVERSAL_TREEWALKER_IMPL_H
|