#ifndef ARABICA_XPATHIC_XPATH_STEP_H #define ARABICA_XPATHIC_XPATH_STEP_H #include #include #include "xpath_object.hpp" #include "xpath_value.hpp" #include "xpath_axis_enumerator.hpp" #include "xpath_node_test.hpp" #include "xpath_ast.hpp" #include "xpath_ast_ids.hpp" #include "xpath_namespace_context.hpp" #include "xpath_compile_context.hpp" namespace Arabica { namespace XPath { template class MatchExpr; namespace impl { template class StepExpression : public XPathExpression_impl { public: StepExpression() { } StepExpression(XPathExpression_impl* pred) { predicates_.push_back(pred); } StepExpression(const std::vector *>& predicates) : predicates_(predicates) { } virtual ~StepExpression() { for(typename std::vector*>::iterator p = predicates_.begin(), e = predicates_.end(); p != e; ++p) delete *p; } // ~StepExpression virtual ValueType type() const { return NODE_SET; } virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const = 0; virtual XPathValue evaluate(NodeSet& context, const ExecutionContext& executionContext) const = 0; bool has_predicates() const { return !predicates_.empty(); } protected: NodeSet applyPredicates(NodeSet& nodes, const ExecutionContext& parentContext) const { for(typename std::vector*>::const_iterator p = predicates_.begin(), e = predicates_.end(); (p != e) && (!nodes.empty()); ++p) nodes = applyPredicate(nodes, *p, parentContext); return nodes; } // applyPredicates private: NodeSet applyPredicate(NodeSet& nodes, XPathExpression_impl* predicate, const ExecutionContext& parentContext) const { ExecutionContext executionContext(nodes.size(), parentContext); NodeSet results(nodes.forward()); unsigned int position = 1; for(typename NodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i, ++position) { executionContext.setPosition(position); XPathValue v = predicate->evaluate(*i, executionContext); if((v.type() == NUMBER) && (position != v.asNumber())) continue; if(v.asBool() == false) continue; results.push_back(*i); } // for ... return results; } // applyPredicate std::vector*> predicates_; friend class MatchExpr; }; // StepExpression template class TestStepExpression : public StepExpression { typedef StepExpression baseT; public: TestStepExpression(Axis axis, NodeTest* test) : StepExpression(), axis_(axis), test_(test) { } // TestStepExpression TestStepExpression(Axis axis, NodeTest* test, XPathExpression_impl* pred) : StepExpression(pred), axis_(axis), test_(test) { } // TestStepExpression TestStepExpression(Axis axis, NodeTest* test, const std::vector*>& predicates) : StepExpression(predicates), axis_(axis), test_(test) { } // TestStepExpression virtual ~TestStepExpression() { delete test_; } // StepExpression virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { NodeSet nodes; enumerateOver(context, nodes, executionContext); return XPathValue(new NodeSetValue(nodes)); } // evaluate virtual XPathValue evaluate(NodeSet& context, const ExecutionContext& executionContext) const { NodeSet nodes; for(typename NodeSet::iterator n = context.begin(); n != context.end(); ++n) enumerateOver(*n, nodes, executionContext); return XPathValue(new NodeSetValue(nodes)); } // evaluate private: void enumerateOver(const DOM::Node& context, NodeSet& results, const ExecutionContext& parentContext) const { AxisEnumerator enumerator(context, axis_); results.forward(enumerator.forward()); NodeSet intermediate(enumerator.forward()); NodeSet& d = (!baseT::has_predicates()) ? results : intermediate; while(*enumerator != 0) { // if test DOM::Node node = *enumerator; if((*test_)(node)) d.push_back(node); ++enumerator; } // while ... if(!baseT::has_predicates()) return; intermediate = baseT::applyPredicates(intermediate, parentContext); results.insert(results.end(), intermediate.begin(), intermediate.end()); } // enumerateOver Axis axis_; NodeTest* test_; friend class MatchExpr; }; // class TestStepExpression template class ExprStepExpression : public StepExpression { typedef StepExpression baseT; public: ExprStepExpression(XPathExpression_impl* expr, const std::vector*>& predicates) : StepExpression(predicates), expr_(expr) { } // ExprStepExpression virtual ~ExprStepExpression() { delete expr_; } // ExprStepExpression virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { if(!baseT::has_predicates()) return expr_->evaluate(context, executionContext); NodeSet ns = expr_->evaluate(context, executionContext).asNodeSet(); ns.to_document_order(); return XPathValue(new NodeSetValue(baseT::applyPredicates(ns, executionContext))); } // evaluate virtual XPathValue evaluate(NodeSet& context, const ExecutionContext& executionContext) const { DOM::Node c = context.top(); return evaluate(c, executionContext); } // evaluate private: XPathExpression_impl* expr_; std::vector*> predicates_; }; // class ExprStepExpression template class StepFactory { public: static StepExpression* createStep(typename types::node_iter_t& node, typename types::node_iter_t const& end, CompilationContext& context) { Axis axis = getAxis(node); return createStep(node, end, context, axis); } // createStep static StepExpression* createStep(typename types::node_iter_t& node, typename types::node_iter_t const& end, CompilationContext& context, Axis axis, bool is_attr = false) { std::auto_ptr > test(getTest(node, end, !is_attr ? axis : ATTRIBUTE, context.namespaceContext())); std::auto_ptr > thing; if(test.get() == 0) thing.reset(XPath::compile_expression(node++, end, context)); std::vector*> preds = createPredicates(node, end, context); if(test.get() == 0) return new ExprStepExpression(thing.release(), preds); return new TestStepExpression(axis, test.release(), preds); } // createStep static StepExpression* createFilter(const typename types::node_iter_t& node, CompilationContext& context) { typename types::node_iter_t c = node->children.begin(); typename types::node_iter_t const ce = node->children.end(); XPathExpression_impl* step = XPath::compile_expression(c, ce, context); ++c; std::vector*> preds = createPredicates(c, ce, context); return new ExprStepExpression(step, preds); } // createFilter static StepExpression* createSingleStep(typename types::node_iter_t& node, typename types::node_iter_t const& end, CompilationContext& context) { Axis axis = getAxis(node); return createSingleStep(node, end, context, axis); } // createStep static StepExpression* createSingleStep(typename types::node_iter_t& node, typename types::node_iter_t const& end, CompilationContext& context, Axis axis) { NodeTest* test = getTest(node, end, axis, context.namespaceContext()); return new TestStepExpression(axis, test); return 0; } // createStep private: static Axis getAxis(typename types::node_iter_t& node) { long id = getNodeId(node); switch(id) { case impl::Slash_id: case impl::SelfSelect_id: return SELF; // don't advance node, SelfSelect is axis specifier and node test in one case impl::ParentSelect_id: return PARENT; case impl::SlashSlash_id: return DESCENDANT_OR_SELF; case impl::AxisSpecifier_id: { typename types::node_iter_t axis_node = node->children.begin(); skipWhitespace(axis_node); ++node; return getAxis(axis_node); } case impl::AbbreviatedAxisSpecifier_id: case impl::Attribute_id: ++node; return ATTRIBUTE; case impl::AncestorOrSelf_id: ++node; return ANCESTOR_OR_SELF; case impl::Ancestor_id: ++node; return ANCESTOR; case impl::Child_id: ++node; return CHILD; case impl::DescendantOrSelf_id: ++node; return DESCENDANT_OR_SELF; case impl::Descendant_id: ++node; return DESCENDANT; case impl::FollowingSibling_id: ++node; return FOLLOWING_SIBLING; case impl::Following_id: ++node; return FOLLOWING; case impl::Namespace_id: ++node; return NAMESPACE; case impl::Parent_id: ++node; return PARENT; case impl::PrecedingSibling_id: ++node; return PRECEDING_SIBLING; case impl::Preceding_id: ++node; return PRECEDING; case impl::Self_id: ++node; return SELF; default: return CHILD; } // switch(id) return CHILD; } // getAxis static std::vector*> createPredicates(typename types::node_iter_t& node, typename types::node_iter_t const& end, CompilationContext& context) { std::vector*> preds; while((node != end) && (getNodeId(node) == impl::Predicate_id)) { typename types::node_iter_t c = node->children.begin(); assert(getNodeId(c) == impl::LeftSquare_id); ++c; preds.push_back(XPath::compile_expression(c, node->children.end(), context)); ++c; assert(getNodeId(c) == impl::RightSquare_id); ++node; } // if ... return preds; } // createPredicates static NodeTest* getTest(typename types::node_iter_t& node, typename types::node_iter_t const& end, Axis axis, const NamespaceContext& namespaceContext) { long id = getNodeId(skipWhitespace(node)); switch(id) { case impl::NodeTest_id: { typename types::node_iter_t c = node->children.begin(); NodeTest* t = getTest(c, node->children.end(), axis, namespaceContext); ++node; return t; } // case NodeTest_id case impl::QName_id: { typename types::node_iter_t c = node->children.begin(); string_type prefix = string_adaptor::construct(c->value.begin(), c->value.end()); string_type uri = namespaceContext.namespaceURI(prefix); ++c; string_type name = string_adaptor::construct(c->value.begin(), c->value.end()); ++node; if(axis == ATTRIBUTE) { if(prefix == string_adaptor::construct_from_utf8("xmlns")) return new FailNodeTest(); return new AttributeQNameNodeTest(uri, name); } return new QNameNodeTest(uri, name); } //case QName_id case impl::NCName_id: { string_type name = string_adaptor::construct(node->value.begin(), node->value.end()); ++node; if(axis == ATTRIBUTE) { if(name == string_adaptor::construct_from_utf8("xmlns")) return new FailNodeTest(); return new AttributeNameNodeTest(name); } return new NameNodeTest(name); } // case NameNodeTest case impl::Comment_id: { ++node; return new CommentNodeTest(); } // case CommentTest_id case impl::Text_id: { ++node; return new TextNodeTest(); } // case Text_id case impl::ProcessingInstruction_id: { ++node; if((node == end) || (getNodeId(node) != impl::Literal_id)) return new ProcessingInstructionNodeTest(); string_type target = string_adaptor::construct(node->value.begin(), node->value.end()); ++node; return new ProcessingInstructionNodeTest(target); } // case ProcessingInstruction_id case impl::SlashSlash_id: case impl::SelfSelect_id: case impl::ParentSelect_id: case impl::Node_id: { ++node; return new AnyNodeTest(); } // case Node_id case impl::NodeMatchPattern_id: { ++node; return new NodeNodeTest(); } // case NodeMatchPattern_id case impl::Slash_id: return new RootNodeTest(); case impl::AnyName_id: { ++node; if(axis == ATTRIBUTE) return new AttributeNodeTest(); return new StarNodeTest(); } // case AnyName_id: case impl::NameTest_id: { typename types::node_iter_t prefixNode = node->children.begin(); ++node; string_type prefix = string_adaptor::construct(prefixNode->value.begin(), prefixNode->value.end()); string_type uri = namespaceContext.namespaceURI(prefix); if(axis == ATTRIBUTE) { if(prefix == string_adaptor::construct_from_utf8("xmlns")) return new FailNodeTest(); return new AttributeQStarNodeTest(uri); } return new QStarNodeTest(uri); } // case } // switch(id) return 0; } // getTest StepFactory(); }; // class StepFactory template class IdKeyStepExpression : public StepExpression { typedef StepExpression baseT; public: IdKeyStepExpression(XPathExpression_impl* expr) : expr_(expr) { } // IdKeyStepExpression virtual ~IdKeyStepExpression() { delete expr_; } // ~IdKeyStepExpression virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { NodeSet ns; NodeSet nodes = expr_->evaluate(context, executionContext).asNodeSet(); for(typename NodeSet::const_iterator n = nodes.begin(), ne = nodes.end(); n != ne; ++n) if(context == *n) { ns.push_back(context); break; } // if ... return XPathValue(new NodeSetValue(ns)); } // evaluate virtual XPathValue evaluate(NodeSet& context, const ExecutionContext& executionContext) const { DOM::Node c = context.top(); return evaluate(c, executionContext); } // evaluate private: XPathExpression_impl* expr_; }; // class IdKeyStepExpression template class RelativeLocationPath : public XPathExpression_impl { public: RelativeLocationPath(StepExpression* step) : steps_() { steps_.push_back(step); } RelativeLocationPath(const StepList& steps) : steps_(steps) { } virtual ~RelativeLocationPath() { for(typename StepList::const_iterator i = steps_.begin(); i != steps_.end(); ++i) delete *i; } // ~RelativeLocationPath virtual ValueType type() const { return NODE_SET; } virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { NodeSet nodes; nodes.push_back(context); for(typename StepList::const_iterator i = steps_.begin(); i != steps_.end(); ++i) { XPathValue v = (*i)->evaluate(nodes, executionContext); nodes = v.asNodeSet(); } // for ... nodes.sort(); return XPathValue(new NodeSetValue(nodes)); } // evaluate private: StepList steps_; friend class MatchExpr; }; // RelativeLocationPath template class AbsoluteLocationPath : public RelativeLocationPath { public: AbsoluteLocationPath(StepExpression* step) : RelativeLocationPath(step) { } AbsoluteLocationPath(const StepList& steps) : RelativeLocationPath(steps) { } virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { int type = context.getNodeType(); if((type == DOM::Node_base::DOCUMENT_NODE) || (type == DOM::Node_base::DOCUMENT_FRAGMENT_NODE)) return RelativeLocationPath::evaluate(context, executionContext); DOM::Document document = context.getOwnerDocument(); return RelativeLocationPath::evaluate(document, executionContext); } // evaluate }; // class AbsoluteLocationPath } // impl } // XPath } // Arabica #endif