#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 namespace Arabica { namespace DOM { namespace Traversal { template class TreeWalkerImpl : public TreeWalker_impl { public: typedef DOM::Node node_t; typedef DOM::Traversal::NodeFilter filter_t; typedef typename filter_t::Result filter_result_t; TreeWalkerImpl ( node_t root, unsigned long whatToShow, NodeFilter* 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_; } NodeFilter* 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_; NodeFilter* nodeFilter_; bool expandEntityRef_; }; // class TreeWalkerImpl } // namespace Traversal } // namespace DOM } // namespace Arabica #endif //JEZUK_DOM_TRAVERSAL_TREEWALKER_IMPL_H