mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-26 21:58:39 +01:00
128 lines
5 KiB
C++
Executable file
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
|