mirror of
https://github.com/jezhiggins/arabica
synced 2025-01-29 08:36:45 +01:00
parameterised all of xpath_object.hpp
This commit is contained in:
parent
8c745fa53d
commit
97e9414b73
4 changed files with 332 additions and 334 deletions
|
@ -496,9 +496,6 @@
|
|||
<File
|
||||
RelativePath="..\XPath\impl\xpath_node_test.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\XPath\src\xpath_object.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\XPath\impl\xpath_object.hpp">
|
||||
</File>
|
||||
|
|
|
@ -26,7 +26,7 @@ DONE - xpath_logical.hpp
|
|||
DONE - xpath_namespace_context.hpp
|
||||
DONE - xpath_namespace_node.hpp
|
||||
DONE - xpath_node_test.hpp
|
||||
xpath_object.hpp
|
||||
DONE - xpath_object.hpp
|
||||
xpath_parser.hpp
|
||||
DONE - xpath_relational.hpp
|
||||
DONE - xpath_resolver_holder.hpp
|
||||
|
@ -36,7 +36,7 @@ DONE - xpath_value.hpp
|
|||
DONE - xpath_variable.hpp
|
||||
DONE - xpath_variable_resolver.hpp
|
||||
|
||||
xpath_axis_enumerator.cpp
|
||||
GONE - xpath_axis_enumerator.cpp
|
||||
xpath_object.cpp
|
||||
GONE - xpath_parser.cpp
|
||||
*/
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <vector>
|
||||
#include <utility>
|
||||
#include <DOM/Node.h>
|
||||
#include <DOM/Attr.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
@ -22,9 +23,131 @@ enum ValueType
|
|||
NODE_SET
|
||||
}; // ValueType
|
||||
|
||||
int compareNodes(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2);
|
||||
bool nodes_less_than(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2);
|
||||
///////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
template<class string_type>
|
||||
DOM::Node<string_type> node_parent_or_owner(const DOM::Node<string_type>& node)
|
||||
{
|
||||
if(node.getNodeType() == DOM::Node_base::ATTRIBUTE_NODE)
|
||||
return (static_cast<DOM::Attr<string_type> >(node)).getOwnerElement();
|
||||
return node.getParentNode();
|
||||
} // node_parent_or_owner
|
||||
|
||||
template<class string_type>
|
||||
unsigned int node_attribute_index(const DOM::Attr<string_type>& attr)
|
||||
{
|
||||
DOM::NamedNodeMap<string_type> attrs = attr.getOwnerElement().getAttributes();
|
||||
unsigned int p = 0;
|
||||
for(unsigned int pe = attrs.getLength(); p != pe; ++p)
|
||||
if(attrs.item(p) == attr)
|
||||
break;
|
||||
return p;
|
||||
} // node_attribute_index
|
||||
|
||||
template<class string_type>
|
||||
unsigned int node_child_position(const DOM::Node<string_type>& node)
|
||||
{
|
||||
if(node.getNodeType() == DOM::Node_base::ATTRIBUTE_NODE)
|
||||
return node_attribute_index(static_cast<DOM::Attr<string_type> >(node));
|
||||
|
||||
unsigned int pos = 0;
|
||||
DOM::Node<string_type> n = node;
|
||||
do
|
||||
{
|
||||
n = n.getPreviousSibling();
|
||||
pos += 1000;
|
||||
} while(n != 0);
|
||||
return pos;
|
||||
} // node_child_position
|
||||
|
||||
template<class string_type>
|
||||
DOM::Node<string_type> ultimate_parent(const DOM::Node<string_type>& origin)
|
||||
{
|
||||
DOM::Node<string_type> n = origin;
|
||||
DOM::Node<string_type> p = node_parent_or_owner(n);
|
||||
while(p != 0)
|
||||
{
|
||||
n = p;
|
||||
p = node_parent_or_owner(n);
|
||||
} // while ...
|
||||
return n;
|
||||
} // ultimate_parent
|
||||
|
||||
template<class string_type>
|
||||
int resolve_different_subtrees(const DOM::Node<string_type>& lhs, const DOM::Node<string_type>& rhs)
|
||||
{
|
||||
// if we have something in the document, and a document fragment,
|
||||
// sort the doc ahead of the fragment
|
||||
DOM::Node<string_type> lp = ultimate_parent(lhs);
|
||||
if(lp.getNodeType() == DOM::Node_base::DOCUMENT_NODE)
|
||||
return -1;
|
||||
DOM::Node<string_type> rp = ultimate_parent(rhs);
|
||||
if(rp.getNodeType() == DOM::Node_base::DOCUMENT_NODE)
|
||||
return 1;
|
||||
|
||||
// otherwise, sort the frags
|
||||
return (lp.unlying_impl() < lp.unlying_impl()) ? -1 : 1;
|
||||
} // resolve_different_subtrees
|
||||
|
||||
template<class string_type>
|
||||
std::vector<unsigned int> node_position(const DOM::Node<string_type>& node)
|
||||
{
|
||||
std::vector<unsigned int> pos;
|
||||
DOM::Node<string_type> n = node;
|
||||
do
|
||||
{
|
||||
pos.push_back(node_child_position(n));
|
||||
n = node_parent_or_owner(n);
|
||||
} while(n != 0);
|
||||
|
||||
return pos;
|
||||
} // node_position
|
||||
|
||||
template<class string_type>
|
||||
int compareNodes(const DOM::Node<string_type>& lhs, const DOM::Node<string_type>& rhs)
|
||||
{
|
||||
if(lhs == rhs)
|
||||
return 0;
|
||||
|
||||
// different documents
|
||||
if(lhs.getOwnerDocument() != rhs.getOwnerDocument())
|
||||
return (lhs.getOwnerDocument().unlying_impl() < rhs.getOwnerDocument().unlying_impl()) ? -1 : 1;
|
||||
|
||||
// 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
|
||||
|
||||
template<class string_type>
|
||||
bool nodes_less_than(const DOM::Node<string_type>& n1, const DOM::Node<string_type>& n2)
|
||||
{
|
||||
return compareNodes(n1, n2) < 0;
|
||||
} // nodes_less_than
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
template<class string_type>
|
||||
class NodeSet : public std::vector<DOM::Node<string_type> >
|
||||
{
|
||||
|
@ -75,7 +198,7 @@ public:
|
|||
{
|
||||
if(!sorted_)
|
||||
{
|
||||
std::sort(baseT::begin(), baseT::end(), nodes_less_than);
|
||||
std::sort(baseT::begin(), baseT::end(), nodes_less_than<string_type>);
|
||||
sorted_ = true;
|
||||
forward_ = true;
|
||||
} // if(!sorted)
|
||||
|
@ -126,8 +249,10 @@ class XPathValuePtr : public boost::shared_ptr<const XPathValue<string_type> >
|
|||
{
|
||||
public:
|
||||
explicit XPathValuePtr(const XPathValue<string_type>* v) : boost::shared_ptr<const XPathValue<string_type> >(v) { }
|
||||
};
|
||||
}; // class XPathValuePtr
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const double NaN = std::sqrt(-2.0);
|
||||
const double Zero = 0.0;
|
||||
const double Negative_Zero = -Zero;
|
||||
|
@ -199,11 +324,207 @@ string_type nodeStringValue(const DOM::Node<string_type>& node)
|
|||
} // switch
|
||||
} // nodeStringValue
|
||||
|
||||
template<class string_type> bool areEqual(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs);
|
||||
template<class string_type> bool isLessThan(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs);
|
||||
template<class string_type> bool isLessThanEquals(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs);
|
||||
template<class string_type> bool isGreaterThan(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs);
|
||||
template<class string_type> bool isGreaterThanEquals(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs);
|
||||
////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class Op, class string_type>
|
||||
class compareNodeWith
|
||||
{
|
||||
typedef typename Op::first_argument_type T;
|
||||
public:
|
||||
compareNodeWith(const T& value) : value_(value) { }
|
||||
compareNodeWith(const compareNodeWith& rhs) : value_(rhs.value_) { }
|
||||
|
||||
bool operator()(const DOM::Node<string_type>& node)
|
||||
{
|
||||
return Op()(nodeValue<T>(node), value_);
|
||||
} // operator()
|
||||
|
||||
template<class RT> RT nodeValue(const DOM::Node<string_type>& node);
|
||||
template<> string_type nodeValue(const DOM::Node<string_type>& node){ return nodeStringValue(node); }
|
||||
template<> double nodeValue(const DOM::Node<string_type>& node) { return nodeNumberValue(node); }
|
||||
|
||||
private:
|
||||
T value_;
|
||||
bool operator==(const compareNodeWith&);
|
||||
compareNodeWith& operator=(const compareNodeWith&);
|
||||
}; // class compareNodeWith
|
||||
|
||||
template<class string_type>
|
||||
bool nodeSetsEqual(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
const NodeSet<string_type>& lns = lhs->asNodeSet();
|
||||
const NodeSet<string_type>& rns = rhs->asNodeSet();
|
||||
|
||||
if((lns.size() == 0) || (rns.size() == 0))
|
||||
return false;
|
||||
|
||||
std::set<string_type> values;
|
||||
NodeSet<string_type>::const_iterator l = lns.begin();
|
||||
string_type lvalue = nodeStringValue(*l);
|
||||
|
||||
for(NodeSet<string_type>::const_iterator r = rns.begin(), rend = rns.end(); r != rend; ++r)
|
||||
{
|
||||
string_type rvalue = nodeStringValue(*r);
|
||||
if(lvalue == rvalue)
|
||||
return true;
|
||||
values.insert(rvalue);
|
||||
} // for ...
|
||||
|
||||
++l;
|
||||
for(NodeSet<string_type>::const_iterator lend = lns.end(); l != lend; ++l)
|
||||
if(values.find(nodeStringValue(*l)) != values.end())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} // nodeSetsEqual
|
||||
|
||||
template<class string_type>
|
||||
bool nodeSetAndValueEqual(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
const NodeSet<string_type>& lns = lhs->asNodeSet();
|
||||
|
||||
switch(rhs->type())
|
||||
{
|
||||
case BOOL:
|
||||
{
|
||||
bool l = !lns.empty();
|
||||
bool r = rhs->asBool();
|
||||
|
||||
return l == r;
|
||||
} // case BOOL
|
||||
case STRING:
|
||||
return std::find_if(lns.begin(),
|
||||
lns.end(),
|
||||
compareNodeWith<std::equal_to<string_type>, string_type>(rhs->asString())) != lns.end();
|
||||
|
||||
case NUMBER:
|
||||
return std::find_if(lns.begin(),
|
||||
lns.end(),
|
||||
compareNodeWith<std::equal_to<double>, string_type>(rhs->asNumber())) != lns.end();
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Node set == not yet implemented for type " + boost::lexical_cast<std::string>(rhs->type()));
|
||||
} // switch
|
||||
} // nodeSetAndValueEqual
|
||||
|
||||
template<class string_type>
|
||||
double minValue(const NodeSet<string_type>& ns)
|
||||
{
|
||||
double v = nodeNumberValue(ns[0]);
|
||||
for(NodeSet<string_type>::const_iterator i = ns.begin(), ie = ns.end(); i != ie; ++i)
|
||||
{
|
||||
double vt = nodeNumberValue(*i);
|
||||
if(isNaN(vt))
|
||||
continue;
|
||||
if(!(vt > v)) // looks weird, but should account for infinity
|
||||
v = vt;
|
||||
} // for ...
|
||||
return v;
|
||||
} // minValue
|
||||
|
||||
template<class string_type>
|
||||
double maxValue(const NodeSet<string_type>& ns)
|
||||
{
|
||||
double v = nodeNumberValue(ns[0]);
|
||||
for(NodeSet<string_type>::const_iterator i = ns.begin(), ie = ns.end(); i != ie; ++i)
|
||||
{
|
||||
double vt = nodeNumberValue(*i);
|
||||
if(isNaN(vt))
|
||||
continue;
|
||||
if(!(vt < v))
|
||||
v = vt;
|
||||
} // for ...
|
||||
return v;
|
||||
} // maxValue
|
||||
|
||||
template<class Op, class string_type>
|
||||
bool compareNodeSets(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
return Op()(minValue(lhs->asNodeSet()), maxValue(rhs->asNodeSet()));
|
||||
} // compareNodeSets
|
||||
|
||||
template<class Op, class string_type>
|
||||
bool compareNodeSetWith(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
const NodeSet<string_type>& lns = lhs->asNodeSet();
|
||||
return std::find_if(lns.begin(),
|
||||
lns.end(),
|
||||
compareNodeWith<Op, string_type>(rhs->asNumber())) != lns.end();
|
||||
} // compareNodeSetAndValue
|
||||
|
||||
template<class string_type>
|
||||
bool areEqual(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
ValueType lt = lhs->type();
|
||||
ValueType rt = rhs->type();
|
||||
|
||||
if((lt == NODE_SET) && (rt == NODE_SET))
|
||||
return nodeSetsEqual(lhs, rhs);
|
||||
|
||||
if(lt == NODE_SET)
|
||||
return nodeSetAndValueEqual(lhs, rhs);
|
||||
if(rt == NODE_SET)
|
||||
return nodeSetAndValueEqual(rhs, lhs);
|
||||
|
||||
if((lt == BOOL) || (rt == BOOL))
|
||||
return lhs->asBool() == rhs->asBool();
|
||||
|
||||
if((lt == NUMBER) || (rt == NUMBER))
|
||||
return lhs->asNumber() == rhs->asNumber();
|
||||
|
||||
if((lt == STRING) || (rt == STRING))
|
||||
return lhs->asString() == rhs->asString();
|
||||
|
||||
return false;
|
||||
} // areEquals
|
||||
|
||||
template<class string_type>
|
||||
bool isLessThan(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
ValueType lt = lhs->type();
|
||||
ValueType rt = rhs->type();
|
||||
|
||||
if((lt == NODE_SET) && (rt == NODE_SET))
|
||||
return compareNodeSets<std::less<double> >(lhs, rhs);
|
||||
|
||||
if(lt == NODE_SET)
|
||||
return compareNodeSetWith<std::less<double> >(lhs, rhs);
|
||||
|
||||
if(rt == NODE_SET)
|
||||
return compareNodeSetWith<std::greater<double> >(rhs, lhs);
|
||||
|
||||
return lhs->asNumber() < rhs->asNumber();
|
||||
} // isLessThan
|
||||
|
||||
template<class string_type>
|
||||
bool isLessThanEquals(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
ValueType lt = lhs->type();
|
||||
ValueType rt = rhs->type();
|
||||
|
||||
if((lt == NODE_SET) && (rt == NODE_SET))
|
||||
return compareNodeSets<std::less_equal<double> >(lhs, rhs);
|
||||
|
||||
if(lt == NODE_SET)
|
||||
return compareNodeSetWith<std::less_equal<double> >(lhs, rhs);
|
||||
|
||||
if(rt == NODE_SET)
|
||||
return compareNodeSetWith<std::greater_equal<double> >(rhs, lhs);
|
||||
|
||||
return lhs->asNumber() <= rhs->asNumber();
|
||||
} // isLessThanEquals
|
||||
|
||||
template<class string_type>
|
||||
bool isGreaterThan(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
return isLessThan(rhs, lhs);
|
||||
} // isGreaterThan
|
||||
|
||||
template<class string_type>
|
||||
bool isGreaterThanEquals(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
return isLessThanEquals(rhs, lhs);
|
||||
} // isGreaterThanEquals
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
|
|
@ -1,320 +0,0 @@
|
|||
#include <XPath/impl/xpath_object.hpp>
|
||||
#include <XPath/impl/xpath_axis_enumerator.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
template<class string_type>
|
||||
bool nodeSetsEqual(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
const NodeSet<string_type>& lns = lhs->asNodeSet();
|
||||
const NodeSet<string_type>& rns = rhs->asNodeSet();
|
||||
|
||||
if((lns.size() == 0) || (rns.size() == 0))
|
||||
return false;
|
||||
|
||||
std::set<string_type> values;
|
||||
NodeSet<string_type>::const_iterator l = lns.begin();
|
||||
string_type lvalue = nodeStringValue(*l);
|
||||
|
||||
for(NodeSet<string_type>::const_iterator r = rns.begin(), rend = rns.end(); r != rend; ++r)
|
||||
{
|
||||
string_type rvalue = nodeStringValue(*r);
|
||||
if(lvalue == rvalue)
|
||||
return true;
|
||||
values.insert(rvalue);
|
||||
} // for ...
|
||||
|
||||
++l;
|
||||
for(NodeSet<string_type>::const_iterator lend = lns.end(); l != lend; ++l)
|
||||
if(values.find(nodeStringValue(*l)) != values.end())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} // nodeSetsEqual
|
||||
|
||||
template<class string_type>
|
||||
bool nodeSetAndValueEqual(const XPathValuePtr<string_type>& lhs, const XPathValuePtr<string_type>& rhs)
|
||||
{
|
||||
const NodeSet<string_type>& lns = lhs->asNodeSet();
|
||||
|
||||
switch(rhs->type())
|
||||
{
|
||||
case BOOL:
|
||||
{
|
||||
bool l = !lns.empty();
|
||||
bool r = rhs->asBool();
|
||||
|
||||
return l == r;
|
||||
} // case BOOL
|
||||
case STRING:
|
||||
return std::find_if(lns.begin(), lns.end(), compareNodeWith<std::equal_to<string_type> >(rhs->asString())) != lns.end();
|
||||
|
||||
case NUMBER:
|
||||
return std::find_if(lns.begin(), lns.end(), compareNodeWith<std::equal_to<double> >(rhs->asNumber())) != lns.end();
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Node set == not yet implemented for type " + boost::lexical_cast<std::string>(rhs->type()));
|
||||
} // switch
|
||||
} // nodeSetAndValueEqual
|
||||
|
||||
template<class string_type>
|
||||
double minValue(const NodeSet<string_type>& ns)
|
||||
{
|
||||
double v = nodeNumberValue(ns[0]);
|
||||
for(NodeSet<string_type>::const_iterator i = ns.begin(), ie = ns.end(); i != ie; ++i)
|
||||
{
|
||||
double vt = nodeNumberValue(*i);
|
||||
if(isNaN(vt))
|
||||
continue;
|
||||
if(!(vt > v)) // looks weird, but should account for infinity
|
||||
v = vt;
|
||||
} // for ...
|
||||
return v;
|
||||
} // minValue
|
||||
|
||||
template<class string_type>
|
||||
double maxValue(const NodeSet<string_type>& ns)
|
||||
{
|
||||
double v = nodeNumberValue(ns[0]);
|
||||
for(NodeSet<string_type>::const_iterator i = ns.begin(), ie = ns.end(); i != ie; ++i)
|
||||
{
|
||||
double vt = nodeNumberValue(*i);
|
||||
if(isNaN(vt))
|
||||
continue;
|
||||
if(!(vt < v))
|
||||
v = vt;
|
||||
} // for ...
|
||||
return v;
|
||||
} // maxValue
|
||||
|
||||
template<class T> T nodeValue(const DOM::Node<std::string>& node);
|
||||
template<> std::string nodeValue(const DOM::Node<std::string>& node) { return nodeStringValue(node); }
|
||||
template<> double nodeValue(const DOM::Node<std::string>& node) { return nodeNumberValue(node); }
|
||||
|
||||
template<class Op>
|
||||
class compareNodeWith
|
||||
{
|
||||
typedef typename Op::first_argument_type T;
|
||||
public:
|
||||
compareNodeWith(const T& value) : value_(value) { }
|
||||
compareNodeWith(const compareNodeWith& rhs) : value_(rhs.value_) { }
|
||||
|
||||
bool operator()(const DOM::Node<std::string>& node)
|
||||
{
|
||||
return Op()(nodeValue<T>(node), value_);
|
||||
} // operator()
|
||||
|
||||
private:
|
||||
T value_;
|
||||
bool operator==(const compareNodeWith&);
|
||||
compareNodeWith& operator=(const compareNodeWith&);
|
||||
}; // class compareNodeWith
|
||||
|
||||
template<class Op>
|
||||
bool compareNodeSets(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
return Op()(minValue(lhs->asNodeSet()), maxValue(rhs->asNodeSet()));
|
||||
} // compareNodeSets
|
||||
|
||||
template<class Op>
|
||||
bool compareNodeSetWith(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
const NodeSet<std::string>& lns = lhs->asNodeSet();
|
||||
return std::find_if(lns.begin(),
|
||||
lns.end(),
|
||||
compareNodeWith<Op>(rhs->asNumber())) != lns.end();
|
||||
} // compareNodeSetAndValue
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
bool areEqual(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
ValueType lt = lhs->type();
|
||||
ValueType rt = rhs->type();
|
||||
|
||||
if((lt == NODE_SET) && (rt == NODE_SET))
|
||||
return nodeSetsEqual(lhs, rhs);
|
||||
|
||||
if(lt == NODE_SET)
|
||||
return nodeSetAndValueEqual(lhs, rhs);
|
||||
if(rt == NODE_SET)
|
||||
return nodeSetAndValueEqual(rhs, lhs);
|
||||
|
||||
if((lt == BOOL) || (rt == BOOL))
|
||||
return lhs->asBool() == rhs->asBool();
|
||||
|
||||
if((lt == NUMBER) || (rt == NUMBER))
|
||||
return lhs->asNumber() == rhs->asNumber();
|
||||
|
||||
if((lt == STRING) || (rt == STRING))
|
||||
return lhs->asString() == rhs->asString();
|
||||
|
||||
return false;
|
||||
} // operator==
|
||||
|
||||
///////////////////////////////
|
||||
bool isLessThan(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
ValueType lt = lhs->type();
|
||||
ValueType rt = rhs->type();
|
||||
|
||||
if((lt == NODE_SET) && (rt == NODE_SET))
|
||||
return compareNodeSets<std::less<double> >(lhs, rhs);
|
||||
|
||||
if(lt == NODE_SET)
|
||||
return compareNodeSetWith<std::less<double> >(lhs, rhs);
|
||||
|
||||
if(rt == NODE_SET)
|
||||
return compareNodeSetWith<std::greater<double> >(rhs, lhs);
|
||||
|
||||
return lhs->asNumber() < rhs->asNumber();
|
||||
} // isLessThan
|
||||
|
||||
bool isLessThanEquals(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
ValueType lt = lhs->type();
|
||||
ValueType rt = rhs->type();
|
||||
|
||||
if((lt == NODE_SET) && (rt == NODE_SET))
|
||||
return compareNodeSets<std::less_equal<double> >(lhs, rhs);
|
||||
|
||||
if(lt == NODE_SET)
|
||||
return compareNodeSetWith<std::less_equal<double> >(lhs, rhs);
|
||||
|
||||
if(rt == NODE_SET)
|
||||
return compareNodeSetWith<std::greater_equal<double> >(rhs, lhs);
|
||||
|
||||
return lhs->asNumber() <= rhs->asNumber();
|
||||
} // isLessThanEquals
|
||||
|
||||
bool isGreaterThan(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
return isLessThan(rhs, lhs);
|
||||
} // isGreaterThan
|
||||
|
||||
bool isGreaterThanEquals(const XPathValuePtr<std::string>& lhs, const XPathValuePtr<std::string>& rhs)
|
||||
{
|
||||
return isLessThanEquals(rhs, lhs);
|
||||
} // isGreaterThanEquals
|
||||
|
||||
////////////////////////////////////
|
||||
DOM::Node<std::string> node_parent_or_owner(const DOM::Node<std::string>& node)
|
||||
{
|
||||
if(node.getNodeType() == DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
return (static_cast<DOM::Attr<std::string> >(node)).getOwnerElement();
|
||||
return node.getParentNode();
|
||||
} // node_parent_or_owner
|
||||
|
||||
DOM::Node<std::string> ultimate_parent(const DOM::Node<std::string>& origin)
|
||||
{
|
||||
DOM::Node<std::string> n = origin;
|
||||
DOM::Node<std::string> p = node_parent_or_owner(n);
|
||||
while(p != 0)
|
||||
{
|
||||
n = p;
|
||||
p = node_parent_or_owner(n);
|
||||
} // while ...
|
||||
return n;
|
||||
} // ultimate_parent
|
||||
|
||||
unsigned int node_attribute_index(const DOM::Attr<std::string>& attr)
|
||||
{
|
||||
DOM::NamedNodeMap<std::string> attrs = attr.getOwnerElement().getAttributes();
|
||||
unsigned int p = 0;
|
||||
for(unsigned int pe = attrs.getLength(); p != pe; ++p)
|
||||
if(attrs.item(p) == attr)
|
||||
break;
|
||||
return p;
|
||||
} // node_attribute_index
|
||||
|
||||
unsigned int node_child_position(const DOM::Node<std::string>& node)
|
||||
{
|
||||
if(node.getNodeType() == DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
return node_attribute_index(static_cast<DOM::Attr<std::string> >(node));
|
||||
|
||||
unsigned int pos = 0;
|
||||
DOM::Node<std::string> n = node;
|
||||
do
|
||||
{
|
||||
n = n.getPreviousSibling();
|
||||
pos += 1000;
|
||||
} while(n != 0);
|
||||
return pos;
|
||||
} // node_child_position
|
||||
|
||||
std::vector<unsigned int> node_position(const DOM::Node<std::string>& node)
|
||||
{
|
||||
std::vector<unsigned int> pos;
|
||||
DOM::Node<std::string> n = node;
|
||||
do
|
||||
{
|
||||
pos.push_back(node_child_position(n));
|
||||
n = node_parent_or_owner(n);
|
||||
} while(n != 0);
|
||||
|
||||
return pos;
|
||||
} // node_position
|
||||
|
||||
int resolve_different_subtrees(const DOM::Node<std::string>& lhs, const DOM::Node<std::string>& rhs)
|
||||
{
|
||||
// if we have something in the document, and a document fragment,
|
||||
// sort the doc ahead of the fragment
|
||||
DOM::Node<std::string> lp = ultimate_parent(lhs);
|
||||
if(lp.getNodeType() == DOM::Node<std::string>::DOCUMENT_NODE)
|
||||
return -1;
|
||||
DOM::Node<std::string> rp = ultimate_parent(rhs);
|
||||
if(rp.getNodeType() == DOM::Node<std::string>::DOCUMENT_NODE)
|
||||
return 1;
|
||||
|
||||
// otherwise, sort the frags
|
||||
return (lp.unlying_impl() < lp.unlying_impl()) ? -1 : 1;
|
||||
} // resolve_different_subtrees
|
||||
|
||||
int compareNodes(const DOM::Node<std::string>& lhs, const DOM::Node<std::string>& rhs)
|
||||
{
|
||||
if(lhs == rhs)
|
||||
return 0;
|
||||
|
||||
// different documents
|
||||
if(lhs.getOwnerDocument() != rhs.getOwnerDocument())
|
||||
return (lhs.getOwnerDocument().unlying_impl() < rhs.getOwnerDocument().unlying_impl()) ? -1 : 1;
|
||||
|
||||
// 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
|
||||
|
||||
bool nodes_less_than(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2)
|
||||
{
|
||||
return compareNodes(n1, n2) < 0;
|
||||
} // nodes_less_than
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
Loading…
Add table
Reference in a new issue