2005-08-04 22:42:30 +02:00
|
|
|
#ifndef ARABICA_XPATHIC_XPATH_OBJECT_H
|
|
|
|
#define ARABICA_XPATHIC_XPATH_OBJECT_H
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <utility>
|
2007-09-05 00:55:47 +02:00
|
|
|
#include <DOM/Node.hpp>
|
|
|
|
#include <DOM/Attr.hpp>
|
2005-08-04 22:42:30 +02:00
|
|
|
#include <boost/shared_ptr.hpp>
|
2005-08-21 14:48:00 +02:00
|
|
|
#include <boost/lexical_cast.hpp>
|
2005-12-07 17:09:37 +01:00
|
|
|
#ifdef __BORLANDC__
|
|
|
|
#include <math>
|
|
|
|
#endif
|
2005-08-04 22:42:30 +02:00
|
|
|
#include <cmath>
|
2007-09-10 19:52:04 +02:00
|
|
|
#include <Arabica/StringAdaptor.hpp>
|
2007-09-10 19:24:17 +02:00
|
|
|
#include <text/normalize_whitespace.hpp>
|
2005-08-21 14:48:00 +02:00
|
|
|
#include "xpath_axis_enumerator.hpp"
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
namespace Arabica
|
|
|
|
{
|
|
|
|
namespace XPath
|
|
|
|
{
|
|
|
|
|
|
|
|
enum ValueType
|
|
|
|
{
|
|
|
|
ANY ,
|
|
|
|
BOOL,
|
|
|
|
NUMBER,
|
|
|
|
STRING,
|
|
|
|
NODE_SET
|
|
|
|
}; // ValueType
|
|
|
|
|
2005-08-19 18:39:29 +02:00
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////
|
2005-08-22 19:59:18 +02:00
|
|
|
namespace impl
|
|
|
|
{
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
DOM::Node<string_type, string_adaptor> node_parent_or_owner(const DOM::Node<string_type, string_adaptor>& node)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
|
|
|
if(node.getNodeType() == DOM::Node_base::ATTRIBUTE_NODE)
|
2007-09-08 01:52:30 +02:00
|
|
|
return (static_cast<DOM::Attr<string_type, string_adaptor> >(node)).getOwnerElement();
|
2005-08-19 18:39:29 +02:00
|
|
|
return node.getParentNode();
|
|
|
|
} // node_parent_or_owner
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
unsigned int node_attribute_index(const DOM::Attr<string_type, string_adaptor>& attr)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-09-08 01:52:30 +02:00
|
|
|
DOM::NamedNodeMap<string_type, string_adaptor> attrs = attr.getOwnerElement().getAttributes();
|
2005-08-19 18:39:29 +02:00
|
|
|
unsigned int p = 0;
|
|
|
|
for(unsigned int pe = attrs.getLength(); p != pe; ++p)
|
|
|
|
if(attrs.item(p) == attr)
|
|
|
|
break;
|
2008-04-23 16:41:00 +02:00
|
|
|
return p+1;
|
2005-08-19 18:39:29 +02:00
|
|
|
} // node_attribute_index
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
unsigned int node_child_position(const DOM::Node<string_type, string_adaptor>& node)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2008-04-23 16:41:00 +02:00
|
|
|
switch(node.getNodeType())
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2008-04-23 16:41:00 +02:00
|
|
|
case NAMESPACE_NODE_TYPE:
|
|
|
|
return 0;
|
|
|
|
case DOM::Node_base::ATTRIBUTE_NODE:
|
|
|
|
return node_attribute_index(static_cast<DOM::Attr<string_type, string_adaptor> >(node));
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
unsigned int pos = 0;
|
|
|
|
DOM::Node<string_type, string_adaptor> n = node;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
n = n.getPreviousSibling();
|
|
|
|
pos += 1000;
|
|
|
|
} while(n != 0);
|
|
|
|
return pos;
|
|
|
|
} // default
|
|
|
|
} // switch ...
|
2005-08-19 18:39:29 +02:00
|
|
|
} // node_child_position
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
DOM::Node<string_type, string_adaptor> ultimate_parent(const DOM::Node<string_type, string_adaptor>& origin)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-09-08 01:52:30 +02:00
|
|
|
DOM::Node<string_type, string_adaptor> n = origin;
|
|
|
|
DOM::Node<string_type, string_adaptor> p = node_parent_or_owner(n);
|
2005-08-19 18:39:29 +02:00
|
|
|
while(p != 0)
|
|
|
|
{
|
|
|
|
n = p;
|
|
|
|
p = node_parent_or_owner(n);
|
|
|
|
} // while ...
|
|
|
|
return n;
|
|
|
|
} // ultimate_parent
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
int resolve_different_subtrees(const DOM::Node<string_type, string_adaptor>& lhs,
|
|
|
|
const DOM::Node<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
|
|
|
// if we have something in the document, and a document fragment,
|
|
|
|
// sort the doc ahead of the fragment
|
2007-09-08 01:52:30 +02:00
|
|
|
DOM::Node<string_type,string_adaptor> lp = ultimate_parent(lhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
if(lp.getNodeType() == DOM::Node_base::DOCUMENT_NODE)
|
|
|
|
return -1;
|
2007-09-08 01:52:30 +02:00
|
|
|
DOM::Node<string_type, string_adaptor> rp = ultimate_parent(rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
if(rp.getNodeType() == DOM::Node_base::DOCUMENT_NODE)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
// otherwise, sort the frags
|
2008-04-23 16:41:00 +02:00
|
|
|
return (lp.underlying_impl() < lp.underlying_impl()) ? -1 : 1;
|
2005-08-19 18:39:29 +02:00
|
|
|
} // resolve_different_subtrees
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
std::vector<unsigned int> node_position(const DOM::Node<string_type, string_adaptor>& node)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
|
|
|
std::vector<unsigned int> pos;
|
2007-09-08 01:52:30 +02:00
|
|
|
DOM::Node<string_type, string_adaptor> n = node;
|
2005-08-19 18:39:29 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
pos.push_back(node_child_position(n));
|
|
|
|
n = node_parent_or_owner(n);
|
|
|
|
} while(n != 0);
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
} // node_position
|
|
|
|
|
2008-04-17 22:32:32 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
DOM::Node<string_type, string_adaptor> get_owner_document(const DOM::Node<string_type, string_adaptor>& node)
|
|
|
|
{
|
|
|
|
if(node.getNodeType() == DOM::Node_base::DOCUMENT_NODE)
|
|
|
|
return node;
|
|
|
|
return node.getOwnerDocument();
|
|
|
|
} // get_owner_document
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
int compareNodes(const DOM::Node<string_type, string_adaptor>& lhs,
|
|
|
|
const DOM::Node<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
|
|
|
if(lhs == rhs)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// different documents
|
2008-04-17 22:32:32 +02:00
|
|
|
if(get_owner_document(lhs) != get_owner_document(rhs))
|
2008-05-28 17:08:58 +02:00
|
|
|
return (get_owner_document(lhs).underlying_impl() < get_owner_document(rhs).underlying_impl()) ? 1 : -1;
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
// ok, nodes belong to the same document, but do they belong to the document itself, or a document fragment,
|
|
|
|
// or is it just floating free? if they both belong to a document fragment, is it the same fragment?
|
|
|
|
if(ultimate_parent(lhs) != ultimate_parent(rhs))
|
|
|
|
return resolve_different_subtrees(lhs, rhs);
|
|
|
|
|
|
|
|
std::vector<unsigned int> pos1 = node_position(lhs);
|
|
|
|
std::vector<unsigned int> pos2 = node_position(rhs);
|
|
|
|
|
|
|
|
std::vector<unsigned int>::const_reverse_iterator l = pos1.rbegin(), le = pos1.rend();
|
|
|
|
std::vector<unsigned int>::const_reverse_iterator r = pos2.rbegin(), re = pos2.rend();
|
|
|
|
|
|
|
|
while(l != le && r != re)
|
|
|
|
{
|
|
|
|
if(*l != *r)
|
|
|
|
return *l - *r;
|
|
|
|
|
|
|
|
++l;
|
|
|
|
++r;
|
|
|
|
} // while
|
|
|
|
|
|
|
|
if(l != le)
|
|
|
|
return 1;
|
|
|
|
if(r != re)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
} // compareNodes
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
bool nodes_less_than(const DOM::Node<string_type, string_adaptor>& n1,
|
|
|
|
const DOM::Node<string_type, string_adaptor>& n2)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
|
|
|
return compareNodes(n1, n2) < 0;
|
|
|
|
} // nodes_less_than
|
|
|
|
|
2005-08-22 19:59:18 +02:00
|
|
|
} // namespace impl
|
|
|
|
|
2005-08-19 18:39:29 +02:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////
|
2007-09-09 00:31:24 +02:00
|
|
|
template<class string_type, class string_adaptor = Arabica::default_string_adaptor<string_type> >
|
2007-07-19 19:01:31 +02:00
|
|
|
class NodeSet
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
|
|
|
public:
|
2007-09-08 01:52:30 +02:00
|
|
|
typedef typename std::vector<DOM::Node<string_type, string_adaptor> >::const_iterator const_iterator;
|
|
|
|
typedef typename std::vector<DOM::Node<string_type, string_adaptor> >::iterator iterator;
|
2007-10-05 16:56:26 +02:00
|
|
|
typedef typename std::vector<DOM::Node<string_type, string_adaptor> >::value_type value_type;
|
2007-07-19 19:01:31 +02:00
|
|
|
|
2005-08-05 23:02:24 +02:00
|
|
|
NodeSet() :
|
2007-07-19 19:01:31 +02:00
|
|
|
nodes_(),
|
2005-08-05 23:02:24 +02:00
|
|
|
forward_(true),
|
|
|
|
sorted_(false)
|
|
|
|
{
|
|
|
|
} // NodeSet
|
|
|
|
|
|
|
|
NodeSet(bool forward) :
|
2007-07-19 19:01:31 +02:00
|
|
|
nodes_(),
|
2005-08-05 23:02:24 +02:00
|
|
|
forward_(forward),
|
2007-07-19 19:01:31 +02:00
|
|
|
sorted_(false)
|
2005-08-05 23:02:24 +02:00
|
|
|
{
|
|
|
|
} // NodeSet
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
NodeSet(const NodeSet<string_type, string_adaptor>& rhs) :
|
2007-07-19 19:01:31 +02:00
|
|
|
nodes_(rhs.nodes_),
|
2005-08-05 23:02:24 +02:00
|
|
|
forward_(rhs.forward_),
|
|
|
|
sorted_(rhs.sorted_)
|
|
|
|
{
|
|
|
|
} // NodeSet
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
NodeSet& operator=(const NodeSet<string_type, string_adaptor>& rhs)
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
2007-07-19 19:01:31 +02:00
|
|
|
nodes_ = rhs.nodes_;
|
2005-08-04 22:42:30 +02:00
|
|
|
forward_ = rhs.forward_;
|
|
|
|
sorted_ = rhs.sorted_;
|
|
|
|
return *this;
|
|
|
|
} // operator=
|
|
|
|
|
|
|
|
void swap(NodeSet& rhs)
|
|
|
|
{
|
2007-07-19 19:01:31 +02:00
|
|
|
nodes_.swap(rhs.nodes_);
|
2005-08-04 22:42:30 +02:00
|
|
|
std::swap(forward_, rhs.forward_);
|
|
|
|
std::swap(sorted_, rhs.sorted_);
|
|
|
|
} // swap
|
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
const_iterator begin() const { return nodes_.begin(); }
|
|
|
|
const_iterator end() const { return nodes_.end(); }
|
|
|
|
iterator begin() { return nodes_.begin(); }
|
|
|
|
iterator end() { return nodes_.end(); }
|
2007-09-08 01:52:30 +02:00
|
|
|
const DOM::Node<string_type, string_adaptor>& operator[](size_t i) const { return nodes_[i]; }
|
2007-07-19 19:01:31 +02:00
|
|
|
size_t size() const { return nodes_.size(); }
|
|
|
|
bool empty() const { return nodes_.empty(); }
|
|
|
|
|
|
|
|
template<typename InputIterator>
|
|
|
|
void insert(iterator position, InputIterator first, InputIterator last)
|
|
|
|
{
|
|
|
|
sorted_ = false;
|
|
|
|
nodes_.insert(position, first, last);
|
|
|
|
} // insert
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
void push_back(const DOM::Node<string_type, string_adaptor>& node)
|
2007-07-19 19:01:31 +02:00
|
|
|
{
|
|
|
|
nodes_.push_back(node);
|
|
|
|
sorted_ = false;
|
|
|
|
} // push_back
|
|
|
|
|
2005-08-04 22:42:30 +02:00
|
|
|
bool forward() const { return sorted_ && forward_; }
|
|
|
|
bool reverse() const { return sorted_ && !forward_; }
|
2007-07-19 19:01:31 +02:00
|
|
|
void forward(bool forward)
|
|
|
|
{
|
|
|
|
if(forward_ == forward)
|
|
|
|
return;
|
|
|
|
|
|
|
|
forward_ = forward;
|
|
|
|
sorted_ = false;
|
|
|
|
} // forward
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
void to_document_order()
|
|
|
|
{
|
2007-07-19 19:01:31 +02:00
|
|
|
sort();
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
if(!forward_)
|
|
|
|
{
|
2007-07-19 19:01:31 +02:00
|
|
|
std::reverse(nodes_.begin(), nodes_.end());
|
2005-08-04 22:42:30 +02:00
|
|
|
forward_ = true;
|
|
|
|
} // if(!forward_)
|
|
|
|
} // to_document_order
|
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
void sort()
|
|
|
|
{
|
|
|
|
if(sorted_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(forward_)
|
2007-09-08 01:52:30 +02:00
|
|
|
std::sort(nodes_.begin(), nodes_.end(), impl::nodes_less_than<string_type, string_adaptor>);
|
2007-07-19 19:01:31 +02:00
|
|
|
else
|
2007-09-08 01:52:30 +02:00
|
|
|
std::sort(nodes_.rbegin(), nodes_.rend(), impl::nodes_less_than<string_type, string_adaptor>);
|
2007-07-19 19:01:31 +02:00
|
|
|
|
|
|
|
nodes_.erase(std::unique(nodes_.begin(), nodes_.end()), nodes_.end());
|
|
|
|
sorted_ = true;
|
|
|
|
} // sort
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
const DOM::Node<string_type, string_adaptor>& top()
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
2007-07-19 19:01:31 +02:00
|
|
|
sort();
|
2005-08-04 22:42:30 +02:00
|
|
|
if(forward_)
|
|
|
|
return (*this)[0];
|
2007-07-19 19:01:31 +02:00
|
|
|
return (*this)[nodes_.size()-1];
|
2005-08-04 22:42:30 +02:00
|
|
|
} // top()
|
|
|
|
|
|
|
|
private:
|
2007-09-08 01:52:30 +02:00
|
|
|
std::vector<DOM::Node<string_type, string_adaptor> > nodes_;
|
2005-08-04 22:42:30 +02:00
|
|
|
bool forward_;
|
|
|
|
bool sorted_;
|
|
|
|
}; // NodeSet
|
|
|
|
|
2007-09-09 00:31:24 +02:00
|
|
|
template<class string_type, class string_adaptor = Arabica::default_string_adaptor<string_type> >
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
class XPathValue_impl
|
2005-08-04 22:42:30 +02:00
|
|
|
{
|
|
|
|
protected:
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
XPathValue_impl() { }
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
public:
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
virtual ~XPathValue_impl() { }
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
virtual bool asBool() const = 0;
|
|
|
|
virtual double asNumber() const = 0;
|
2005-08-16 17:29:02 +02:00
|
|
|
virtual string_type asString() const = 0;
|
2007-09-08 01:52:30 +02:00
|
|
|
virtual const NodeSet<string_type, string_adaptor>& asNodeSet() const = 0;
|
2005-08-04 22:42:30 +02:00
|
|
|
|
|
|
|
virtual ValueType type() const = 0;
|
|
|
|
|
|
|
|
private:
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
XPathValue_impl(const XPathValue_impl&);
|
|
|
|
bool operator==(const XPathValue_impl&) const;
|
|
|
|
XPathValue_impl& operator=(const XPathValue_impl&);
|
|
|
|
}; // class XPathValue_impl
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
template<class string_type, class string_adaptor> class XPathValuePtr;
|
|
|
|
|
2007-09-09 00:31:24 +02:00
|
|
|
template<class string_type, class string_adaptor = Arabica::default_string_adaptor<string_type> >
|
2007-10-22 19:42:50 +02:00
|
|
|
class XPathValue
|
2005-08-16 13:57:23 +02:00
|
|
|
{
|
|
|
|
public:
|
2007-10-22 19:42:50 +02:00
|
|
|
explicit XPathValue() : ptr_() { }
|
|
|
|
explicit XPathValue(const XPathValue_impl<string_type, string_adaptor>* v) : ptr_(v) { }
|
|
|
|
XPathValue(const XPathValue& rhs) : ptr_(rhs.ptr_) { }
|
|
|
|
XPathValue& operator=(const XPathValue& rhs)
|
2005-11-01 11:08:15 +01:00
|
|
|
{
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
ptr_ = rhs.ptr_;
|
2005-11-01 11:08:15 +01:00
|
|
|
return *this;
|
|
|
|
} // operator=
|
2005-08-16 13:57:23 +02:00
|
|
|
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
bool asBool() const { return ptr_->asBool(); }
|
|
|
|
double asNumber() const { return ptr_->asNumber(); }
|
|
|
|
string_type asString() const { return ptr_->asString(); }
|
|
|
|
const NodeSet<string_type, string_adaptor>& asNodeSet() const { return ptr_->asNodeSet(); }
|
|
|
|
|
|
|
|
ValueType type() const { return ptr_->type(); }
|
|
|
|
|
2007-10-22 16:10:49 +02:00
|
|
|
operator bool() const { return ptr_.get(); }
|
|
|
|
bool operator==(int dummy) const { return (dummy == 0) && (ptr_.get() == 0); }
|
|
|
|
bool operator!=(int dummy) const { return !(operator==(dummy)); }
|
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
private:
|
|
|
|
bool operator==(const XPathValue&) const;
|
|
|
|
|
|
|
|
typedef boost::shared_ptr<const XPathValue_impl<string_type, string_adaptor> > ValuePtr;
|
|
|
|
ValuePtr ptr_;
|
|
|
|
|
|
|
|
explicit XPathValue(ValuePtr ptr) : ptr_(ptr) { }
|
|
|
|
|
2007-10-25 22:58:27 +02:00
|
|
|
friend class XPathValuePtr<string_type, string_adaptor>;
|
2007-10-22 19:42:50 +02:00
|
|
|
}; // class XPathValue
|
|
|
|
|
|
|
|
template<class string_type, class string_adaptor = Arabica::default_string_adaptor<string_type> >
|
|
|
|
class XPathValuePtr
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit XPathValuePtr() : ptr_() { }
|
|
|
|
explicit XPathValuePtr(const XPathValue_impl<string_type, string_adaptor>* v) : ptr_(v) { }
|
|
|
|
XPathValuePtr(const XPathValue<string_type, string_adaptor>& rhs) : ptr_(rhs.ptr_) { }
|
|
|
|
XPathValuePtr(const XPathValuePtr& rhs) : ptr_(rhs.ptr_) { }
|
|
|
|
XPathValuePtr& operator=(const XPathValue<string_type, string_adaptor>& rhs)
|
|
|
|
{
|
|
|
|
ptr_ = rhs.ptr_;
|
|
|
|
return *this;
|
|
|
|
} // operator=
|
|
|
|
XPathValuePtr& operator=(const XPathValuePtr& rhs)
|
|
|
|
{
|
|
|
|
ptr_ = rhs.ptr_;
|
|
|
|
return *this;
|
|
|
|
} // operator=
|
|
|
|
|
|
|
|
const XPathValue_impl<string_type, string_adaptor>* operator->() const { return ptr_.get(); }
|
|
|
|
|
2008-05-28 10:45:25 +02:00
|
|
|
operator bool() const { return (ptr_.get() != 0); }
|
2007-10-22 19:42:50 +02:00
|
|
|
operator XPathValue<string_type, string_adaptor>() const { return XPathValue<string_type, string_adaptor>(ptr_); }
|
|
|
|
|
Some time ago, it was gently suggested to me that XPathValuePtr and XPathExpressionPtr both exposed an implementation detail, because they derive fromboost::shared_ptr, and provided an interface that was inconsisted with the DOM classes, because you accessed the member functions via -> rather than .
At the time, I was just pleased to have got the XPath stuff done and wasn't really fussed, so I left it. Since then though, it's niggled and niggled away at the back of my mind and now I've decided to do something about it.
XPathValuePtr will become XPathValue, with the member functions accessed through the . operator. The XPathValuePtr name and -> member access will be retained for the meantime, so that existing code won't be broken. XPathExpressionPtr will be similarly changed.
This commit is the first bit of that work, now I've satisfied myself it's going to be pretty easy so long as I pay proper attention.
2007-10-19 23:59:24 +02:00
|
|
|
private:
|
|
|
|
bool operator==(const XPathValuePtr&) const;
|
|
|
|
|
|
|
|
typedef boost::shared_ptr<const XPathValue_impl<string_type, string_adaptor> > ValuePtr;
|
|
|
|
ValuePtr ptr_;
|
|
|
|
}; // class XPathValuePtr
|
2005-11-01 11:08:15 +01:00
|
|
|
|
|
|
|
|
2005-08-19 18:39:29 +02:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2005-08-04 22:42:30 +02:00
|
|
|
const double NaN = std::sqrt(-2.0);
|
|
|
|
const double Zero = 0.0;
|
|
|
|
const double Negative_Zero = -Zero;
|
|
|
|
const double Infinity = HUGE_VAL;
|
|
|
|
const double Negative_Infinity = -Infinity;
|
|
|
|
|
|
|
|
inline bool isNaN(double value) { return (value != value); }
|
|
|
|
inline bool isInfinity(double value) { return (value == Infinity); }
|
|
|
|
inline bool isNegativeInfinity(double value) { return (value == Negative_Infinity); }
|
|
|
|
inline bool isInfinite(double value) { return isInfinity(value) || isNegativeInfinity(value); }
|
|
|
|
|
2005-08-22 20:54:53 +02:00
|
|
|
namespace impl
|
|
|
|
{
|
2005-08-04 22:42:30 +02:00
|
|
|
inline double roundNumber(double value)
|
|
|
|
{
|
|
|
|
if(!(isNaN(value) || isInfinite(value) || (std::fabs(value) == 0)))
|
|
|
|
if((value < 0.0) && (value > -0.5))
|
|
|
|
value = -0.0;
|
|
|
|
else
|
|
|
|
value = std::floor(value + 0.5);
|
|
|
|
return value;
|
|
|
|
} // roundNumber
|
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2005-08-16 17:29:02 +02:00
|
|
|
double stringAsNumber(const string_type& str)
|
|
|
|
{
|
|
|
|
try {
|
2007-09-10 19:24:17 +02:00
|
|
|
return boost::lexical_cast<double>(Arabica::text::normalize_whitespace<string_type, string_adaptor>(str));
|
2005-08-16 17:29:02 +02:00
|
|
|
} // try
|
|
|
|
catch(const boost::bad_lexical_cast&) {
|
|
|
|
return NaN;
|
|
|
|
} // catch
|
|
|
|
} // stringAsNumber
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2008-09-13 19:36:46 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
|
|
|
bool nodeIsText(const DOM::Node<string_type, string_adaptor>& node)
|
|
|
|
{
|
|
|
|
return (node.getNodeType() == DOM::Node_base::TEXT_NODE) ||
|
|
|
|
(node.getNodeType() == DOM::Node_base::CDATA_SECTION_NODE);
|
|
|
|
} // nodeIsText
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-09-08 01:52:30 +02:00
|
|
|
string_type nodeStringValue(const DOM::Node<string_type, string_adaptor>& node)
|
2005-08-16 17:29:02 +02:00
|
|
|
{
|
|
|
|
switch(node.getNodeType())
|
|
|
|
{
|
|
|
|
case DOM::Node_base::DOCUMENT_NODE:
|
|
|
|
case DOM::Node_base::DOCUMENT_FRAGMENT_NODE:
|
|
|
|
case DOM::Node_base::ELEMENT_NODE:
|
|
|
|
{
|
2005-10-22 05:17:39 +02:00
|
|
|
std::basic_ostringstream<typename string_adaptor::value_type> os;
|
2005-08-23 21:19:17 +02:00
|
|
|
AxisEnumerator<string_type, string_adaptor> ae(node, DESCENDANT);
|
2005-08-16 17:29:02 +02:00
|
|
|
while(*ae != 0)
|
|
|
|
{
|
2008-09-13 19:36:46 +02:00
|
|
|
if(nodeIsText<string_type, string_adaptor>(*ae))
|
2005-08-16 17:29:02 +02:00
|
|
|
os << ae->getNodeValue();
|
|
|
|
++ae;
|
|
|
|
} // while
|
2005-09-30 23:36:11 +02:00
|
|
|
return string_adaptor::construct(os.str().c_str());
|
2005-08-16 17:29:02 +02:00
|
|
|
} // case
|
|
|
|
|
|
|
|
case DOM::Node_base::ATTRIBUTE_NODE:
|
|
|
|
case DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
|
|
|
|
case DOM::Node_base::COMMENT_NODE:
|
2007-07-19 19:01:31 +02:00
|
|
|
case NAMESPACE_NODE_TYPE:
|
2005-08-16 17:29:02 +02:00
|
|
|
return node.getNodeValue();
|
|
|
|
|
2008-09-13 19:36:46 +02:00
|
|
|
case DOM::Node_base::TEXT_NODE:
|
|
|
|
case DOM::Node_base::CDATA_SECTION_NODE:
|
|
|
|
{
|
|
|
|
DOM::Node<string_type, string_adaptor> next = node.getNextSibling();
|
|
|
|
if((next == 0) ||
|
|
|
|
!nodeIsText<string_type, string_adaptor>(next))
|
|
|
|
return node.getNodeValue();
|
|
|
|
|
|
|
|
std::basic_ostringstream<typename string_adaptor::value_type> os;
|
|
|
|
os << node.getNodeValue()
|
|
|
|
<< nodeStringValue<string_type, string_adaptor>(next);
|
|
|
|
return string_adaptor::construct(os.str().c_str());
|
|
|
|
} // case
|
|
|
|
|
2005-08-16 17:29:02 +02:00
|
|
|
default:
|
2005-09-08 23:43:21 +02:00
|
|
|
throw std::runtime_error("Don't know how to calculate string-value of " +
|
|
|
|
string_adaptor().asStdString(node.getNodeName()));
|
2005-08-16 17:29:02 +02:00
|
|
|
} // switch
|
|
|
|
} // nodeStringValue
|
|
|
|
|
2005-08-25 13:30:23 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-09-08 01:52:30 +02:00
|
|
|
double nodeNumberValue(const DOM::Node<string_type, string_adaptor>& node)
|
2005-08-25 13:30:23 +02:00
|
|
|
{
|
2007-07-19 19:01:31 +02:00
|
|
|
return stringAsNumber<string_type, string_adaptor>(nodeStringValue<string_type, string_adaptor>(node));
|
2005-08-25 13:30:23 +02:00
|
|
|
} // nodeNumberValue
|
|
|
|
|
2005-08-22 20:54:53 +02:00
|
|
|
} // namespace impl
|
|
|
|
|
2005-08-19 18:39:29 +02:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2005-08-22 12:35:43 +02:00
|
|
|
|
|
|
|
namespace impl {
|
2005-08-23 21:19:17 +02:00
|
|
|
template<typename RT, typename string_type, typename string_adaptor> struct value_of_node {
|
2007-09-08 01:52:30 +02:00
|
|
|
RT operator()(const DOM::Node<string_type, string_adaptor>& node) { return nodeStringValue<string_type, string_adaptor>(node); }
|
2005-08-22 12:35:43 +02:00
|
|
|
};
|
2005-08-23 21:19:17 +02:00
|
|
|
template<typename string_type, typename string_adaptor> struct value_of_node<double, string_type, string_adaptor> {
|
2007-09-08 01:52:30 +02:00
|
|
|
double operator()(const DOM::Node<string_type, string_adaptor>& node) { return nodeNumberValue<string_type, string_adaptor>(node); }
|
2005-08-22 12:35:43 +02:00
|
|
|
};
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class Op, class string_type, class string_adaptor>
|
2005-08-19 18:39:29 +02:00
|
|
|
class compareNodeWith
|
|
|
|
{
|
|
|
|
typedef typename Op::first_argument_type T;
|
|
|
|
|
|
|
|
|
2005-08-22 12:15:49 +02:00
|
|
|
public:
|
|
|
|
compareNodeWith(const T& value) : value_(value) { }
|
|
|
|
compareNodeWith(const compareNodeWith& rhs) : value_(rhs.value_) { }
|
|
|
|
|
2007-09-08 01:52:30 +02:00
|
|
|
bool operator()(const DOM::Node<string_type, string_adaptor>& node)
|
2005-08-22 12:15:49 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
value_of_node<T, string_type, string_adaptor> nv;
|
2005-08-22 12:15:49 +02:00
|
|
|
return Op()(nv(node), value_);
|
|
|
|
} // operator()
|
|
|
|
|
|
|
|
private:
|
2005-08-19 18:39:29 +02:00
|
|
|
T value_;
|
|
|
|
bool operator==(const compareNodeWith&);
|
|
|
|
compareNodeWith& operator=(const compareNodeWith&);
|
|
|
|
}; // class compareNodeWith
|
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
template<class string_type, class string_adaptor, class predicate1, class predicate2>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool nodeSetsCompare(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
const NodeSet<string_type, string_adaptor>& lns = lhs.asNodeSet();
|
|
|
|
const NodeSet<string_type, string_adaptor>& rns = rhs.asNodeSet();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lns.size() == 0) || (rns.size() == 0))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::set<string_type> values;
|
2007-09-08 01:52:30 +02:00
|
|
|
typename NodeSet<string_type, string_adaptor>::const_iterator l = lns.begin();
|
2005-08-23 21:19:17 +02:00
|
|
|
string_type lvalue = nodeStringValue<string_type, string_adaptor>(*l);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
predicate1 p1;
|
2007-09-08 01:52:30 +02:00
|
|
|
for(typename NodeSet<string_type, string_adaptor>::const_iterator r = rns.begin(), rend = rns.end(); r != rend; ++r)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
string_type rvalue = nodeStringValue<string_type, string_adaptor>(*r);
|
2007-07-19 19:01:31 +02:00
|
|
|
if(p1(lvalue, rvalue))
|
2005-08-19 18:39:29 +02:00
|
|
|
return true;
|
|
|
|
values.insert(rvalue);
|
|
|
|
} // for ...
|
|
|
|
|
|
|
|
++l;
|
2007-07-19 19:01:31 +02:00
|
|
|
predicate2 p2;
|
2007-09-08 01:52:30 +02:00
|
|
|
for(typename NodeSet<string_type, string_adaptor>::const_iterator lend = lns.end(); l != lend; ++l)
|
2007-07-19 19:01:31 +02:00
|
|
|
if(p2(values.find(nodeStringValue<string_type, string_adaptor>(*l)), values.end()))
|
2005-08-19 18:39:29 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} // nodeSetsEqual
|
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool nodeSetsEqual(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2007-07-19 19:01:31 +02:00
|
|
|
{
|
|
|
|
return nodeSetsCompare<string_type, string_adaptor,
|
|
|
|
std::equal_to<string_type>,
|
|
|
|
std::not_equal_to<typename std::set<string_type>::const_iterator> >(lhs, rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool nodeSetsNotEqual(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2007-07-19 19:01:31 +02:00
|
|
|
{
|
|
|
|
return nodeSetsCompare<string_type, string_adaptor,
|
|
|
|
std::not_equal_to<string_type>,
|
|
|
|
std::equal_to<typename std::set<string_type>::const_iterator> >(lhs, rhs);
|
|
|
|
}
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool nodeSetAndValueEqual(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
const NodeSet<string_type, string_adaptor>& lns = lhs.asNodeSet();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
switch(rhs.type())
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
|
|
|
case BOOL:
|
|
|
|
{
|
|
|
|
bool l = !lns.empty();
|
2007-10-22 19:42:50 +02:00
|
|
|
bool r = rhs.asBool();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
return l == r;
|
|
|
|
} // case BOOL
|
|
|
|
case STRING:
|
|
|
|
return std::find_if(lns.begin(),
|
|
|
|
lns.end(),
|
2007-10-22 19:42:50 +02:00
|
|
|
compareNodeWith<std::equal_to<string_type>, string_type, string_adaptor>(rhs.asString())) != lns.end();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
case NUMBER:
|
|
|
|
return std::find_if(lns.begin(),
|
|
|
|
lns.end(),
|
2007-10-22 19:42:50 +02:00
|
|
|
compareNodeWith<std::equal_to<double>, string_type, string_adaptor>(rhs.asNumber())) != lns.end();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
default:
|
2007-10-22 19:42:50 +02:00
|
|
|
throw std::runtime_error("Node set == not yet implemented for type " + boost::lexical_cast<std::string>(rhs.type()));
|
2005-08-19 18:39:29 +02:00
|
|
|
} // switch
|
|
|
|
} // nodeSetAndValueEqual
|
|
|
|
|
2007-07-19 19:01:31 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool nodeSetAndValueNotEqual(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2007-07-19 19:01:31 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
const NodeSet<string_type, string_adaptor>& lns = lhs.asNodeSet();
|
2007-07-19 19:01:31 +02:00
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
switch(rhs.type())
|
2007-07-19 19:01:31 +02:00
|
|
|
{
|
|
|
|
case BOOL:
|
|
|
|
{
|
|
|
|
bool l = !lns.empty();
|
2007-10-22 19:42:50 +02:00
|
|
|
bool r = rhs.asBool();
|
2007-07-19 19:01:31 +02:00
|
|
|
|
|
|
|
return l != r;
|
|
|
|
} // case BOOL
|
|
|
|
case STRING:
|
|
|
|
return std::find_if(lns.begin(),
|
|
|
|
lns.end(),
|
2007-10-22 19:42:50 +02:00
|
|
|
compareNodeWith<std::not_equal_to<string_type>, string_type, string_adaptor>(rhs.asString())) != lns.end();
|
2007-07-19 19:01:31 +02:00
|
|
|
|
|
|
|
case NUMBER:
|
|
|
|
return std::find_if(lns.begin(),
|
|
|
|
lns.end(),
|
2007-10-22 19:42:50 +02:00
|
|
|
compareNodeWith<std::not_equal_to<double>, string_type, string_adaptor>(rhs.asNumber())) != lns.end();
|
2007-07-19 19:01:31 +02:00
|
|
|
|
|
|
|
default:
|
2007-10-22 19:42:50 +02:00
|
|
|
throw std::runtime_error("Node set == not yet implemented for type " + boost::lexical_cast<std::string>(rhs.type()));
|
2007-07-19 19:01:31 +02:00
|
|
|
} // switch
|
|
|
|
} // nodeSetAndValueNotEqual
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-09-08 01:52:30 +02:00
|
|
|
double minValue(const NodeSet<string_type, string_adaptor>& ns)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
double v = nodeNumberValue<string_type, string_adaptor>(ns[0]);
|
2007-09-08 01:52:30 +02:00
|
|
|
for(typename NodeSet<string_type, string_adaptor>::const_iterator i = ns.begin(), ie = ns.end(); i != ie; ++i)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
double vt = nodeNumberValue<string_type, string_adaptor>(*i);
|
2005-08-19 18:39:29 +02:00
|
|
|
if(isNaN(vt))
|
|
|
|
continue;
|
|
|
|
if(!(vt > v)) // looks weird, but should account for infinity
|
|
|
|
v = vt;
|
|
|
|
} // for ...
|
|
|
|
return v;
|
|
|
|
} // minValue
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-09-08 01:52:30 +02:00
|
|
|
double maxValue(const NodeSet<string_type, string_adaptor>& ns)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
double v = nodeNumberValue<string_type, string_adaptor>(ns[0]);
|
2007-09-08 01:52:30 +02:00
|
|
|
for(typename NodeSet<string_type, string_adaptor>::const_iterator i = ns.begin(), ie = ns.end(); i != ie; ++i)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
double vt = nodeNumberValue<string_type, string_adaptor>(*i);
|
2005-08-19 18:39:29 +02:00
|
|
|
if(isNaN(vt))
|
|
|
|
continue;
|
|
|
|
if(!(vt < v))
|
|
|
|
v = vt;
|
|
|
|
} // for ...
|
|
|
|
return v;
|
|
|
|
} // maxValue
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class Op, class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool compareNodeSets(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
return Op()(minValue<string_type, string_adaptor>(lhs.asNodeSet()), maxValue<string_type, string_adaptor>(rhs.asNodeSet()));
|
2005-08-19 18:39:29 +02:00
|
|
|
} // compareNodeSets
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class Op, class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool compareNodeSetWith(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
const NodeSet<string_type, string_adaptor>& lns = lhs.asNodeSet();
|
2005-08-19 18:39:29 +02:00
|
|
|
return std::find_if(lns.begin(),
|
|
|
|
lns.end(),
|
2007-10-22 19:42:50 +02:00
|
|
|
compareNodeWith<Op, string_type, string_adaptor>(rhs.asNumber())) != lns.end();
|
2005-08-19 18:39:29 +02:00
|
|
|
} // compareNodeSetAndValue
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool areEqual(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
ValueType lt = lhs.type();
|
|
|
|
ValueType rt = rhs.type();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lt == NODE_SET) && (rt == NODE_SET))
|
2005-08-23 21:19:17 +02:00
|
|
|
return nodeSetsEqual<string_type, string_adaptor>(lhs, rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if(lt == NODE_SET)
|
2005-08-23 21:19:17 +02:00
|
|
|
return nodeSetAndValueEqual<string_type, string_adaptor>(lhs, rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
if(rt == NODE_SET)
|
2005-08-23 21:19:17 +02:00
|
|
|
return nodeSetAndValueEqual<string_type, string_adaptor>(rhs, lhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lt == BOOL) || (rt == BOOL))
|
2007-10-22 19:42:50 +02:00
|
|
|
return lhs.asBool() == rhs.asBool();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lt == NUMBER) || (rt == NUMBER))
|
2007-10-22 19:42:50 +02:00
|
|
|
return lhs.asNumber() == rhs.asNumber();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lt == STRING) || (rt == STRING))
|
2007-10-22 19:42:50 +02:00
|
|
|
return lhs.asString() == rhs.asString();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
return false;
|
2007-07-19 19:01:31 +02:00
|
|
|
} // areEqual
|
|
|
|
|
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool areNotEqual(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2007-07-19 19:01:31 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
ValueType lt = lhs.type();
|
|
|
|
ValueType rt = rhs.type();
|
2007-07-19 19:01:31 +02:00
|
|
|
|
|
|
|
if((lt == NODE_SET) && (rt == NODE_SET))
|
|
|
|
return nodeSetsNotEqual<string_type, string_adaptor>(lhs, rhs);
|
|
|
|
|
|
|
|
if(lt == NODE_SET)
|
|
|
|
return nodeSetAndValueNotEqual<string_type, string_adaptor>(lhs, rhs);
|
|
|
|
|
|
|
|
if(rt == NODE_SET)
|
|
|
|
return nodeSetAndValueNotEqual<string_type, string_adaptor>(rhs, lhs);
|
|
|
|
|
|
|
|
return !areEqual<string_type, string_adaptor>(lhs, rhs);
|
|
|
|
} // areNotEqual
|
2005-08-19 18:39:29 +02:00
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool isLessThan(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
ValueType lt = lhs.type();
|
|
|
|
ValueType rt = rhs.type();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lt == NODE_SET) && (rt == NODE_SET))
|
2005-08-23 21:19:17 +02:00
|
|
|
return compareNodeSets<std::less<double>, string_type, string_adaptor>(lhs, rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if(lt == NODE_SET)
|
2005-08-23 21:19:17 +02:00
|
|
|
return compareNodeSetWith<std::less<double>, string_type, string_adaptor>(lhs, rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if(rt == NODE_SET)
|
2005-08-23 21:19:17 +02:00
|
|
|
return compareNodeSetWith<std::greater<double>, string_type, string_adaptor>(rhs, lhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
return lhs.asNumber() < rhs.asNumber();
|
2005-08-19 18:39:29 +02:00
|
|
|
} // isLessThan
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool isLessThanEquals(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2007-10-22 19:42:50 +02:00
|
|
|
ValueType lt = lhs.type();
|
|
|
|
ValueType rt = rhs.type();
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if((lt == NODE_SET) && (rt == NODE_SET))
|
2005-08-23 21:19:17 +02:00
|
|
|
return compareNodeSets<std::less_equal<double>, string_type, string_adaptor>(lhs, rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if(lt == NODE_SET)
|
2005-08-23 21:19:17 +02:00
|
|
|
return compareNodeSetWith<std::less_equal<double>, string_type, string_adaptor>(lhs, rhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
|
|
|
if(rt == NODE_SET)
|
2005-08-23 21:19:17 +02:00
|
|
|
return compareNodeSetWith<std::greater_equal<double>, string_type, string_adaptor>(rhs, lhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
return lhs.asNumber() <= rhs.asNumber();
|
2005-08-19 18:39:29 +02:00
|
|
|
} // isLessThanEquals
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool isGreaterThan(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
return isLessThan<string_type, string_adaptor>(rhs, lhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
} // isGreaterThan
|
|
|
|
|
2005-08-23 21:19:17 +02:00
|
|
|
template<class string_type, class string_adaptor>
|
2007-10-22 19:42:50 +02:00
|
|
|
bool isGreaterThanEquals(const XPathValue<string_type, string_adaptor>& lhs, const XPathValue<string_type, string_adaptor>& rhs)
|
2005-08-19 18:39:29 +02:00
|
|
|
{
|
2005-08-23 21:19:17 +02:00
|
|
|
return isLessThanEquals<string_type, string_adaptor>(rhs, lhs);
|
2005-08-19 18:39:29 +02:00
|
|
|
} // isGreaterThanEquals
|
2005-08-04 22:42:30 +02:00
|
|
|
|
2005-08-22 17:35:20 +02:00
|
|
|
} // namespace impl
|
2005-08-04 22:42:30 +02:00
|
|
|
} // namespace XPath
|
|
|
|
} // namespace Arabica
|
|
|
|
|
|
|
|
#endif
|