2005-08-04 22:42:30 +02:00
|
|
|
#ifndef ARABICA_XPATHIC_XPATH_UNION_HPP
|
|
|
|
#define ARABICA_XPATHIC_XPATH_UNION_HPP
|
|
|
|
|
|
|
|
#include "xpath_value.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
namespace Arabica
|
|
|
|
{
|
|
|
|
namespace XPath
|
|
|
|
{
|
|
|
|
|
2005-08-17 12:13:05 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
class UnionExpression : private BinaryExpression<string_type, string_adaptor>,
|
|
|
|
public XPathExpression<string_type, string_adaptor>
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
2005-08-17 12:13:05 +02:00
|
|
|
typedef BinaryExpression<string_type, string_adaptor> baseT;
|
2005-08-04 22:42:30 +02:00
|
|
|
public:
|
2005-08-17 12:13:05 +02:00
|
|
|
UnionExpression(XPathExpression<string_type, string_adaptor>* lhs,
|
|
|
|
XPathExpression<string_type, string_adaptor>* rhs) :
|
|
|
|
BinaryExpression<string_type, string_adaptor>(lhs, rhs) { }
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2005-08-16 23:07:05 +02:00
|
|
|
virtual XPathValuePtr<string_type> evaluate(const DOM::Node<string_type>& context,
|
2005-08-17 12:13:05 +02:00
|
|
|
const ExecutionContext<string_type, string_adaptor>& executionContext) const
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
2005-08-16 23:07:05 +02:00
|
|
|
XPathValuePtr<string_type> p1 = baseT::lhs()->evaluate(context, executionContext);
|
2005-08-04 22:42:30 +02:00
|
|
|
if(p1->type() != NODE_SET)
|
|
|
|
throw RuntimeException("Union operator joins node-sets. First argument is not a node-set.");
|
2005-08-16 23:07:05 +02:00
|
|
|
XPathValuePtr<string_type> p2 = baseT::rhs()->evaluate(context, executionContext);
|
2005-08-04 22:42:30 +02:00
|
|
|
if(p2->type() != NODE_SET)
|
2005-08-16 18:04:24 +02:00
|
|
|
throw RuntimeException("Union operator joins node-sets. Second argument is not a node-set.");
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2005-08-16 23:07:05 +02:00
|
|
|
NodeSet<string_type> ns1(p1->asNodeSet());
|
|
|
|
NodeSet<string_type> ns2(p2->asNodeSet());
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
// do the obvious optimizations
|
|
|
|
if(ns1.empty())
|
|
|
|
return wrap(ns2);
|
|
|
|
if(ns2.empty())
|
|
|
|
return wrap(ns1);
|
|
|
|
|
|
|
|
ns1.to_document_order();
|
|
|
|
ns2.to_document_order();
|
2005-08-21 14:48:00 +02:00
|
|
|
typename NodeSet<string_type>::const_iterator n1 = ns1.begin(), n1e = ns1.end();
|
|
|
|
typename NodeSet<string_type>::const_iterator n2 = ns2.begin(), n2e = ns2.end();
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2005-08-16 23:07:05 +02:00
|
|
|
NodeSet<string_type> result(true);
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
while((n1 != n1e) && (n2 != n2e))
|
|
|
|
{
|
|
|
|
int c = compareNodes(*n1, *n2);
|
|
|
|
if(c < 0)
|
|
|
|
result.push_back(*n1++);
|
|
|
|
else if(c > 0)
|
|
|
|
result.push_back(*n2++);
|
|
|
|
else
|
|
|
|
{ // same node, so bin out duplicate
|
|
|
|
result.push_back(*n1++);
|
|
|
|
++n2;
|
|
|
|
} // if ...
|
|
|
|
} // while ...
|
|
|
|
|
|
|
|
// pop on any left overs, leftovers
|
|
|
|
std::copy(n1, n1e, std::back_inserter(result));
|
|
|
|
std::copy(n2, n2e, std::back_inserter(result));
|
|
|
|
|
|
|
|
return wrap(result);
|
|
|
|
} // evaluate
|
|
|
|
|
|
|
|
private:
|
2005-08-16 23:07:05 +02:00
|
|
|
XPathValuePtr<string_type> wrap(const NodeSet<string_type>& ns) const
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
2005-08-17 12:13:05 +02:00
|
|
|
return XPathValuePtr<string_type>(new NodeSetValue<string_type, string_adaptor>(ns));
|
2005-08-04 22:42:30 +02:00
|
|
|
} // wrap
|
|
|
|
}; // UnionExpression
|
|
|
|
|
|
|
|
} // namespace XPath
|
|
|
|
|
|
|
|
} // namespace Arabica
|
|
|
|
#endif
|