arabica/include/XPath/impl/xpath_match_rewrite.hpp

128 lines
5 KiB
C++
Executable file

#ifndef ARABICA_XPATHIC_MATCH_REWRITE_HPP
#define ARABICA_XPATHIC_MATCH_REWRITE_HPP
namespace Arabica
{
namespace XPath
{
template<class string_type, class string_adaptor>
class ReplacementExpression : public XPathExpression_impl<string_type, string_adaptor>
{
public:
ReplacementExpression(impl::NodeTest<string_type, string_adaptor>* test,
const std::vector<XPathExpression_impl<string_type, string_adaptor>*>& preds)
{
test_ = new impl::TestStepExpression<string_type, string_adaptor>(CHILD, test, preds);
} // ReplacementExpression
~ReplacementExpression()
{
delete test_;
} // ~ReplacementExpression
virtual ValueType type() const { return BOOL; }
virtual XPathValue<string_type, string_adaptor> evaluate(const DOM::Node<string_type, string_adaptor>& context,
const ExecutionContext<string_type, string_adaptor>& executionContext) const
{
DOM::Node<string_type, string_adaptor> parent = context.getParentNode();
NodeSet<string_type, string_adaptor> nodes = test_->evaluateAsNodeSet(parent, executionContext);
bool found = false;
for(typename NodeSet<string_type, string_adaptor>::const_iterator n = nodes.begin(), ne = nodes.end();
!found && (n != ne); ++n)
found = (context == *n);
return XPathValue<string_type, string_adaptor>(new BoolValue<string_type, string_adaptor>(found));
} // evaluate
private:
impl::TestStepExpression<string_type, string_adaptor>* test_;
}; // class ReplacementExpression
namespace impl
{
template<class string_type, class string_adaptor>
class PositionFnScanner : public Expression_scanner<string_type, string_adaptor>
{
public:
PositionFnScanner() : found_(false) { }
bool found() const { return found_; }
virtual void scan(const XPathExpression_impl<string_type, string_adaptor>* const expr)
{
typedef FunctionHolder<string_type, string_adaptor> FH;
const FH* const fn = dynamic_cast<const FH* const>(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<class string_type, class string_adaptor>
const string_type PositionFnScanner<string_type, string_adaptor>::FN_POSITION = string_adaptor::construct_from_utf8("position");
template<class string_type, class string_adaptor>
const string_type PositionFnScanner<string_type, string_adaptor>::FN_LAST = string_adaptor::construct_from_utf8("last");
template<class string_type, class string_adaptor>
bool should_rewrite(XPathExpression_impl<string_type, string_adaptor>* expr)
{
if(expr->type() == NUMBER)
return true;
PositionFnScanner<string_type, string_adaptor> scanner;
expr->scan(scanner);
return scanner.found();
} // should_rewrite
} // namespace impl
template<class string_type, class string_adaptor>
MatchExpr<string_type, string_adaptor>::MatchExpr(XPathExpression_impl<string_type, string_adaptor>* match, double priority) :
match_(match), priority_(priority)
{
typedef impl::RelativeLocationPath<string_type, string_adaptor> RelativeLocation;
typedef impl::StepList<string_type, string_adaptor> StepList;
typedef impl::TestStepExpression<string_type, string_adaptor> Step;
typedef XPathExpression_impl<string_type, string_adaptor> Expression;
typedef std::vector<Expression*> Predicates;
// match is a RelativeLocationPath
RelativeLocation* path = dynamic_cast<RelativeLocation*>(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<Step*>(*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<string_type, string_adaptor>);
while(positional != predicates.end())
{
Predicates folding(predicates.begin(), positional+1);
Expression* replacement_expression = new ReplacementExpression<string_type, string_adaptor>(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<string_type, string_adaptor>);
} // while ...
} // for(StepList::const_iterator ...
} // MatchExpr
} // namespace XPath
} // namespace Arabica
#endif