#ifndef ARABICA_XPATHIC_MATCH_REWRITE_HPP #define ARABICA_XPATHIC_MATCH_REWRITE_HPP namespace Arabica { namespace XPath { template class ReplacementExpression : public XPathExpression_impl { public: ReplacementExpression(impl::NodeTest* test, const std::vector*>& preds) { test_ = new impl::TestStepExpression(CHILD, test, preds); } // ReplacementExpression ~ReplacementExpression() { delete test_; } // ~ReplacementExpression virtual ValueType type() const { return BOOL; } virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { DOM::Node parent = context.getParentNode(); NodeSet nodes = test_->evaluateAsNodeSet(parent, executionContext); bool found = false; for(typename NodeSet::const_iterator n = nodes.begin(), ne = nodes.end(); !found && (n != ne); ++n) found = (context == *n); return XPathValue(new BoolValue(found)); } // evaluate private: impl::TestStepExpression* test_; }; // class ReplacementExpression namespace impl { template class PositionFnScanner : public Expression_scanner { public: PositionFnScanner() : found_(false) { } bool found() const { return found_; } virtual void scan(const XPathExpression_impl* const expr) { typedef FunctionHolder FH; const FH* const fn = dynamic_cast(expr); if(fn == 0) return; if(!string_adaptor::empty(fn->namespace_uri())) return; found_ = found_ || ((fn->name() == FN_POSITION) || (fn->name() == FN_LAST)); } // scan private: bool found_; static const string_type FN_POSITION; static const string_type FN_LAST; }; // class PositionFnScanner template const string_type PositionFnScanner::FN_POSITION = string_adaptor::construct_from_utf8("position"); template const string_type PositionFnScanner::FN_LAST = string_adaptor::construct_from_utf8("last"); template bool should_rewrite(XPathExpression_impl* expr) { if(expr->type() == NUMBER) return true; PositionFnScanner scanner; expr->scan(scanner); return scanner.found(); } // should_rewrite } // namespace impl template MatchExpr::MatchExpr(XPathExpression_impl* match, double priority) : match_(match), priority_(priority) { typedef impl::RelativeLocationPath RelativeLocation; typedef impl::StepList StepList; typedef impl::TestStepExpression Step; typedef XPathExpression_impl Expression; typedef std::vector Predicates; // match is a RelativeLocationPath RelativeLocation* path = dynamic_cast(match); // foreach step in the steplist StepList& steps = path->steps_; for(typename StepList::const_iterator s = steps.begin(), se = steps.end(); s != se; ++s) { // foreach predicate in the predicatelist Step* step = dynamic_cast(*s); if(!step || step->has_predicates() == false) continue; Predicates& predicates = step->predicates_; typename Predicates::iterator positional = std::find_if(predicates.begin(), predicates.end(), impl::should_rewrite); while(positional != predicates.end()) { Predicates folding(predicates.begin(), positional+1); Expression* replacement_expression = new ReplacementExpression(step->test_->clone(), folding); // replacement_expression now owns the leading predicates *positional = replacement_expression; // so remove the everyting upto the one we've just replaced predicates.erase(predicates.begin(), positional); positional = std::find_if(predicates.begin(), predicates.end(), impl::should_rewrite); } // while ... } // for(StepList::const_iterator ... } // MatchExpr } // namespace XPath } // namespace Arabica #endif