#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); } } // 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) { 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"); } // AxisEnumerator AxisEnumerator(const AxisEnumerator& rhs) : walker_(rhs.walker_->clone()) { } // AxisEnumerator AxisEnumerator& operator=(const AxisEnumerator& rhs) { impl::AxisWalker* newwalker = rhs.walker_->clone(); delete walker_; walker_ = newwalker; 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 walker_->get(); } const DOM::Node* const operator->() const { return &(walker_->get()); } AxisEnumerator& operator++() { walker_->advance(); return *this; } AxisEnumerator operator++(int) { AxisEnumerator copy(*this); walker_->advance(); return copy; } private: impl::AxisWalker* walker_; AxisEnumerator(); }; // class AxisEnumerator //////////////////////////////////////////////////// namespace impl { template class AxisWalker { public: virtual ~AxisWalker() { } const DOM::Node& get() const { return current_; } virtual void advance() = 0; bool forward() { return forward_; } virtual AxisWalker* clone() const = 0; protected: AxisWalker(bool forward) : forward_(forward) { } AxisWalker(const AxisWalker& rhs) : current_(rhs.current_), forward_(rhs.forward_) { } void set(const DOM::Node& current) { current_ = current; } void end() { current_ = 0; } static DOM::Node walkDown(const DOM::Node& context, const DOM::Node& origin) { if(context.getNodeType() == DOM::Node_base::ATTRIBUTE_NODE) return 0; DOM::Node 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; DOM::Node parent = context.getParentNode(); while(parent != origin && next == 0) { next = parent.getNextSibling(); parent = parent.getParentNode(); } // while ... return next; } // walkDown static DOM::Node findNextSibling(const DOM::Node& node) { if(!nodeIsText(node)) return node.getNextSibling(); DOM::Node next = node.getNextSibling(); while((next != 0) && nodeIsText(next)) next = next.getNextSibling(); return next; } // findNextSibling private: static bool nodeIsText(const DOM::Node& node) { return (node.getNodeType() == DOM::Node_base::TEXT_NODE) || (node.getNodeType() == DOM::Node_base::CDATA_SECTION_NODE); } // nodeIsText DOM::Node current_; bool forward_; AxisWalker& operator=(const AxisWalker&); bool operator==(const AxisWalker&); }; // AxisWalker template class AncestorAxisWalker : public AxisWalker { public: AncestorAxisWalker(const DOM::Node& context) : AxisWalker(false) { if(context == 0) return; if(context.getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) AxisWalker::set(context.getParentNode()); else AxisWalker::set((static_cast >(context)).getOwnerElement()); } // AncestorAxisWalker virtual void advance() { if(AxisWalker::get() != 0) AxisWalker::set(AxisWalker::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 { public: AncestorOrSelfAxisWalker(const DOM::Node& context) : AxisWalker(false) { if(context != 0) AxisWalker::set(context); } // AncestorAxisWalker virtual void advance() { if(AxisWalker::get() == 0) return; if(AxisWalker::get().getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) AxisWalker::set(AxisWalker::get().getParentNode()); else AxisWalker::set((static_cast >(AxisWalker::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 { public: AttributeAxisWalker(const DOM::Node& 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(AxisWalker::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 attrs_; unsigned int index_; unsigned int count_; void set_next() { if(index_ == count_) { AxisWalker::end(); return; } // if ... DOM::Node a; do { a = attrs_.item(index_++); } while ((a != 0) && (a.getNamespaceURI() == string_adaptor::construct_from_utf8("http://www.w3.org/2000/xmlns/"))); AxisWalker::set(a); } // set_next }; // class AttributeAxisEnumerator template class ChildAxisWalker : public AxisWalker { public: ChildAxisWalker(const DOM::Node& context) : AxisWalker(true) { if(context != 0) AxisWalker::set(context.getFirstChild()); } // ChildAxisWalker virtual void advance() { if(AxisWalker::get() != 0) AxisWalker::set(AxisWalker::findNextSibling(AxisWalker::get())); } // advance virtual AxisWalker* clone() const { return new ChildAxisWalker(*this); } private: ChildAxisWalker(const ChildAxisWalker& rhs) : AxisWalker(rhs) { } }; // class ChildAxisWalker template class DescendantAxisWalker : public AxisWalker { public: DescendantAxisWalker(const DOM::Node& context) : AxisWalker(true), origin_(context) { if((context != 0) && (context.getNodeType() != DOM::Node_base::ATTRIBUTE_NODE)) AxisWalker::set(context.getFirstChild()); } // DescendantAxisWalker virtual void advance() { AxisWalker::set(nextDescendant()); } // advance virtual AxisWalker* clone() const { return new DescendantAxisWalker(*this); } private: DOM::Node nextDescendant() { DOM::Node next = AxisWalker::get().getFirstChild(); if(next == 0) next = AxisWalker::findNextSibling(AxisWalker::get()); if(next != 0) return next; DOM::Node parent = AxisWalker::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 DOM::Node origin_; }; // class DescendantAxisWalker template class DescendantOrSelfAxisWalker : public AxisWalker { public: DescendantOrSelfAxisWalker(const DOM::Node& context) : AxisWalker(true), origin_(context) { if(context != 0) AxisWalker::set(context); } // DescendantAxisWalker virtual void advance() { AxisWalker::set(AxisWalker::walkDown(AxisWalker::get(), origin_)); } // advance virtual AxisWalker* clone() const { return new DescendantOrSelfAxisWalker(*this); } private: DescendantOrSelfAxisWalker(const DescendantOrSelfAxisWalker& rhs) : AxisWalker(rhs), origin_(rhs.origin_) { } const DOM::Node origin_; }; // class DescendantOrSelfAxisWalker template class FollowingAxisWalker : public AxisWalker { public: FollowingAxisWalker(const DOM::Node& context) : AxisWalker(true) { AxisWalker::set(firstFollowing(context)); } // FollowingAxisWalker virtual void advance() { AxisWalker::set(AxisWalker::walkDown(AxisWalker::get(), AxisWalker::get().getOwnerDocument())); } // advance virtual AxisWalker* clone() const { return new FollowingAxisWalker(*this); } private: DOM::Node firstFollowing(const DOM::Node& context) const { if(context.getNodeType() == DOM::Node_base::ATTRIBUTE_NODE) { DOM::Node owner = static_cast >(context).getOwnerElement(); if(owner.hasChildNodes()) return owner.getFirstChild(); return firstFollowing(owner); } // if attribute DOM::Node next = context.getNextSibling(); if(next != 0) return next; DOM::Node 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 { public: FollowingSiblingAxisWalker(const DOM::Node& context) : AxisWalker(true) { if(context != 0) AxisWalker::set(context.getNextSibling()); } // FollowingSiblingAxisWalker virtual void advance() { if(AxisWalker::get() != 0) AxisWalker::set(AxisWalker::get().getNextSibling()); } // advance virtual AxisWalker* clone() const { return new FollowingSiblingAxisWalker(*this); } private: FollowingSiblingAxisWalker(const FollowingSiblingAxisWalker& rhs) : AxisWalker(rhs) { } }; // class FollowingSiblingAxisWalker template class NamespaceAxisWalker : public AxisWalker { public: NamespaceAxisWalker(const DOM::Node& context) : AxisWalker(true), xmlns_prefix_(string_adaptor::construct_from_utf8("xmlns")), index_(0) { DOM::Node current = context; if(current.getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) list_.push_back(DOM::Node( new NamespaceNodeImpl(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) { DOM::Node attr = current.getAttributes().item(a); if(attr.getPrefix() == xmlns_prefix_) list_.push_back(DOM::Node( new NamespaceNodeImpl(context, attr.getLocalName(), attr.getNodeValue()) ) ); if(attr.getNodeName() == xmlns_prefix_) list_.push_back(DOM::Node( new NamespaceNodeImpl(context, string_adaptor::empty_string(), attr.getNodeValue()) ) ); } // for ... current = current.getParentNode(); } // while list_.push_back(DOM::Node(0)); AxisWalker::set(list_[index_]); } // NamespaceAxisWalker virtual void advance() { if(index_ != list_.size()) AxisWalker::set(list_[++index_]); } // advance virtual AxisWalker* clone() const { return new NamespaceAxisWalker(*this); } private: NamespaceAxisWalker(const NamespaceAxisWalker& rhs) : AxisWalker(rhs) { } std::vector > list_; const string_type xmlns_prefix_; unsigned int index_; }; // class NamespaceAxisWalker template class ParentAxisWalker : public AxisWalker { public: ParentAxisWalker(const DOM::Node& context) : AxisWalker(false) { if(context == 0) return; if(context.getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) AxisWalker::set(context.getParentNode()); else AxisWalker::set((static_cast >(context)).getOwnerElement()); } // ParentAxisWalker virtual void advance() { if(AxisWalker::get() != 0) AxisWalker::set(0); } // advance virtual AxisWalker* clone() const { return new ParentAxisWalker(*this); } private: ParentAxisWalker(const ParentAxisWalker& rhs) : AxisWalker(rhs) { } }; // class ParentAxisWalker template class PrecedingAxisWalker : public AxisWalker { public: PrecedingAxisWalker(const DOM::Node& context) : AxisWalker(false) { if(context.getNodeType() != DOM::Node_base::ATTRIBUTE_NODE) firstPreceding(context); else firstPreceding((static_cast >(context)).getOwnerElement()); } // PrecedingAxisWalker virtual void advance() { AxisWalker::set(previousInDocument(AxisWalker::get())); } // advance virtual AxisWalker* clone() const { return new PrecedingAxisWalker(*this); } private: void firstPreceding(const DOM::Node& context) { nextAncestor_ = context.getParentNode(); AxisWalker::set(previousInDocument(context)); } // firstPreceding DOM::Node previousInDocument(const DOM::Node& context) { DOM::Node next = context.getPreviousSibling(); 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 DOM::Node getLastDescendant(const DOM::Node& context) { if(context.getFirstChild() == 0) return context; DOM::Node c = context.getFirstChild(); while(c.getNextSibling() != 0) c = c.getNextSibling(); return getLastDescendant(c); } // getLastDescendant PrecedingAxisWalker(const PrecedingAxisWalker& rhs) : AxisWalker(rhs), nextAncestor_(rhs.nextAncestor_) { } DOM::Node nextAncestor_; }; // PrecedingAxisWalker template class PrecedingSiblingAxisWalker : public AxisWalker { public: PrecedingSiblingAxisWalker(const DOM::Node& context) : AxisWalker(false) { if(context != 0) AxisWalker::set(context.getPreviousSibling()); } // PrecedingSiblingAxisWalker virtual void advance() { if(AxisWalker::get() != 0) AxisWalker::set(AxisWalker::get().getPreviousSibling()); } // advance virtual AxisWalker* clone() const { return new PrecedingSiblingAxisWalker(*this); } private: PrecedingSiblingAxisWalker(const PrecedingSiblingAxisWalker& rhs) : AxisWalker(rhs) { } }; // class PrecedingSiblingAxisWalker template class SelfAxisWalker : public AxisWalker { public: SelfAxisWalker(const DOM::Node& context) : AxisWalker(true) { AxisWalker::set(context); } // SelfAxisWalker virtual void advance() { AxisWalker::end(); } virtual AxisWalker* clone() const { return new SelfAxisWalker(*this); } private: SelfAxisWalker(const SelfAxisWalker& rhs) : AxisWalker(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