#ifndef ARABICA_XPATHIC_XPATH_AXIS_ENUMERATOR_H #define ARABICA_XPATHIC_XPATH_AXIS_ENUMERATOR_H #include #include #include #include "xpath_namespace_node.hpp" #include "xpath_object.hpp" namespace Arabica { namespace XPath { enum Axis { ANCESTOR, ANCESTOR_OR_SELF, ATTRIBUTE, CHILD, DESCENDANT, DESCENDANT_OR_SELF, FOLLOWING, FOLLOWING_SIBLING, NAMESPACE, PARENT, PRECEDING, PRECEDING_SIBLING, SELF }; // Axis namespace impl { template class AxisWalker; template AxisWalker* CreateAxis(const DOM::Node& context) { return new axis_walker(context.underlying_impl()); } // CreateAxis } // namespace impl template > class AxisEnumerator { typedef impl::AxisWalker* (*CreateAxisPtr)(const DOM::Node& context); struct NamedAxis { Axis name; CreateAxisPtr creator; }; static const NamedAxis AxisLookupTable[]; public: AxisEnumerator(const DOM::Node& context, Axis axis) : walker_(0), node_(0) { for(const NamedAxis* ax = AxisLookupTable; ax->creator != 0; ++ax) if(axis == ax->name) walker_ = ax->creator(context); if(!walker_) throw std::runtime_error("Unknown Axis specifier"); grab(); } // AxisEnumerator AxisEnumerator(const AxisEnumerator& rhs) : walker_(rhs.walker_->clone()) { grab(); } // AxisEnumerator AxisEnumerator& operator=(const AxisEnumerator& rhs) { impl::AxisWalker* newwalker = rhs.walker_->clone(); delete walker_; walker_ = newwalker; grab(); return *this; } // operator= ~AxisEnumerator() { delete walker_; } // ~AxisEnumerator bool forward() const { return walker_->forward(); } bool reverse() const { return !walker_->forward(); } const DOM::Node& operator*() const { return node_; } const DOM::Node* operator->() const { return &node_; } AxisEnumerator& operator++() { advance(); return *this; } AxisEnumerator operator++(int) { AxisEnumerator copy(*this); advance(); return copy; } private: void advance() { walker_->advance(); grab(); } // advance void grab() { node_.set_underlying_impl(walker_->get()); } // grab impl::AxisWalker* walker_; mutable DOM::Node node_; AxisEnumerator(); }; // class AxisEnumerator //////////////////////////////////////////////////// namespace impl { template class AxisWalker { public: virtual ~AxisWalker() { } DOM::Node_impl* get() const { return current_; } virtual void advance() = 0; bool forward() { return forward_; } virtual AxisWalker* clone() const = 0; protected: typedef DOM::Node_impl* RawNodeT; AxisWalker(bool forward) : current_(0), forward_(forward) { } AxisWalker(const AxisWalker& rhs) : current_(rhs.current_), forward_(rhs.forward_) { } void set(const RawNodeT current) { current_ = current; } void end() { current_ = 0; } static RawNodeT walkDown(const RawNodeT context, const RawNodeT origin) { if(context->getNodeType() == DOM::Node_base::ATTRIBUTE_NODE) return 0; RawNodeT next = context->getFirstChild(); if((next == 0) && (context == origin)) // node with no children return 0; if(next != 0) return next; next = findNextSibling(context); if(next != 0) return next; RawNodeT parent = context->getParentNode(); while(parent != origin && next == 0) { next = parent->getNextSibling(); parent = parent->getParentNode(); } // while ... return next; } // walkDown static RawNodeT findNextSibling(const RawNodeT node) { if(!nodeIsText(node)) return node->getNextSibling(); RawNodeT next = node->getNextSibling(); while((next != 0) && nodeIsText(next)) next = next->getNextSibling(); return next; } // findNextSibling static RawNodeT findPreviousSibling(const RawNodeT node) { RawNodeT prev = node->getPreviousSibling(); if((prev == 0) || (!nodeIsText(prev))) return prev; RawNodeT prev_again = prev->getPreviousSibling(); while((prev_again != 0) && (nodeIsText(prev_again))) { prev = prev_again; prev_again = prev->getPreviousSibling(); } // while return prev; } // findPreviousSibling private: static bool nodeIsText(const RawNodeT node) { return (node->getNodeType() == DOM::Node_base::TEXT_NODE) || (node->getNodeType() == DOM::Node_base::CDATA_SECTION_NODE); } // nodeIsText RawNodeT current_; bool forward_; AxisWalker& operator=(const AxisWalker&); bool operator==(const AxisWalker&); }; // AxisWalker template class AncestorAxisWalker : public AxisWalker { typedef DOM::Node_impl const* RawNodeT; typedef AxisWalker BaseT; public: AncestorAxisWalker(const RawNodeT context) : AxisWalker(false) { if(context == 0) return; if(context->getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) BaseT::set(context->getParentNode()); else BaseT::set((dynamic_cast* const>(context))->getOwnerElement()); } // AncestorAxisWalker virtual void advance() { if(BaseT::get() != 0) BaseT::set(BaseT::get()->getParentNode()); } // advance virtual AxisWalker* clone() const { return new AncestorAxisWalker(*this); } private: AncestorAxisWalker(const AncestorAxisWalker& rhs) : AxisWalker(rhs) { } }; // class AncestorAxisWalker template class AncestorOrSelfAxisWalker : public AxisWalker { typedef DOM::Node_impl* RawNodeT; typedef AxisWalker BaseT; public: AncestorOrSelfAxisWalker(const RawNodeT context) : AxisWalker(false) { if(context != 0) BaseT::set(context); } // AncestorAxisWalker virtual void advance() { if(BaseT::get() == 0) return; if(BaseT::get()->getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) BaseT::set(BaseT::get()->getParentNode()); else BaseT::set((dynamic_cast* const>(BaseT::get()))->getOwnerElement()); } // advance virtual AxisWalker* clone() const { return new AncestorOrSelfAxisWalker(*this); } private: AncestorOrSelfAxisWalker(const AncestorOrSelfAxisWalker& rhs) : AxisWalker(rhs) { } }; // class AncestorOrSelfAxisWalker template class AttributeAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; AttributeAxisWalker(const RawNodeT context) : AxisWalker(true), index_(0), count_(0) { if((context != 0) && (context->hasAttributes())) { attrs_ = context->getAttributes(); count_ = attrs_->getLength(); set_next(); } // if ... } // AttributeAxisWalker virtual void advance() { if(BaseT::get() == 0) return; set_next(); } // advance virtual AxisWalker* clone() const { return new AttributeAxisWalker(*this); } private: AttributeAxisWalker(const AttributeAxisWalker& rhs) : AxisWalker(rhs), attrs_(rhs.attrs_), index_(rhs.index_), count_(rhs.count_) { } DOM::NamedNodeMap_impl* attrs_; unsigned int index_; unsigned int count_; void set_next() { if(index_ == count_) { BaseT::end(); return; } // if ... RawNodeT a; do { a = attrs_->item(index_++); } while ((a != 0) && (a->getNamespaceURI() == string_adaptor::construct_from_utf8("http://www.w3.org/2000/xmlns/"))); BaseT::set(a); } // set_next }; // class AttributeAxisEnumerator template class ChildAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; ChildAxisWalker(const RawNodeT context) : AxisWalker(true) { if(context != 0) BaseT::set(context->getFirstChild()); } // ChildAxisWalker virtual void advance() { if(BaseT::get() != 0) BaseT::set(BaseT::findNextSibling(BaseT::get())); } // advance virtual AxisWalker* clone() const { return new ChildAxisWalker(*this); } private: ChildAxisWalker(const ChildAxisWalker& rhs) : AxisWalker(rhs) { } }; // class ChildAxisWalker template class DescendantAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; DescendantAxisWalker(const RawNodeT context) : AxisWalker(true), origin_(context) { if((context != 0) && (context->getNodeType() != DOM::Node_base::ATTRIBUTE_NODE)) BaseT::set(context->getFirstChild()); } // DescendantAxisWalker virtual void advance() { BaseT::set(nextDescendant()); } // advance virtual AxisWalker* clone() const { return new DescendantAxisWalker(*this); } private: RawNodeT nextDescendant() { RawNodeT next = BaseT::get()->getFirstChild(); if(next == 0) next = BaseT::findNextSibling(BaseT::get()); if(next != 0) return next; RawNodeT parent = BaseT::get()->getParentNode(); while(parent != origin_ && next == 0) { next = parent->getNextSibling(); parent = parent->getParentNode(); } // while ... return next; } // nextDescendant DescendantAxisWalker(const DescendantAxisWalker& rhs) : AxisWalker(rhs), origin_(rhs.origin_) { } const RawNodeT origin_; }; // class DescendantAxisWalker template class DescendantOrSelfAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; DescendantOrSelfAxisWalker(const RawNodeT context) : AxisWalker(true), origin_(context) { if(context != 0) BaseT::set(context); } // DescendantOrSelfAxisWalker virtual void advance() { BaseT::set(BaseT::walkDown(BaseT::get(), origin_)); } // advance virtual AxisWalker* clone() const { return new DescendantOrSelfAxisWalker(*this); } private: DescendantOrSelfAxisWalker(const DescendantOrSelfAxisWalker& rhs) : AxisWalker(rhs), origin_(rhs.origin_) { } const RawNodeT origin_; }; // class DescendantOrSelfAxisWalker template class FollowingAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; FollowingAxisWalker(const RawNodeT context) : AxisWalker(true) { BaseT::set(firstFollowing(context)); } // FollowingAxisWalker virtual void advance() { BaseT::set(BaseT::walkDown(BaseT::get(), BaseT::get()->getOwnerDocument())); } // advance virtual AxisWalker* clone() const { return new FollowingAxisWalker(*this); } private: RawNodeT firstFollowing(const RawNodeT context) const { if(context->getNodeType() == DOM::Node_base::ATTRIBUTE_NODE) { RawNodeT owner = dynamic_cast* const>(context)->getOwnerElement(); if(owner->hasChildNodes()) return owner->getFirstChild(); return firstFollowing(owner); } // if attribute RawNodeT next = BaseT::findNextSibling(context); if(next != 0) return next; RawNodeT parent = context->getParentNode(); while(parent != context->getOwnerDocument() && next == 0) { next = parent->getNextSibling(); parent = parent->getParentNode(); } // while ... return next; } // firstFollowing FollowingAxisWalker(const FollowingAxisWalker& rhs) : AxisWalker(rhs) { } }; // class FollowingAxisWalker template class FollowingSiblingAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; FollowingSiblingAxisWalker(const RawNodeT context) : BaseT(true) { if(context != 0) BaseT::set(BaseT::findNextSibling(context)); } // FollowingSiblingAxisWalker virtual void advance() { if(BaseT::get() != 0) BaseT::set(BaseT::findNextSibling(BaseT::get())); } // advance virtual BaseT* clone() const { return new FollowingSiblingAxisWalker(*this); } private: FollowingSiblingAxisWalker(const FollowingSiblingAxisWalker& rhs) : BaseT(rhs) { } }; // class FollowingSiblingAxisWalker template class NamespaceAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; NamespaceAxisWalker(const RawNodeT context) : BaseT(true), xmlns_prefix_(string_adaptor::construct_from_utf8("xmlns")), index_(0) { RawNodeT current = context; if(current->getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) push_back(context, string_adaptor::construct_from_utf8("xml"), string_adaptor::construct_from_utf8("http://www.w3.org/XML/1998/namespace")); while(current->getNodeType() == DOM::Node_base::ELEMENT_NODE) { for(unsigned int a = 0, ae = current->getAttributes()->getLength(); a != ae; ++a) { RawNodeT attr = current->getAttributes()->item(a); if(attr->getPrefix() == xmlns_prefix_) push_back(context, attr->getLocalName(), attr->getNodeValue()); if(attr->getNodeName() == xmlns_prefix_) push_back(context, string_adaptor::empty_string(), attr->getNodeValue()); } // for ... current = current->getParentNode(); } // while list_.push_back(0); BaseT::set(list_[index_]); } // NamespaceAxisWalker virtual ~NamespaceAxisWalker() { for(int i = 0; list_[i] != 0; ++i) list_[i]->releaseRef(); } // ~NamespaceAxisWalker virtual void advance() { if(index_ != list_.size()) BaseT::set(list_[++index_]); } // advance virtual BaseT* clone() const { return new NamespaceAxisWalker(*this); } private: void push_back(RawNodeT context, const string_type& prefix, const string_type& uri) { RawNodeT node = new NamespaceNodeImpl(context, prefix, uri); node->addRef(); list_.push_back(node); } // push_back NamespaceAxisWalker(const NamespaceAxisWalker& rhs) : BaseT(rhs) { } std::vector list_; const string_type xmlns_prefix_; unsigned int index_; }; // class NamespaceAxisWalker template class ParentAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; ParentAxisWalker(const RawNodeT context) : BaseT(false) { if(context == 0) return; if(context->getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) BaseT::set(context->getParentNode()); else BaseT::set((dynamic_cast* const>(context))->getOwnerElement()); } // ParentAxisWalker virtual void advance() { if(BaseT::get() != 0) BaseT::set(0); } // advance virtual BaseT* clone() const { return new ParentAxisWalker(*this); } private: ParentAxisWalker(const ParentAxisWalker& rhs) : BaseT(rhs) { } }; // class ParentAxisWalker template class PrecedingAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; PrecedingAxisWalker(const RawNodeT context) : BaseT(false) { if(context->getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) firstPreceding(context); else firstPreceding((dynamic_cast* const>(context))->getOwnerElement()); } // PrecedingAxisWalker virtual void advance() { BaseT::set(previousInDocument(BaseT::get())); } // advance virtual BaseT* clone() const { return new PrecedingAxisWalker(*this); } private: void firstPreceding(const RawNodeT context) { nextAncestor_ = context->getParentNode(); BaseT::set(previousInDocument(context)); } // firstPreceding RawNodeT previousInDocument(const RawNodeT context) { RawNodeT next = BaseT::findPreviousSibling(context); if(next != 0) return getLastDescendant(next); next = context->getParentNode(); if(next != nextAncestor_) return next; // ancestor collision!! woorp, woorp! if(nextAncestor_ != 0) { nextAncestor_ = nextAncestor_->getParentNode(); if(nextAncestor_ != 0) return previousInDocument(next); } // return 0; } // previousInDocument RawNodeT getLastDescendant(const RawNodeT context) { if(context->getFirstChild() == 0) return context; RawNodeT c = context->getFirstChild(); while(c->getNextSibling() != 0) c = c->getNextSibling(); return getLastDescendant(c); } // getLastDescendant PrecedingAxisWalker(const PrecedingAxisWalker& rhs) : BaseT(rhs), nextAncestor_(rhs.nextAncestor_) { } RawNodeT nextAncestor_; }; // PrecedingAxisWalker template class PrecedingSiblingAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; PrecedingSiblingAxisWalker(const RawNodeT& context) : BaseT(false) { if(context != 0) BaseT::set(BaseT::findPreviousSibling(context)); } // PrecedingSiblingAxisWalker virtual void advance() { if(BaseT::get() != 0) BaseT::set(BaseT::findPreviousSibling(BaseT::get())); } // advance virtual BaseT* clone() const { return new PrecedingSiblingAxisWalker(*this); } private: PrecedingSiblingAxisWalker(const PrecedingSiblingAxisWalker& rhs) : BaseT(rhs) { } }; // class PrecedingSiblingAxisWalker template class SelfAxisWalker : public AxisWalker { typedef AxisWalker BaseT; public: typedef DOM::Node_impl* RawNodeT; SelfAxisWalker(const RawNodeT context) : BaseT(true) { BaseT::set(context); } // SelfAxisWalker virtual void advance() { BaseT::end(); } // advance virtual BaseT* clone() const { return new SelfAxisWalker(*this); } private: SelfAxisWalker(const SelfAxisWalker& rhs) : BaseT(rhs) { } }; // class SelfAxisWalker } // namespace impl template const typename AxisEnumerator::NamedAxis AxisEnumerator::AxisLookupTable[] = { { ANCESTOR, impl::CreateAxis, string_type> }, { ANCESTOR_OR_SELF, impl::CreateAxis, string_type> }, { ATTRIBUTE, impl::CreateAxis, string_type> }, { CHILD, impl::CreateAxis, string_type> }, { DESCENDANT, impl::CreateAxis, string_type> }, { DESCENDANT_OR_SELF, impl::CreateAxis, string_type> }, { FOLLOWING, impl::CreateAxis, string_type> }, { FOLLOWING_SIBLING, impl::CreateAxis, string_type> }, { NAMESPACE, impl::CreateAxis, string_type> }, { PARENT, impl::CreateAxis, string_type> }, { PRECEDING, impl::CreateAxis, string_type> }, { PRECEDING_SIBLING, impl::CreateAxis, string_type> }, { SELF, impl::CreateAxis, string_type> }, { static_cast(0), 0 } }; } // namespace XPath } // namespace Arabica #endif