mirror of
https://github.com/jezhiggins/arabica
synced 2025-01-17 18:12:04 +01:00
moved here from xpath-dev-sandbox
This commit is contained in:
parent
50f169b1c7
commit
b18f90ce9e
27 changed files with 4266 additions and 0 deletions
12
XPath/XPath.hpp
Normal file
12
XPath/XPath.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_HPP
|
||||
|
||||
#include <XPath/impl/xpath_parser.hpp>
|
||||
#include <XPath/impl/xpath_value.hpp>
|
||||
#include <XPath/impl/xpath_function.hpp>
|
||||
#include <XPath/impl/xpath_step.hpp>
|
||||
#include <XPath/impl/xpath_relational.hpp>
|
||||
#include <XPath/impl/xpath_logical.hpp>
|
||||
#include <XPath/impl/xpath_arithmetic.hpp>
|
||||
|
||||
#endif
|
92
XPath/impl/xpath_arithmetic.hpp
Normal file
92
XPath/impl/xpath_arithmetic.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_ARITHMETIC_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_ARITHMETIC_HPP
|
||||
|
||||
#include "xpath_value.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class PlusOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
PlusOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return NumericValue::createValue(lhs()->evaluateAsNumber(context) + rhs()->evaluateAsNumber(context));
|
||||
} // evaluate
|
||||
}; // class PlusOperator
|
||||
|
||||
class MinusOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
MinusOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return NumericValue::createValue(lhs()->evaluateAsNumber(context) - rhs()->evaluateAsNumber(context));
|
||||
} // evaluate
|
||||
}; // class MinusOperator
|
||||
|
||||
class MultiplyOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
MultiplyOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return NumericValue::createValue(lhs()->evaluateAsNumber(context) * rhs()->evaluateAsNumber(context));
|
||||
} // evaluate
|
||||
}; // class MultiplyOperator
|
||||
|
||||
class DivideOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
DivideOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return NumericValue::createValue(lhs()->evaluateAsNumber(context) / rhs()->evaluateAsNumber(context));
|
||||
} // evaluate
|
||||
}; // class DivideOperator
|
||||
|
||||
class ModOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
ModOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return NumericValue::createValue(static_cast<long>(lhs()->evaluateAsNumber(context)) % static_cast<long>(rhs()->evaluateAsNumber(context)));
|
||||
} // evaluate
|
||||
}; // class ModOperator
|
||||
|
||||
class UnaryNegative : private UnaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
UnaryNegative(XPathExpression* expr) :
|
||||
UnaryExpression(expr) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return NumericValue::createValue(-expr()->evaluate(context, executionContext)->asNumber());
|
||||
} // evaluate
|
||||
}; // class UnaryNegative
|
||||
|
||||
} // XPath
|
||||
} // Arabica
|
||||
|
||||
#endif
|
27
XPath/impl/xpath_ast.hpp
Normal file
27
XPath/impl/xpath_ast.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_AST_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_AST_HPP
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/tree/ast.hpp>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
typedef std::string::const_iterator str_iter_t;
|
||||
|
||||
typedef boost::spirit::tree_match<str_iter_t> tree_match_t;
|
||||
typedef tree_match_t::tree_iterator node_iter_t;
|
||||
typedef boost::spirit::tree_parse_info<str_iter_t> tree_info_t;
|
||||
|
||||
long getNodeId(node_iter_t const& node);
|
||||
node_iter_t& skipWhitespace(node_iter_t& node);
|
||||
|
||||
class XPathExpression;
|
||||
class CompilationContext;
|
||||
XPathExpression* compile_expression(node_iter_t const& i, CompilationContext& context);
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
#endif
|
106
XPath/impl/xpath_ast_ids.hpp
Normal file
106
XPath/impl/xpath_ast_ids.hpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_AST_IDS_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_AST_IDS_HPP
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
LocationPath_id = 1,
|
||||
AbsoluteLocationPath_id,
|
||||
RelativeLocationPath_id,
|
||||
Step_id,
|
||||
AxisSpecifier_id,
|
||||
NodeTest_id,
|
||||
Predicate_id,
|
||||
PredicateExpr_id,
|
||||
AbbreviatedAbsoluteLocationPath_id,
|
||||
AbbreviatedStep_id,
|
||||
AbbreviatedAxisSpecifier_id,
|
||||
Expr_id,
|
||||
PrimaryExpr_id,
|
||||
FunctionCall_id,
|
||||
Argument_id,
|
||||
UnionExpr_id,
|
||||
PathExpr_id,
|
||||
FilterExpr_id,
|
||||
OrExpr_id,
|
||||
AndExpr_id,
|
||||
EqualityExpr_id,
|
||||
RelationalExpr_id,
|
||||
AdditiveExpr_id,
|
||||
MultiplicativeExpr_id,
|
||||
UnaryExpr_id,
|
||||
Literal_id,
|
||||
Number_id,
|
||||
Digits_id,
|
||||
MultiplyOperator_id,
|
||||
FunctionName_id,
|
||||
VariableReference_id,
|
||||
NameTest_id,
|
||||
S_id,
|
||||
NodeType_id,
|
||||
AxisName_id,
|
||||
|
||||
QName_id,
|
||||
Prefix_id,
|
||||
LocalPart_id,
|
||||
NCName_id,
|
||||
NCNameChar_id,
|
||||
|
||||
Slash_id,
|
||||
SlashSlash_id,
|
||||
|
||||
AncestorOrSelf_id,
|
||||
Ancestor_id,
|
||||
Attribute_id,
|
||||
Child_id,
|
||||
DescendantOrSelf_id,
|
||||
Descendant_id,
|
||||
FollowingSibling_id,
|
||||
Following_id,
|
||||
Namespace_id,
|
||||
Parent_id,
|
||||
PrecedingSibling_id,
|
||||
Preceding_id,
|
||||
Self_id,
|
||||
|
||||
Comment_id,
|
||||
Text_id,
|
||||
ProcessingInstruction_id,
|
||||
Node_id,
|
||||
AnyName_id,
|
||||
|
||||
SelfSelect_id,
|
||||
ParentSelect_id,
|
||||
|
||||
LeftSquare_id,
|
||||
RightSquare_id,
|
||||
|
||||
LeftBracket_id,
|
||||
RightBracket_id,
|
||||
|
||||
PlusOperator_id,
|
||||
MinusOperator_id,
|
||||
ModOperator_id,
|
||||
DivOperator_id,
|
||||
EqualsOperator_id,
|
||||
NotEqualsOperator_id,
|
||||
LessThanOperator_id,
|
||||
LessThanEqualsOperator_id,
|
||||
GreaterThanOperator_id,
|
||||
GreaterThanEqualsOperator_id,
|
||||
|
||||
OrOperator_id,
|
||||
AndOperator_id,
|
||||
UnionOperator_id,
|
||||
UnaryMinusOperator_id
|
||||
};
|
||||
|
||||
} // namespace XPath
|
||||
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
531
XPath/impl/xpath_axis_enumerator.hpp
Normal file
531
XPath/impl/xpath_axis_enumerator.hpp
Normal file
|
@ -0,0 +1,531 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_AXIS_ENUMERATOR_H
|
||||
#define ARABICA_XPATHIC_XPATH_AXIS_ENUMERATOR_H
|
||||
|
||||
#include <DOM/Node.h>
|
||||
#include <DOM/Document.h>
|
||||
#include <DOM/NamedNodeMap.h>
|
||||
#include "xpath_namespace_node.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
enum Axis
|
||||
{
|
||||
ANCESTOR,
|
||||
ANCESTOR_OR_SELF,
|
||||
ATTRIBUTE,
|
||||
CHILD,
|
||||
DESCENDANT,
|
||||
DESCENDANT_OR_SELF,
|
||||
FOLLOWING,
|
||||
FOLLOWING_SIBLING,
|
||||
NAMESPACE,
|
||||
PARENT,
|
||||
PRECEDING,
|
||||
PRECEDING_SIBLING,
|
||||
SELF
|
||||
}; // Axis
|
||||
|
||||
class AxisEnumerator
|
||||
{
|
||||
class AxisWalker;
|
||||
|
||||
template<class axis_walker>
|
||||
static AxisWalker* CreateAxis(const DOM::Node<std::string>& context) { return new axis_walker(context); }
|
||||
|
||||
typedef AxisWalker* (*CreateAxisPtr)(const DOM::Node<std::string>& context);
|
||||
|
||||
struct NamedAxis { Axis name; CreateAxisPtr creator; };
|
||||
|
||||
static const NamedAxis AxisLookupTable[];
|
||||
|
||||
public:
|
||||
AxisEnumerator(const DOM::Node<std::string>& context, Axis axis) :
|
||||
walker_(0)
|
||||
{
|
||||
for(const NamedAxis* ax = AxisLookupTable; ax->creator != 0; ++ax)
|
||||
if(axis == ax->name)
|
||||
walker_ = ax->creator(context);
|
||||
|
||||
if(!walker_)
|
||||
throw std::runtime_error("Unknown Axis specifier");
|
||||
} // AxisEnumerator
|
||||
|
||||
AxisEnumerator(const AxisEnumerator& rhs) :
|
||||
walker_(rhs.walker_->clone())
|
||||
{
|
||||
} // AxisEnumerator
|
||||
|
||||
AxisEnumerator& operator=(const AxisEnumerator& rhs)
|
||||
{
|
||||
AxisWalker* newwalker = rhs.walker_->clone();
|
||||
delete walker_;
|
||||
walker_ = newwalker;
|
||||
return *this;
|
||||
} // operator=
|
||||
|
||||
~AxisEnumerator()
|
||||
{
|
||||
delete walker_;
|
||||
} // ~AxisEnumerator
|
||||
|
||||
bool forward() const { return walker_->forward(); }
|
||||
bool reverse() const { return !walker_->forward(); }
|
||||
const DOM::Node<std::string>& operator*() const { return walker_->get(); }
|
||||
const DOM::Node<std::string>* const operator->() const { return &(walker_->get()); }
|
||||
AxisEnumerator& operator++() { walker_->advance(); return *this; }
|
||||
AxisEnumerator operator++(int) { AxisEnumerator copy(*this); walker_->advance(); return copy; }
|
||||
|
||||
private:
|
||||
AxisWalker* walker_;
|
||||
|
||||
AxisEnumerator();
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
class AxisWalker
|
||||
{
|
||||
public:
|
||||
virtual ~AxisWalker() { }
|
||||
const DOM::Node<std::string>& get() const { return current_; }
|
||||
virtual void advance() = 0;
|
||||
bool forward() { return forward_; }
|
||||
virtual AxisWalker* clone() const = 0;
|
||||
|
||||
protected:
|
||||
AxisWalker(bool forward) : forward_(forward) { }
|
||||
AxisWalker(const AxisWalker& rhs) : current_(rhs.current_), forward_(rhs.forward_) { }
|
||||
void set(const DOM::Node<std::string>& current) { current_ = current; }
|
||||
void end() { current_ = 0; }
|
||||
|
||||
private:
|
||||
DOM::Node<std::string> current_;
|
||||
bool forward_;
|
||||
|
||||
AxisWalker& operator=(const AxisWalker&);
|
||||
bool operator==(const AxisWalker&);
|
||||
}; // AxisWalker
|
||||
|
||||
class AncestorAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
AncestorAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(false)
|
||||
{
|
||||
if(context == 0)
|
||||
return;
|
||||
|
||||
if(context.getNodeType() != DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
set(context.getParentNode());
|
||||
else
|
||||
set((static_cast<DOM::Attr<std::string> >(context)).getOwnerElement());
|
||||
} // AncestorAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() != 0)
|
||||
set(get().getParentNode());
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new AncestorAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
AncestorAxisWalker(const AncestorAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class AncestorAxisWalker
|
||||
|
||||
class AncestorOrSelfAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
AncestorOrSelfAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(false)
|
||||
{
|
||||
if(context != 0)
|
||||
set(context);
|
||||
} // AncestorAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() == 0)
|
||||
return;
|
||||
|
||||
if(get().getNodeType() != DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
set(get().getParentNode());
|
||||
else
|
||||
set((static_cast<DOM::Attr<std::string> >(get())).getOwnerElement());
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new AncestorOrSelfAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
AncestorOrSelfAxisWalker(const AncestorOrSelfAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class AncestorOrSelfAxisWalker
|
||||
|
||||
class AttributeAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
AttributeAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true),
|
||||
index_(0), count_(0)
|
||||
{
|
||||
if((context != 0) && (context.hasAttributes()))
|
||||
{
|
||||
attrs_ = context.getAttributes();
|
||||
count_ = attrs_.getLength();
|
||||
set_next();
|
||||
} // if ...
|
||||
} // AttributeAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() == 0)
|
||||
return;
|
||||
set_next();
|
||||
} // advance
|
||||
|
||||
virtual AxisWalker* clone() const { return new AttributeAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
AttributeAxisWalker(const AttributeAxisWalker& rhs) :
|
||||
AxisWalker(rhs),
|
||||
attrs_(rhs.attrs_),
|
||||
index_(rhs.index_),
|
||||
count_(rhs.count_) { }
|
||||
|
||||
DOM::NamedNodeMap<std::string> attrs_;
|
||||
unsigned int index_;
|
||||
unsigned int count_;
|
||||
|
||||
void set_next()
|
||||
{
|
||||
if(index_ == count_)
|
||||
{
|
||||
end();
|
||||
return;
|
||||
} // if ...
|
||||
|
||||
DOM::Node<std::string> a;
|
||||
do
|
||||
{
|
||||
a = attrs_.item(index_++);
|
||||
} while ((a != 0) && (a.getNamespaceURI() == "http://www.w3.org/2000/xmlns/"));
|
||||
|
||||
set(a);
|
||||
} // set_next
|
||||
}; // class AttributeAxisEnumerator
|
||||
|
||||
class ChildAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
ChildAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true)
|
||||
{
|
||||
if(context != 0)
|
||||
set(context.getFirstChild());
|
||||
} // ChildAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() != 0)
|
||||
set(get().getNextSibling());
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new ChildAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
ChildAxisWalker(const ChildAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class ChildAxisWalker
|
||||
|
||||
class DescendantAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
DescendantAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true),
|
||||
origin_(context)
|
||||
{
|
||||
if((context != 0) && (context.getNodeType() != DOM::Node<std::string>::ATTRIBUTE_NODE))
|
||||
set(context.getFirstChild());
|
||||
} // DescendantAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
set(nextDescendant());
|
||||
} // advance
|
||||
|
||||
virtual AxisWalker* clone() const { return new DescendantAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
DOM::Node<std::string> nextDescendant()
|
||||
{
|
||||
DOM::Node<std::string> next = get().getFirstChild();
|
||||
if(next == 0)
|
||||
next = get().getNextSibling();
|
||||
if(next != 0)
|
||||
return next;
|
||||
|
||||
DOM::Node<std::string> parent = get().getParentNode();
|
||||
while(parent != origin_ && next == 0)
|
||||
{
|
||||
next = parent.getNextSibling();
|
||||
parent = parent.getParentNode();
|
||||
} // while ...
|
||||
|
||||
return next;
|
||||
} // nextDescendant
|
||||
|
||||
DescendantAxisWalker(const DescendantAxisWalker& rhs) : AxisWalker(rhs), origin_(rhs.origin_) { }
|
||||
const DOM::Node<std::string> origin_;
|
||||
}; // class DescendantAxisWalker
|
||||
|
||||
class DescendantOrSelfAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
DescendantOrSelfAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true),
|
||||
origin_(context)
|
||||
{
|
||||
if(context != 0)
|
||||
set(context);
|
||||
} // DescendantAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
set(walkDown(get(), origin_));
|
||||
} // advance
|
||||
|
||||
virtual AxisWalker* clone() const { return new DescendantOrSelfAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
DescendantOrSelfAxisWalker(const DescendantOrSelfAxisWalker& rhs) : AxisWalker(rhs), origin_(rhs.origin_) { }
|
||||
const DOM::Node<std::string> origin_;
|
||||
}; // class DescendantOrSelfAxisWalker
|
||||
|
||||
class FollowingAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
FollowingAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true)
|
||||
{
|
||||
set(firstFollowing(context));
|
||||
} // FollowingAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
set(walkDown(get(), get().getOwnerDocument()));
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new FollowingAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
DOM::Node<std::string> firstFollowing(const DOM::Node<std::string>& context) const
|
||||
{
|
||||
if(context.getNodeType() == DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
return 0;
|
||||
|
||||
DOM::Node<std::string> next = context.getNextSibling();
|
||||
if(next != 0)
|
||||
return next;
|
||||
|
||||
DOM::Node<std::string> parent = context.getParentNode();
|
||||
while(parent != context.getOwnerDocument() && next == 0)
|
||||
{
|
||||
next = parent.getNextSibling();
|
||||
parent = parent.getParentNode();
|
||||
} // while ...
|
||||
|
||||
return next;
|
||||
} // firstFollowing
|
||||
|
||||
FollowingAxisWalker(const FollowingAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class FollowingAxisWalker
|
||||
|
||||
class FollowingSiblingAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
FollowingSiblingAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true)
|
||||
{
|
||||
if(context != 0)
|
||||
set(context.getNextSibling());
|
||||
} // FollowingSiblingAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() != 0)
|
||||
set(get().getNextSibling());
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new FollowingSiblingAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
FollowingSiblingAxisWalker(const FollowingSiblingAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class FollowingSiblingAxisWalker
|
||||
|
||||
class NamespaceAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
NamespaceAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true),
|
||||
index_(0)
|
||||
{
|
||||
DOM::Node<std::string> current = context;
|
||||
while(current.getNodeType() == DOM::Node<std::string>::ELEMENT_NODE)
|
||||
{
|
||||
for(unsigned int a = 0, ae = current.getAttributes().getLength(); a != ae; ++a)
|
||||
{
|
||||
DOM::Node<std::string> attr = current.getAttributes().item(a);
|
||||
if(attr.getPrefix() == "xmlns")
|
||||
list_.push_back(DOM::Node<std::string>(
|
||||
new NamespaceNodeImpl<std::string>(attr.getLocalName(),
|
||||
attr.getNodeValue())
|
||||
)
|
||||
);
|
||||
} // for ...
|
||||
current = current.getParentNode();
|
||||
} // while
|
||||
list_.push_back(DOM::Node<std::string>(0));
|
||||
set(list_[index_]);
|
||||
} // NamespaceAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(index_ != list_.size())
|
||||
set(list_[++index_]);
|
||||
} // advance
|
||||
|
||||
virtual AxisWalker* clone() const { return new NamespaceAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
NamespaceAxisWalker(const NamespaceAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
std::vector<DOM::Node<std::string> > list_;
|
||||
unsigned int index_;
|
||||
}; // class NamespaceAxisWalker
|
||||
|
||||
class ParentAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
ParentAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(false)
|
||||
{
|
||||
if(context == 0)
|
||||
return;
|
||||
|
||||
if(context.getNodeType() != DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
set(context.getParentNode());
|
||||
else
|
||||
set((static_cast<DOM::Attr<std::string> >(context)).getOwnerElement());
|
||||
} // ParentAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() != 0)
|
||||
set(0);
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new ParentAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
ParentAxisWalker(const ParentAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class ParentAxisWalker
|
||||
|
||||
class PrecedingAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
PrecedingAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(false)
|
||||
{
|
||||
nextAncestor_ = context.getParentNode();
|
||||
set(previousInDocument(context));
|
||||
} // PrecedingAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
set(previousInDocument(get()));
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new PrecedingAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
DOM::Node<std::string> previousInDocument(const DOM::Node<std::string>& context)
|
||||
{
|
||||
DOM::Node<std::string> next = context.getPreviousSibling();
|
||||
if(next != 0)
|
||||
return getLastDescendant(next);
|
||||
|
||||
next = context.getParentNode();
|
||||
if(next != nextAncestor_)
|
||||
return next;
|
||||
|
||||
// ancestor collision!! woorp, woorp!
|
||||
nextAncestor_ = nextAncestor_.getParentNode();
|
||||
if(nextAncestor_ != 0)
|
||||
return previousInDocument(next);
|
||||
|
||||
return 0;
|
||||
} // previousInDocument
|
||||
|
||||
DOM::Node<std::string> getLastDescendant(const DOM::Node<std::string>& context)
|
||||
{
|
||||
if(context.getFirstChild() == 0)
|
||||
return context;
|
||||
|
||||
DOM::Node<std::string> c = context.getFirstChild();
|
||||
while(c.getNextSibling() != 0)
|
||||
c = c.getNextSibling();
|
||||
|
||||
return getLastDescendant(c);
|
||||
} // getLastDescendant
|
||||
|
||||
PrecedingAxisWalker(const PrecedingAxisWalker& rhs) : AxisWalker(rhs), nextAncestor_(rhs.nextAncestor_) { }
|
||||
DOM::Node<std::string> nextAncestor_;
|
||||
}; // PrecedingAxisWalker
|
||||
|
||||
class PrecedingSiblingAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
PrecedingSiblingAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(false)
|
||||
{
|
||||
if(context != 0)
|
||||
set(context.getPreviousSibling());
|
||||
} // PrecedingSiblingAxisWalker
|
||||
|
||||
virtual void advance()
|
||||
{
|
||||
if(get() != 0)
|
||||
set(get().getPreviousSibling());
|
||||
} // advance
|
||||
virtual AxisWalker* clone() const { return new PrecedingSiblingAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
PrecedingSiblingAxisWalker(const PrecedingSiblingAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class PrecedingSiblingAxisWalker
|
||||
|
||||
class SelfAxisWalker : public AxisWalker
|
||||
{
|
||||
public:
|
||||
SelfAxisWalker(const DOM::Node<std::string>& context) : AxisWalker(true)
|
||||
{
|
||||
set(context);
|
||||
} // SelfAxisWalker
|
||||
|
||||
virtual void advance() { end(); }
|
||||
virtual AxisWalker* clone() const { return new SelfAxisWalker(*this); }
|
||||
|
||||
private:
|
||||
SelfAxisWalker(const SelfAxisWalker& rhs) : AxisWalker(rhs) { }
|
||||
}; // class SelfAxisWalker
|
||||
|
||||
static DOM::Node<std::string> walkDown(const DOM::Node<std::string>& context, const DOM::Node<std::string>& origin)
|
||||
{
|
||||
if(context.getNodeType() == DOM::Node<std::string>::ATTRIBUTE_NODE)
|
||||
return 0;
|
||||
|
||||
DOM::Node<std::string> next = context.getFirstChild();
|
||||
if((next == 0) && (context == origin)) // node with no children
|
||||
return 0;
|
||||
|
||||
if(next != 0)
|
||||
return next;
|
||||
|
||||
next = context.getNextSibling();
|
||||
if(next != 0)
|
||||
return next;
|
||||
|
||||
DOM::Node<std::string> parent = context.getParentNode();
|
||||
while(parent != origin && next == 0)
|
||||
{
|
||||
next = parent.getNextSibling();
|
||||
parent = parent.getParentNode();
|
||||
} // while ...
|
||||
|
||||
return next;
|
||||
} // walkDown
|
||||
}; // class AxisEnumerator
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
||||
|
42
XPath/impl/xpath_compile_context.hpp
Normal file
42
XPath/impl/xpath_compile_context.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef ARABICA_XPATH_COMPILE_CONTEXT_HPP
|
||||
#define ARABICA_XPATH_COMPILE_CONTEXT_HPP
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class XPath;
|
||||
class NamespaceContext;
|
||||
class FunctionResolver;
|
||||
|
||||
class CompilationContext
|
||||
{
|
||||
public:
|
||||
CompilationContext(const XPath& xpathCompiler,
|
||||
const NamespaceContext& namespaceContext,
|
||||
const FunctionResolver& functionResolver) :
|
||||
xpath_(xpathCompiler),
|
||||
namespaceContext_(namespaceContext),
|
||||
functionResolver_(functionResolver)
|
||||
{
|
||||
} // CompilationContext
|
||||
|
||||
const XPath& xpath() const { return xpath_; }
|
||||
const NamespaceContext& namespaceContext() const { return namespaceContext_; }
|
||||
const FunctionResolver& functionResolver() const { return functionResolver_; }
|
||||
|
||||
private:
|
||||
const XPath& xpath_;
|
||||
const NamespaceContext& namespaceContext_;
|
||||
const FunctionResolver& functionResolver_;
|
||||
|
||||
CompilationContext(const CompilationContext&);
|
||||
CompilationContext& operator=(const CompilationContext&);
|
||||
bool operator==(const CompilationContext&) const;
|
||||
}; // class CompilationContext
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
50
XPath/impl/xpath_execution_context.hpp
Normal file
50
XPath/impl/xpath_execution_context.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef ARABICA_XPATH_EXECUTION_CONTEXT_HPP
|
||||
#define ARABICA_XPATH_EXECUTION_CONTEXT_HPP
|
||||
|
||||
#include "xpath_variable_resolver.hpp"
|
||||
#include "xpath_resolver_holder.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class ExecutionContext
|
||||
{
|
||||
public:
|
||||
ExecutionContext() :
|
||||
position_(-1),
|
||||
last_(-1)
|
||||
{
|
||||
} // ExecutionContext
|
||||
|
||||
ExecutionContext(size_t last, const ExecutionContext& parent) :
|
||||
position_(-1),
|
||||
last_(last),
|
||||
variableResolver_(parent.variableResolver_)
|
||||
{
|
||||
} // ExecutionContext
|
||||
|
||||
size_t position() const { return position_; }
|
||||
size_t last() const { return last_; }
|
||||
|
||||
void setPosition(unsigned int pos) { position_ = pos; }
|
||||
|
||||
const VariableResolver& variableResolver() const { return variableResolver_.get(); }
|
||||
void setVariableResolver(const VariableResolver& resolver) { variableResolver_.set(resolver); }
|
||||
void setVariableResolver(VariableResolverPtr& resolver) { variableResolver_.set(resolver); }
|
||||
|
||||
private:
|
||||
size_t position_;
|
||||
size_t last_;
|
||||
ResolverHolder<const VariableResolver> variableResolver_;
|
||||
|
||||
ExecutionContext(const ExecutionContext&);
|
||||
ExecutionContext& operator=(const ExecutionContext&);
|
||||
bool operator==(const ExecutionContext&) const;
|
||||
}; // class ExecutionContext
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
543
XPath/impl/xpath_function.hpp
Normal file
543
XPath/impl/xpath_function.hpp
Normal file
|
@ -0,0 +1,543 @@
|
|||
#ifndef ARABICA_XPATH_FUNCTION_HPP
|
||||
#define ARABICA_XPATH_FUNCTION_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <cmath>
|
||||
#include <XML/XMLCharacterClasses.h>
|
||||
#include <XML/UnicodeCharacters.h>
|
||||
#include "xpath_value.hpp"
|
||||
#include "xpath_execution_context.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class XPathFunction
|
||||
{
|
||||
protected:
|
||||
XPathFunction(int minArgs, int maxArgs, const std::vector<XPathExpressionPtr>& args) :
|
||||
args_(args)
|
||||
{
|
||||
if(((minArgs != -1) && (static_cast<int>(args.size()) < minArgs)) ||
|
||||
((maxArgs != -1) && (static_cast<int>(args.size()) > maxArgs)))
|
||||
throw SyntaxException("wrong number of arguments to function");
|
||||
} // XPathFunction
|
||||
|
||||
public:
|
||||
virtual ~XPathFunction() { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const = 0;
|
||||
|
||||
protected:
|
||||
size_t argCount() const { return args_.size(); }
|
||||
|
||||
bool argAsBool(size_t index,
|
||||
const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return args_[index]->evaluate(context, executionContext)->asBool();
|
||||
} // argAsBool
|
||||
|
||||
double argAsNumber(size_t index,
|
||||
const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return args_[index]->evaluate(context, executionContext)->asNumber();
|
||||
} // argAsNumber
|
||||
|
||||
std::string argAsString(size_t index,
|
||||
const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return args_[index]->evaluate(context, executionContext)->asString();
|
||||
} // argAsString
|
||||
|
||||
NodeSet argAsNodeSet(size_t index,
|
||||
const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return args_[index]->evaluate(context, executionContext)->asNodeSet();
|
||||
} // argAsNodeSet
|
||||
|
||||
private:
|
||||
const std::vector<XPathExpressionPtr> args_;
|
||||
}; // class XPathFunction
|
||||
|
||||
////////////////////////////////
|
||||
// node-set functions
|
||||
// number last()
|
||||
class LastFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
LastFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 0, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(executionContext.last());
|
||||
} // evaluate
|
||||
}; // class LastFn
|
||||
|
||||
// number position()
|
||||
class PositionFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
PositionFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 0, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(executionContext.position());
|
||||
} // evaluate
|
||||
}; // class PositionFn
|
||||
|
||||
// number count(node-set)
|
||||
class CountFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
CountFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(argAsNodeSet(0, context, executionContext).size());
|
||||
} // evaluate
|
||||
}; // class CountFn
|
||||
|
||||
// node-set id(object)
|
||||
// string local-name(node-set?)
|
||||
class LocalNameFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
LocalNameFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
DOM::Node<std::string> node;
|
||||
if(argCount() == 0)
|
||||
node = context;
|
||||
else
|
||||
{
|
||||
NodeSet ns = argAsNodeSet(0, context, executionContext);
|
||||
if(ns.size() != 0)
|
||||
node = ns.top();
|
||||
} // if ...
|
||||
|
||||
if(node != 0)
|
||||
switch(node.getNodeType())
|
||||
{
|
||||
case DOM::Node_base::ATTRIBUTE_NODE:
|
||||
case DOM::Node_base::ELEMENT_NODE:
|
||||
case DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
|
||||
return new StringValue(node.hasNamespaceURI() ? node.getLocalName() : node.getNodeName());
|
||||
} // switch ...
|
||||
return new StringValue("");
|
||||
} // evaluate
|
||||
}; // class LocalNameFn
|
||||
|
||||
// string namespace-uri(node-set?)
|
||||
class NamespaceURIFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
NamespaceURIFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
DOM::Node<std::string> node;
|
||||
if(argCount() == 0)
|
||||
node = context;
|
||||
else
|
||||
{
|
||||
NodeSet ns = argAsNodeSet(0, context, executionContext);
|
||||
if(ns.size() != 0)
|
||||
node = ns.top();
|
||||
} // if ...
|
||||
|
||||
if(node != 0)
|
||||
switch(node.getNodeType())
|
||||
{
|
||||
case DOM::Node_base::ATTRIBUTE_NODE:
|
||||
case DOM::Node_base::ELEMENT_NODE:
|
||||
return new StringValue(node.getNamespaceURI());
|
||||
} // switch ...
|
||||
return new StringValue("");
|
||||
} // evaluate
|
||||
}; // class NamespaceURIFn
|
||||
|
||||
// string name(node-set?)
|
||||
class NameFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
NameFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
DOM::Node<std::string> node;
|
||||
if(argCount() == 0)
|
||||
node = context;
|
||||
else
|
||||
{
|
||||
NodeSet ns = argAsNodeSet(0, context, executionContext);
|
||||
if(ns.size() != 0)
|
||||
node = ns.top();
|
||||
} // if ...
|
||||
|
||||
if(node != 0)
|
||||
switch(node.getNodeType())
|
||||
{
|
||||
case DOM::Node_base::ATTRIBUTE_NODE:
|
||||
case DOM::Node_base::ELEMENT_NODE:
|
||||
case DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
|
||||
return new StringValue(node.getNodeName());
|
||||
} // switch ...
|
||||
return new StringValue("");
|
||||
} // evaluate
|
||||
}; // class NameFn
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// string functions
|
||||
|
||||
// string string(object?)
|
||||
class StringFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
StringFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new StringValue((argCount() > 0) ? argAsString(0, context, executionContext) : nodeStringValue(context));
|
||||
} // evaluate
|
||||
}; // class StringFn
|
||||
|
||||
// string concat(string, string, string*)
|
||||
class ConcatFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
ConcatFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(2, -1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string s;
|
||||
for(size_t a = 0, ae = argCount(); a < ae; ++a)
|
||||
s.append(argAsString(a, context, executionContext));
|
||||
return new StringValue(s);
|
||||
} // evaluate
|
||||
}; // ConcatFn
|
||||
|
||||
// boolean starts-with(string, string)
|
||||
class StartsWithFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
StartsWithFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(2, 2, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string value = argAsString(0, context, executionContext);
|
||||
std::string start = argAsString(1, context, executionContext);
|
||||
|
||||
if(value.length() < start.length())
|
||||
return new BoolValue(false);
|
||||
|
||||
for(size_t i = 0, ie = start.length(); i < ie; ++i)
|
||||
if(value[i] != start[i])
|
||||
return new BoolValue(false);
|
||||
|
||||
return new BoolValue(true);
|
||||
} // evaluate
|
||||
}; // StartsWithFn
|
||||
|
||||
// boolean contains(string, string)
|
||||
class ContainsFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
ContainsFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(2, 2, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new BoolValue(argAsString(0, context, executionContext).find(argAsString(1, context, executionContext)) != std::string::npos);
|
||||
} // evaluate
|
||||
}; // class ContainsFn
|
||||
|
||||
// string substring-before(string, string)
|
||||
class SubstringBeforeFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
SubstringBeforeFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(2, 2, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string value = argAsString(0, context, executionContext);
|
||||
size_t splitAt = value.find(argAsString(1, context, executionContext));
|
||||
|
||||
if(splitAt == std::string::npos)
|
||||
return new StringValue("");
|
||||
|
||||
return new StringValue(value.substr(0, splitAt));
|
||||
} // evaluate
|
||||
}; // class SubstringBeforeFn
|
||||
|
||||
// string substring-after(string, string)
|
||||
class SubstringAfterFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
SubstringAfterFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(2, 2, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string value = argAsString(0, context, executionContext);
|
||||
std::string split = argAsString(1, context, executionContext);
|
||||
size_t splitAt = value.find(split);
|
||||
|
||||
if((splitAt == std::string::npos) || ((splitAt + split.length()) >= value.length()))
|
||||
return new StringValue("");
|
||||
|
||||
return new StringValue(value.substr(splitAt + split.length()));
|
||||
} // evaluate
|
||||
}; // class SubstringAfterFn
|
||||
|
||||
// string substring(string, number, number?)
|
||||
class SubstringFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
SubstringFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(2, 3, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string value = argAsString(0, context, executionContext);
|
||||
double startAt = roundNumber(argAsNumber(1, context, executionContext)) - 1;
|
||||
double endAt = roundNumber((argCount() == 3 ? argAsNumber(2, context, executionContext) : Infinity)) + startAt;
|
||||
|
||||
if((endAt < 0) || (endAt < startAt))
|
||||
return new StringValue("");
|
||||
|
||||
if(startAt < 0)
|
||||
startAt = 0;
|
||||
if((isInfinite(endAt)) || (endAt > value.length()))
|
||||
endAt = value.length();
|
||||
|
||||
return new StringValue(value.substr(static_cast<int>(startAt), static_cast<int>(endAt - startAt)));
|
||||
} // evaluate
|
||||
}; // SubstringFn
|
||||
|
||||
// number string-length(string?)
|
||||
class StringLengthFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
StringLengthFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(((argCount() > 0) ? argAsString(0, context, executionContext) : nodeStringValue(context)).length());
|
||||
} // evaluate
|
||||
}; // StringLengthFn
|
||||
|
||||
// string normalize-space(string?)
|
||||
class NormalizeSpaceFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
NormalizeSpaceFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string value = ((argCount() > 0) ? argAsString(0, context, executionContext) : nodeStringValue(context));
|
||||
size_t i = 0, ie = value.length();
|
||||
|
||||
// string leading space
|
||||
while((i != ie) && (XML::is_space(static_cast<wchar_t>(value[i]))))
|
||||
++i;
|
||||
|
||||
size_t p = 0;
|
||||
while(i != ie)
|
||||
{
|
||||
while((i != ie) && (!XML::is_space(static_cast<wchar_t>(value[i]))))
|
||||
value[p++] = value[i++];
|
||||
while((i != ie) && (XML::is_space(static_cast<wchar_t>(value[i]))))
|
||||
++i;
|
||||
if(i != ie)
|
||||
value[p++] = Unicode<char>::SPACE;
|
||||
} // while ...
|
||||
if(p != ie)
|
||||
value.resize(p);
|
||||
|
||||
return new StringValue(value);
|
||||
} // evaluate
|
||||
}; // class NormalizeSpaceFn
|
||||
|
||||
// string translate(string, string, string)
|
||||
class TranslateFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
TranslateFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(3, 3, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
std::string str = argAsString(0, context, executionContext);
|
||||
std::string from = argAsString(1, context, executionContext);
|
||||
std::string to = argAsString(2, context, executionContext);
|
||||
|
||||
size_t p = 0;
|
||||
for(size_t i = 0, ie = str.length(); i != ie; ++i)
|
||||
{
|
||||
size_t r = from.find(str[i]);
|
||||
if(r == std::string::npos)
|
||||
++p;
|
||||
else if(r < to.length())
|
||||
str[p++] = to[r];
|
||||
} // for ...
|
||||
if(p != str.length())
|
||||
str.resize(p);
|
||||
|
||||
return new StringValue(str);
|
||||
} // evaluate
|
||||
}; // class TranslateFn
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// boolean functions
|
||||
|
||||
// boolean boolean(object)
|
||||
class BooleanFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
BooleanFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new BoolValue(argAsBool(0, context, executionContext));
|
||||
} // evaluate
|
||||
}; // class BooleanFn
|
||||
|
||||
// boolean not(boolean)
|
||||
class NotFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
NotFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new BoolValue(!argAsBool(0, context, executionContext));
|
||||
}
|
||||
}; // class NotFn
|
||||
|
||||
// boolean true()
|
||||
class TrueFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
TrueFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 0, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new BoolValue(true);
|
||||
} // evaluate
|
||||
}; // TrueFn
|
||||
|
||||
// boolean false()
|
||||
class FalseFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
FalseFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 0, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new BoolValue(false);
|
||||
} // evaluate
|
||||
}; // FalseFn
|
||||
|
||||
// boolean lang(string)
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// number functions
|
||||
|
||||
// number number(object?)
|
||||
class NumberFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
NumberFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(0, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
double result = (argCount() > 0) ? argAsNumber(0, context, executionContext) :
|
||||
StringValue(nodeStringValue(context)).asNumber();
|
||||
return new NumericValue(result);
|
||||
} // evaluate
|
||||
}; // NumberFn
|
||||
|
||||
// number sum(node-set)
|
||||
class SumFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
SumFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
double sum = 0;
|
||||
NodeSet ns = argAsNodeSet(0, context, executionContext);
|
||||
for(NodeSet::const_iterator n = ns.begin(), end = ns.end(); n != end; ++n)
|
||||
sum += nodeNumberValue(*n);
|
||||
return new NumericValue(sum);
|
||||
} // evaluate
|
||||
}; // class SumFn
|
||||
|
||||
// number floor(number)
|
||||
class FloorFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
FloorFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(std::floor(argAsNumber(0, context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class FloorFn
|
||||
|
||||
// number ceiling(number)
|
||||
class CeilingFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
CeilingFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(std::ceil(argAsNumber(0, context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class CeilingFn
|
||||
|
||||
// number round(number)
|
||||
class RoundFn : public XPathFunction
|
||||
{
|
||||
public:
|
||||
RoundFn(const std::vector<XPathExpressionPtr>& args) : XPathFunction(1, 1, args) { }
|
||||
|
||||
virtual XPathValue* evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return new NumericValue(roundNumber(argAsNumber(0, context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class RoundFn
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
92
XPath/impl/xpath_function_holder.hpp
Normal file
92
XPath/impl/xpath_function_holder.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#ifndef ARABICA_XPATH_FUNCTION_HOLDER_HPP
|
||||
#define ARABICA_XPATH_FUNCTION_HOLDER_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "xpath_value.hpp"
|
||||
#include "xpath_function.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
template<class function_type>
|
||||
XPathFunction* CreateFn(const std::vector<XPathExpressionPtr>& argExprs) { return new function_type(argExprs); }
|
||||
|
||||
typedef XPathFunction* (*CreateFnPtr)(const std::vector<XPathExpressionPtr>& argExprs);
|
||||
|
||||
struct NamedFunction { const char* name; CreateFnPtr creator; };
|
||||
|
||||
const NamedFunction FunctionLookupTable[] = { // node-set functions
|
||||
{ "position", CreateFn<PositionFn> },
|
||||
{ "last", CreateFn<LastFn> },
|
||||
{ "count", CreateFn<CountFn> },
|
||||
{ "local-name", CreateFn<LocalNameFn> },
|
||||
{ "namespace-uri", CreateFn<NamespaceURIFn> },
|
||||
{ "name", CreateFn<NameFn> },
|
||||
// string functions
|
||||
{"string", CreateFn<StringFn> },
|
||||
{"concat", CreateFn<ConcatFn> },
|
||||
{"starts-with", CreateFn<StartsWithFn> },
|
||||
{"contains", CreateFn<ContainsFn> },
|
||||
{"substring-before", CreateFn<SubstringBeforeFn> },
|
||||
{"substring-after", CreateFn<SubstringAfterFn> },
|
||||
{"substring", CreateFn<SubstringFn> },
|
||||
{"string-length", CreateFn<StringLengthFn> },
|
||||
{"normalize-space", CreateFn<NormalizeSpaceFn> },
|
||||
{"translate", CreateFn<TranslateFn> },
|
||||
// boolean functions
|
||||
{"boolean", CreateFn<BooleanFn> },
|
||||
{"not", CreateFn<NotFn> },
|
||||
{"true", CreateFn<TrueFn> },
|
||||
{"false", CreateFn<FalseFn> },
|
||||
// number functions
|
||||
{"number", CreateFn<NumberFn> },
|
||||
{"sum", CreateFn<SumFn> },
|
||||
{"floor", CreateFn<FloorFn> },
|
||||
{"ceiling", CreateFn<CeilingFn> },
|
||||
{"round", CreateFn<RoundFn> },
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
class FunctionHolder : public XPathExpression
|
||||
{
|
||||
public:
|
||||
FunctionHolder(XPathFunction* func) :
|
||||
func_(func)
|
||||
{
|
||||
} // FunctionHolder
|
||||
|
||||
virtual ~FunctionHolder()
|
||||
{
|
||||
delete func_;
|
||||
} // ~FunctionHolder
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return XPathValuePtr(func_->evaluate(context, executionContext));
|
||||
} // evaluate
|
||||
|
||||
static FunctionHolder* createFunction(const std::string& name,
|
||||
const std::vector<XPathExpressionPtr>& argExprs,
|
||||
const CompilationContext& context)
|
||||
{
|
||||
for(const NamedFunction* fn = FunctionLookupTable; fn->name != 0; ++fn)
|
||||
if(name == fn->name)
|
||||
return new FunctionHolder(fn->creator(argExprs));
|
||||
|
||||
XPathFunction* func = context.functionResolver().resolveFunction(name, argExprs);
|
||||
if(func == 0)
|
||||
throw std::runtime_error("Function " + name + " not implemented");
|
||||
return new FunctionHolder(func);
|
||||
} // createFunction
|
||||
|
||||
private:
|
||||
XPathFunction* func_;
|
||||
}; // class FunctionResolver
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
44
XPath/impl/xpath_function_resolver.hpp
Normal file
44
XPath/impl/xpath_function_resolver.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef ARABICA_XPATH_FUNCTION_RESOLVER_HPP
|
||||
#define ARABICA_XPATH_FUNCTION_RESOLVER_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class XPathFunction;
|
||||
class XPathExpression;
|
||||
typedef boost::shared_ptr<XPathExpression> XPathExpressionPtr;
|
||||
|
||||
class UndefinedFunctionException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
UndefinedFunctionException(const std::string& thing) : std::runtime_error("The function '" + thing + "' is undefined.") { }
|
||||
}; // class UndefinedFunctionException
|
||||
|
||||
class FunctionResolver
|
||||
{
|
||||
public:
|
||||
// TODO: should make this a QName
|
||||
virtual XPathFunction* resolveFunction(const std::string& name,
|
||||
const std::vector<XPathExpressionPtr>& argExprs) const = 0;
|
||||
}; // class FunctionResolver
|
||||
|
||||
typedef boost::shared_ptr<FunctionResolver> FunctionResolverPtr;
|
||||
|
||||
class NullFunctionResolver : public FunctionResolver
|
||||
{
|
||||
public:
|
||||
virtual XPathFunction* resolveFunction(const std::string& name,
|
||||
const std::vector<XPathExpressionPtr>& argExprs) const
|
||||
{
|
||||
throw UndefinedFunctionException(name);
|
||||
} // resolveVariable
|
||||
}; // NullFunctionResolver
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
329
XPath/impl/xpath_grammar.hpp
Normal file
329
XPath/impl/xpath_grammar.hpp
Normal file
|
@ -0,0 +1,329 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_GRAMMER_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_GRAMMER_HPP
|
||||
|
||||
#define BOOST_SPIRIT_DEBUG
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/phoenix/primitives.hpp>
|
||||
#include <boost/spirit/symbols/symbols.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "xpath_ast_ids.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
template<typename ScannerT>
|
||||
struct xpath_grammar_definition
|
||||
{
|
||||
xpath_grammar_definition()
|
||||
{
|
||||
using namespace boost::spirit;
|
||||
|
||||
// [1]
|
||||
LocationPath = AbsoluteLocationPath | RelativeLocationPath;
|
||||
// [2]
|
||||
AbsoluteLocationPath = AbbreviatedAbsoluteLocationPath
|
||||
| (Slash >> !RelativeLocationPath);
|
||||
// [3]
|
||||
RelativeLocationPath = Step >> *((SlashSlash | discard_node_d[Slash]) >> Step);
|
||||
|
||||
// [4], [5]
|
||||
Step = AxisSpecifier >> NodeTest >> *Predicate | AbbreviatedStep;
|
||||
AxisSpecifier = S >> ( AxisName >> S >> "::" | AbbreviatedAxisSpecifier ) >> S;
|
||||
|
||||
// [6]
|
||||
AxisName = AncestorOrSelf
|
||||
| Ancestor
|
||||
| Attribute
|
||||
| Child
|
||||
| DescendantOrSelf
|
||||
| Descendant
|
||||
| FollowingSibling
|
||||
| Following
|
||||
| Namespace
|
||||
| Parent
|
||||
| PrecedingSibling
|
||||
| Preceding
|
||||
| Self;
|
||||
|
||||
// [7]
|
||||
NodeTest = S >>(ProcessingInstruction >> S >> discard_node_d[ch_p('(')] >> S >> Literal >> S >> discard_node_d[ch_p(')')]
|
||||
| NodeType >> S >> discard_node_d[ch_p('(')] >> S >> discard_node_d[ch_p(')')]
|
||||
| NameTest )
|
||||
>> S;
|
||||
|
||||
// [8], [9]
|
||||
Predicate = S >> LeftSquare >> PredicateExpr >> RightSquare >> S;
|
||||
PredicateExpr = Expr;
|
||||
|
||||
// [10]
|
||||
AbbreviatedAbsoluteLocationPath = SlashSlash >> RelativeLocationPath;
|
||||
// [11] AbbreviatedRelativeLocationPath eliminated
|
||||
// [12], [13]
|
||||
AbbreviatedStep = ParentSelect | SelfSelect;
|
||||
AbbreviatedAxisSpecifier = !ch_p('@');
|
||||
|
||||
// [14], [15]
|
||||
Expr = OrExpr;
|
||||
PrimaryExpr = discard_node_d[S] >>
|
||||
(VariableReference
|
||||
| Number
|
||||
| FunctionCall
|
||||
| inner_node_d[ch_p('(') >> S >> Expr >> S >> ch_p(')')]
|
||||
| Literal) >>
|
||||
discard_node_d[S];
|
||||
|
||||
// [16], [17]
|
||||
FunctionCall = FunctionName >> S >> LeftBracket >> !(Argument >> *(discard_node_d[ch_p(',')] >> S >> Argument)) >> S >> RightBracket >> S;
|
||||
Argument = Expr;
|
||||
|
||||
// [18], [19], [20]
|
||||
// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
|
||||
UnionExpr = PathExpr >> *(UnionOperator >> PathExpr);
|
||||
/*
|
||||
LocationPath
|
||||
| FilterExpr
|
||||
| FilterExpr '/' RelativeLocationPath
|
||||
| FilterExpr '//' RelativeLocationPath */
|
||||
PathExpr = discard_node_d[S] >>
|
||||
(FilterExpr >> !((SlashSlash | Slash) >> RelativeLocationPath)
|
||||
| LocationPath) >>
|
||||
discard_node_d[S];
|
||||
// FilterExpr ::= PrimaryExpr | FilterExpr Predicate
|
||||
FilterExpr = PrimaryExpr >> *Predicate;
|
||||
|
||||
// [21], [22], [23], [24]
|
||||
OrExpr = AndExpr >> *(OrOperator >> AndExpr);
|
||||
AndExpr = EqualityExpr >> *(AndOperator >> EqualityExpr);
|
||||
EqualityExpr = RelationalExpr >> *((EqualsOperator | NotEqualsOperator) >> RelationalExpr);
|
||||
RelationalExpr = AdditiveExpr >> *((LessThanEqualsOperator | GreaterThanEqualsOperator | LessThanOperator |GreaterThanOperator) >> AdditiveExpr);
|
||||
|
||||
// [25], [26], [27]
|
||||
AdditiveExpr = MultiplicativeExpr >> *((PlusOperator | MinusOperator) >> MultiplicativeExpr);
|
||||
MultiplicativeExpr = UnaryExpr >> *(token_node_d[(MultiplyOperator | DivOperator | ModOperator)] >> UnaryExpr);
|
||||
UnaryExpr = discard_node_d[S] >> *(UnaryMinusOperator) >> UnionExpr;
|
||||
|
||||
// [28] ExprToken not actually used
|
||||
|
||||
//[29], [30], [31],
|
||||
Literal = inner_node_d[ch_p('\"') >> token_node_d[*~ch_p('\"')] >> '\"']
|
||||
| inner_node_d[ch_p('\'') >> token_node_d[*~ch_p('\'')] >> '\''];
|
||||
Number = token_node_d[ch_p('.') >> Digits | Digits >> !('.' >> *Digits)];
|
||||
Digits = token_node_d[+digit_p];
|
||||
// [32] Operator not actually used
|
||||
// [33] OperatorName not actually used
|
||||
// [34], [35], [36], [37], [38], [39]
|
||||
MultiplyOperator = ch_p('*');
|
||||
FunctionName = QName - NodeType;
|
||||
VariableReference = token_node_d[ch_p('$') >> QName];
|
||||
NameTest = AnyName
|
||||
| NCName >> discard_node_d[ch_p(':')] >> AnyName
|
||||
| QName;
|
||||
NodeType = Comment
|
||||
| Text
|
||||
| ProcessingInstruction
|
||||
| Node;
|
||||
|
||||
// These aren't correct to spec yet :)
|
||||
S = *space_p;
|
||||
QName = !(Prefix >> discard_node_d[ch_p(':')]) >> LocalPart;
|
||||
Prefix = NCName;
|
||||
LocalPart = NCName;
|
||||
NCName = token_node_d[(alpha_p | '_') >> *NCNameChar];
|
||||
NCNameChar = alpha_p | digit_p | '.' | '-' | '_';
|
||||
|
||||
// things not defined in the spec, but which are just kind of handy :)
|
||||
Slash = ch_p('/');
|
||||
SlashSlash = str_p("//");
|
||||
|
||||
AncestorOrSelf = str_p("ancestor-or-self");
|
||||
Ancestor = str_p("ancestor");
|
||||
Attribute = str_p("attribute");
|
||||
Child = str_p("child");
|
||||
DescendantOrSelf = str_p("descendant-or-self");
|
||||
Descendant = str_p("descendant");
|
||||
FollowingSibling = str_p("following-sibling");
|
||||
Following = str_p("following");
|
||||
Namespace = str_p("namespace");
|
||||
Parent = str_p("parent");
|
||||
PrecedingSibling = str_p("preceding-sibling");
|
||||
Preceding = str_p("preceding");
|
||||
Self = str_p("self");
|
||||
|
||||
Comment = str_p("comment");
|
||||
Text = str_p("text");
|
||||
ProcessingInstruction = str_p("processing-instruction");
|
||||
Node = str_p("node");
|
||||
AnyName = ch_p('*');
|
||||
|
||||
SelfSelect = ch_p('.');
|
||||
ParentSelect = str_p("..");
|
||||
|
||||
LeftSquare = ch_p('[');
|
||||
RightSquare = ch_p(']');
|
||||
|
||||
LeftBracket = ch_p('(');
|
||||
RightBracket = ch_p(')');
|
||||
|
||||
PlusOperator = ch_p('+');
|
||||
MinusOperator = ch_p('-');
|
||||
ModOperator = str_p("mod");
|
||||
DivOperator = str_p("div");
|
||||
EqualsOperator = ch_p('=');
|
||||
NotEqualsOperator = str_p("!=");
|
||||
LessThanOperator = ch_p('<');
|
||||
LessThanEqualsOperator = str_p("<=");
|
||||
GreaterThanOperator = ch_p('>');
|
||||
GreaterThanEqualsOperator = str_p(">=");
|
||||
|
||||
OrOperator = str_p("or");
|
||||
AndOperator = str_p("and");
|
||||
UnionOperator = ch_p('|');
|
||||
UnaryMinusOperator = ch_p('-');
|
||||
} // xpath_grammar_definition
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<QName_id> > QName;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Prefix_id> > Prefix;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LocalPart_id> > LocalPart;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<NCName_id> > NCName;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<NCNameChar_id> > NCNameChar;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AxisName_id> > AxisName;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<NodeType_id> > NodeType;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LocationPath_id> > LocationPath;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AbsoluteLocationPath_id> > AbsoluteLocationPath;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<RelativeLocationPath_id> > RelativeLocationPath;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Step_id> > Step;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AxisSpecifier_id> > AxisSpecifier;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<NodeTest_id> > NodeTest;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Predicate_id> > Predicate;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<PredicateExpr_id> > PredicateExpr;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AbbreviatedAbsoluteLocationPath_id> > AbbreviatedAbsoluteLocationPath;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AbbreviatedStep_id> > AbbreviatedStep;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AbbreviatedAxisSpecifier_id> > AbbreviatedAxisSpecifier;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Expr_id> > Expr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<PrimaryExpr_id> > PrimaryExpr;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<FunctionCall_id> > FunctionCall;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Argument_id> > Argument;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<UnionExpr_id> > UnionExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<PathExpr_id> > PathExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<FilterExpr_id> > FilterExpr;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<OrExpr_id> > OrExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AndExpr_id> > AndExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<EqualityExpr_id> > EqualityExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<RelationalExpr_id> > RelationalExpr;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AdditiveExpr_id> > AdditiveExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<MultiplicativeExpr_id> > MultiplicativeExpr;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<UnaryExpr_id> > UnaryExpr;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Literal_id> > Literal;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Number_id> > Number;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Digits_id> > Digits;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<MultiplyOperator_id> > MultiplyOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<FunctionName_id> > FunctionName;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<VariableReference_id> > VariableReference;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<NameTest_id> > NameTest;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<S_id> > S; // ExprWhitespace
|
||||
|
||||
// bonus bits
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Slash_id> > Slash;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<SlashSlash_id> > SlashSlash;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AncestorOrSelf_id> > AncestorOrSelf;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Ancestor_id> > Ancestor;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Attribute_id> > Attribute;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Child_id> > Child;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<DescendantOrSelf_id> > DescendantOrSelf;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Descendant_id> > Descendant;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<FollowingSibling_id> > FollowingSibling;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Following_id> > Following;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Namespace_id> > Namespace;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Parent_id> > Parent;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<PrecedingSibling_id> > PrecedingSibling;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Preceding_id> > Preceding;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Self_id> > Self;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Comment_id> > Comment;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Text_id> > Text;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<ProcessingInstruction_id> > ProcessingInstruction;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Node_id> > Node;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AnyName_id> > AnyName;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<SelfSelect_id> > SelfSelect;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<ParentSelect_id> > ParentSelect;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LeftSquare_id> > LeftSquare;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<RightSquare_id> > RightSquare;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LeftBracket_id> > LeftBracket;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<RightBracket_id> > RightBracket;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<PlusOperator_id> > PlusOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<MinusOperator_id> > MinusOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<ModOperator_id> > ModOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<DivOperator_id> > DivOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<EqualsOperator_id> > EqualsOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<NotEqualsOperator_id> > NotEqualsOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LessThanOperator_id> > LessThanOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LessThanEqualsOperator_id> > LessThanEqualsOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<GreaterThanOperator_id> > GreaterThanOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<GreaterThanEqualsOperator_id> > GreaterThanEqualsOperator;
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<OrOperator_id> > OrOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<AndOperator_id> > AndOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<UnionOperator_id> > UnionOperator;
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<UnaryMinusOperator_id> > UnaryMinusOperator;
|
||||
}; // xpath_grammar_definition
|
||||
|
||||
|
||||
struct xpath_grammar : public boost::spirit::grammar<xpath_grammar>
|
||||
{
|
||||
template<typename ScannerT>
|
||||
struct definition : public xpath_grammar_definition<ScannerT>
|
||||
{
|
||||
definition(xpath_grammar const& /* self */)
|
||||
{
|
||||
} // definition
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<LocationPath_id> > const&
|
||||
start() const
|
||||
{
|
||||
return xpath_grammar_definition<ScannerT>::LocationPath;
|
||||
} // start
|
||||
}; // definition<ScannerT>
|
||||
}; // xpath_grammar
|
||||
|
||||
struct xpath_grammar_expr : public boost::spirit::grammar<xpath_grammar_expr>
|
||||
{
|
||||
template<typename ScannerT>
|
||||
struct definition : public xpath_grammar_definition<ScannerT>
|
||||
{
|
||||
definition(xpath_grammar_expr const& /* self */)
|
||||
{
|
||||
} // definition
|
||||
|
||||
boost::spirit::rule<ScannerT, boost::spirit::parser_tag<Expr_id> > const&
|
||||
start() const
|
||||
{
|
||||
return xpath_grammar_definition<ScannerT>::Expr;
|
||||
} // start
|
||||
}; // definition<ScannerT>
|
||||
}; // xpath_grammar
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
53
XPath/impl/xpath_logical.hpp
Normal file
53
XPath/impl/xpath_logical.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_LOGICAL_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_LOGICAL_HPP
|
||||
|
||||
#include "xpath_value.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class OrOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
OrOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
// From XPath 1.0 Rec, section 3.4
|
||||
// An or expression is evaluated by evaluating each operand and converting its value
|
||||
// to a boolean as if by a call to the boolean function. The result is true if either
|
||||
// value is true and false otherwise. The right operand is not evaluated if the
|
||||
// left operand evaluates to true.
|
||||
if(lhs()->evaluate(context, executionContext)->asBool())
|
||||
return BoolValue::createValue(true);
|
||||
return BoolValue::createValue(rhs()->evaluate(context, executionContext)->asBool());
|
||||
} // evaluate
|
||||
}; // class OrOperator
|
||||
|
||||
class AndOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
AndOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
// From XPath 1.0 Rec, section 3.4
|
||||
// An and expression is evaluated by evaluating each operand and converting its value
|
||||
// to a boolean as if by a call to the boolean function. The result is true if both
|
||||
// values are true and false otherwise. The right operand is not evaluated if the left
|
||||
// operand evaluates to false.
|
||||
if(!lhs()->evaluate(context, executionContext)->asBool())
|
||||
return BoolValue::createValue(false);
|
||||
return BoolValue::createValue(rhs()->evaluate(context, executionContext)->asBool());
|
||||
} // evaluate
|
||||
}; // class AndOperator
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
#endif
|
76
XPath/impl/xpath_namespace_context.hpp
Normal file
76
XPath/impl/xpath_namespace_context.hpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#ifndef ARABICA_XPATH_NAMESPACE_CONTEXT_HPP
|
||||
#define ARABICA_XPATH_NAMESPACE_CONTEXT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class UnboundNamespacePrefixException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
UnboundNamespacePrefixException(const std::string& thing) : std::runtime_error("The prefix '" + thing + "' is not bound to a namespace URI") { }
|
||||
}; // class UnboundNamespacePrefixException
|
||||
|
||||
class NamespaceContext
|
||||
{
|
||||
public:
|
||||
NamespaceContext() { }
|
||||
virtual ~NamespaceContext() = 0 { }
|
||||
|
||||
virtual std::string namespaceURI(const std::string& prefix) const = 0;
|
||||
|
||||
virtual NamespaceContext* clone() const = 0;
|
||||
|
||||
private:
|
||||
NamespaceContext(const NamespaceContext&);
|
||||
NamespaceContext& operator=(const NamespaceContext&);
|
||||
bool operator==(const NamespaceContext&) const;
|
||||
}; // class NamespaceContext
|
||||
|
||||
typedef boost::shared_ptr<NamespaceContext> NamespaceContextPtr;
|
||||
|
||||
class NullNamespaceContext : public NamespaceContext
|
||||
{
|
||||
public:
|
||||
virtual std::string namespaceURI(const std::string& prefix) const { throw UnboundNamespacePrefixException(prefix); }
|
||||
virtual NamespaceContext* clone() const { return new NullNamespaceContext; }
|
||||
}; // class NullNamespaceContext
|
||||
|
||||
class StandardNamespaceContext : public NamespaceContext
|
||||
{
|
||||
public:
|
||||
StandardNamespaceContext() { }
|
||||
~StandardNamespaceContext() { }
|
||||
|
||||
virtual std::string namespaceURI(const std::string& prefix) const
|
||||
{
|
||||
NSMap::const_iterator n = map_.find(prefix);
|
||||
if(n == map_.end())
|
||||
throw UnboundNamespacePrefixException(prefix);
|
||||
return (*n).second;
|
||||
} // namespaceURI
|
||||
|
||||
void addNamespaceDeclaration(const std::string& namespaceURI, const std::string& prefix)
|
||||
{
|
||||
map_[prefix] = namespaceURI;
|
||||
} // addNamespaceDeclaration
|
||||
|
||||
virtual StandardNamespaceContext* clone() const { return new StandardNamespaceContext(*this); }
|
||||
|
||||
private:
|
||||
StandardNamespaceContext(const StandardNamespaceContext& rhs) : map_(rhs.map_) { }
|
||||
|
||||
typedef std::map<std::string, std::string> NSMap;
|
||||
NSMap map_;
|
||||
}; // class StandardNamespaceContext
|
||||
|
||||
} // namespace XPath
|
||||
|
||||
} // namespace Arabica
|
||||
#endif
|
82
XPath/impl/xpath_namespace_node.hpp
Normal file
82
XPath/impl/xpath_namespace_node.hpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_NAMESPACE_NODE_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_NAMESPACE_NODE_HPP
|
||||
|
||||
#pragma warning(disable: 4250)
|
||||
|
||||
#include <DOM/Simple/DocumentImpl.h>
|
||||
#include <DOM/Simple/NodeImpl.h>
|
||||
#include <SAX/helpers/StringAdaptor.h>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
const DOM::Node_base::Type NAMESPACE_NODE_TYPE = static_cast<DOM::Node_base::Type>(DOM::Node_base::MAX_TYPE + 27); // 27 is a random choice
|
||||
|
||||
template<class stringT, class string_adaptorT = SAX::default_string_adaptor<stringT> >
|
||||
class NamespaceNodeImpl : public SimpleDOM::ChildlessNodeImpl<stringT, string_adaptorT>
|
||||
{
|
||||
typedef SimpleDOM::ChildlessNodeImpl<stringT, string_adaptorT> NodeT;
|
||||
public:
|
||||
NamespaceNodeImpl(stringT localname,
|
||||
stringT value) :
|
||||
SimpleDOM::ChildlessNodeImpl<stringT, string_adaptorT>(0),
|
||||
localname_(localname),
|
||||
value_(value),
|
||||
ref_(0)
|
||||
{
|
||||
this->setReadOnly(true);
|
||||
} // NamespaceNodeImpl
|
||||
|
||||
virtual ~NamespaceNodeImpl() { }
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// DOM::Node methods
|
||||
virtual DOM::Node_base::Type getNodeType() const
|
||||
{
|
||||
return NAMESPACE_NODE_TYPE;
|
||||
} // getNodeType
|
||||
|
||||
virtual stringT getNodeName() const
|
||||
{
|
||||
return localname_;
|
||||
} // getNodeName
|
||||
|
||||
virtual stringT getNodeValue() const
|
||||
{
|
||||
return value_;
|
||||
} // getNodeValue
|
||||
|
||||
virtual stringT getLocalName() const
|
||||
{
|
||||
return localname_;
|
||||
} // getNodeName
|
||||
|
||||
virtual DOM::Node_impl<stringT>* cloneNode(bool deep) const
|
||||
{
|
||||
return new NamespaceNodeImpl<stringT, string_adaptorT>(localname_, value_);
|
||||
} // cloneNode
|
||||
|
||||
// not part of the document, so need to manage our own lifetime
|
||||
virtual void addRef()
|
||||
{
|
||||
++ref_;
|
||||
} // addRef
|
||||
|
||||
virtual void releaseRef()
|
||||
{
|
||||
if(!(--ref_))
|
||||
delete this;
|
||||
} // releaseRef
|
||||
|
||||
private:
|
||||
stringT localname_;
|
||||
stringT value_;
|
||||
unsigned int ref_;
|
||||
}; // class NamespaceNodeImpl
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
151
XPath/impl/xpath_node_test.hpp
Normal file
151
XPath/impl/xpath_node_test.hpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_NODE_TEST_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_NODE_TEST_HPP
|
||||
|
||||
#include <DOM/Node.h>
|
||||
#include "xpath_namespace_node.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class NodeTest
|
||||
{
|
||||
protected:
|
||||
NodeTest() { }
|
||||
public:
|
||||
virtual ~NodeTest() { }
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const = 0;
|
||||
|
||||
private:
|
||||
NodeTest(NodeTest&);
|
||||
bool operator==(const NodeTest&);
|
||||
NodeTest& operator=(const NodeTest&);
|
||||
}; // class NodeTest
|
||||
|
||||
class AnyNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
return true;
|
||||
} // matches
|
||||
}; // class AnyNodeTest
|
||||
|
||||
class NameNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
NameNodeTest(const std::string& name) : name_(name) { }
|
||||
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
return (name_ == node.getNodeName()) &&
|
||||
(node.getPrefix().empty());
|
||||
} // test
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
}; // NameNodeTest
|
||||
|
||||
class QNameNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
QNameNodeTest(const std::string& namespace_uri, const std::string& name) : uri_(namespace_uri), name_(name) { }
|
||||
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
return (name_ == node.getLocalName()) &&
|
||||
(uri_ == node.getNamespaceURI());
|
||||
} // test
|
||||
|
||||
private:
|
||||
std::string uri_;
|
||||
std::string name_;
|
||||
}; // QNameNodeTest
|
||||
|
||||
class StarNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
// match the primary node types on the various axis
|
||||
// fortunately they are all independent
|
||||
int type = node.getNodeType();
|
||||
return (type == DOM::Node_base::ELEMENT_NODE ||
|
||||
type == NAMESPACE_NODE_TYPE ||
|
||||
type == DOM::Node_base::ATTRIBUTE_NODE);
|
||||
} // test
|
||||
}; // class StarNodeTest
|
||||
|
||||
class QStarNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
QStarNodeTest(const std::string& namespace_uri) : uri_(namespace_uri) { }
|
||||
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
return (uri_ == node.getNamespaceURI());
|
||||
} // test
|
||||
|
||||
private:
|
||||
std::string uri_;
|
||||
}; // clase QStarNodeTest
|
||||
|
||||
class TextNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
return node.getNodeType() == DOM::Node<std::string>::TEXT_NODE;
|
||||
} // test
|
||||
}; // class TextNodeTest
|
||||
|
||||
class CommentNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
return node.getNodeType() == DOM::Node<std::string>::COMMENT_NODE;
|
||||
} // operator()
|
||||
}; // CommentNodeTest
|
||||
|
||||
class ProcessingInstructionNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
ProcessingInstructionNodeTest() : target_() { }
|
||||
ProcessingInstructionNodeTest(const std::string& target) : target_(target) { }
|
||||
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
if(node.getNodeType() != DOM::Node<std::string>::PROCESSING_INSTRUCTION_NODE)
|
||||
return false;
|
||||
|
||||
if(target_.empty())
|
||||
return true;
|
||||
|
||||
return node.getNodeName() == target_;
|
||||
} // test
|
||||
|
||||
private:
|
||||
std::string target_;
|
||||
}; // ProcessingInstructionNodeTest
|
||||
|
||||
class RootNodeTest : public NodeTest
|
||||
{
|
||||
public:
|
||||
virtual bool operator()(const DOM::Node<std::string>& node) const
|
||||
{
|
||||
int type = node.getNodeType();
|
||||
return (type == DOM::Node<std::string>::DOCUMENT_NODE) ||
|
||||
(type == DOM::Node<std::string>::DOCUMENT_FRAGMENT_NODE);
|
||||
|
||||
} // operator()
|
||||
}; // RootNodeTest
|
||||
|
||||
} // namespace XPath
|
||||
|
||||
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
210
XPath/impl/xpath_object.hpp
Normal file
210
XPath/impl/xpath_object.hpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_OBJECT_H
|
||||
#define ARABICA_XPATHIC_XPATH_OBJECT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <DOM/Node.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <cmath>
|
||||
#include "xpath_execution_context.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class XPathExpression;
|
||||
typedef boost::shared_ptr<XPathExpression> XPathExpressionPtr;
|
||||
class XPathValue;
|
||||
typedef boost::shared_ptr<const XPathValue> XPathValuePtr;
|
||||
|
||||
enum ValueType
|
||||
{
|
||||
ANY ,
|
||||
BOOL,
|
||||
NUMBER,
|
||||
STRING,
|
||||
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);
|
||||
|
||||
class NodeSet : public std::vector<DOM::Node<std::string> >
|
||||
{
|
||||
public:
|
||||
NodeSet() : forward_(true), sorted_(false), std::vector<DOM::Node<std::string> >() { }
|
||||
NodeSet(bool forward) : forward_(forward), sorted_(true), std::vector<DOM::Node<std::string> >() { }
|
||||
NodeSet(const NodeSet& rhs) : forward_(rhs.forward_), sorted_(rhs.sorted_), std::vector<DOM::Node<std::string> >(rhs) { }
|
||||
NodeSet& operator=(const NodeSet& rhs)
|
||||
{
|
||||
forward_ = rhs.forward_;
|
||||
sorted_ = rhs.sorted_;
|
||||
std::vector<DOM::Node<std::string> >::operator=(rhs);
|
||||
return *this;
|
||||
} // operator=
|
||||
|
||||
void swap(NodeSet& rhs)
|
||||
{
|
||||
std::vector<DOM::Node<std::string> >::swap(rhs);
|
||||
std::swap(forward_, rhs.forward_);
|
||||
std::swap(sorted_, rhs.sorted_);
|
||||
} // swap
|
||||
|
||||
bool forward() const { return sorted_ && forward_; }
|
||||
bool reverse() const { return sorted_ && !forward_; }
|
||||
void forward(bool forward) { forward_ = forward; sorted_ = true; }
|
||||
|
||||
void to_document_order()
|
||||
{
|
||||
if(!sorted_)
|
||||
{
|
||||
std::sort(begin(), end(), nodes_less_than);
|
||||
sorted_ = true;
|
||||
forward_ = true;
|
||||
} // if(!sorted)
|
||||
|
||||
if(!forward_)
|
||||
{
|
||||
std::reverse(begin(), end());
|
||||
forward_ = true;
|
||||
} // if(!forward_)
|
||||
} // to_document_order
|
||||
|
||||
DOM::Node<std::string> top() const
|
||||
{
|
||||
if(forward_)
|
||||
return (*this)[0];
|
||||
return (*this)[size()-1];
|
||||
} // top()
|
||||
|
||||
private:
|
||||
bool forward_;
|
||||
bool sorted_;
|
||||
}; // NodeSet
|
||||
|
||||
class XPathValue
|
||||
{
|
||||
protected:
|
||||
XPathValue() { }
|
||||
|
||||
public:
|
||||
virtual ~XPathValue() { }
|
||||
|
||||
virtual bool asBool() const = 0;
|
||||
virtual double asNumber() const = 0;
|
||||
virtual std::string asString() const = 0;
|
||||
virtual const NodeSet& asNodeSet() const = 0;
|
||||
|
||||
virtual ValueType type() const = 0;
|
||||
|
||||
private:
|
||||
XPathValue(const XPathValue&);
|
||||
bool operator==(const XPathValue&);
|
||||
XPathValue& operator=(const XPathValue&);
|
||||
}; // class XPathValue
|
||||
|
||||
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); }
|
||||
|
||||
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
|
||||
|
||||
double stringAsNumber(const std::string& str);
|
||||
double nodeNumberValue(const DOM::Node<std::string>& node);
|
||||
std::string nodeStringValue(const DOM::Node<std::string>& node);
|
||||
|
||||
bool areEqual(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
bool isLessThan(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
bool isLessThanEquals(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
bool isGreaterThan(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
bool isGreaterThanEquals(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
|
||||
|
||||
class XPathExpression
|
||||
{
|
||||
protected:
|
||||
XPathExpression() { }
|
||||
|
||||
public:
|
||||
virtual ~XPathExpression() { }
|
||||
|
||||
XPathValuePtr evaluate(const DOM::Node<std::string>& context) const
|
||||
{
|
||||
ExecutionContext executionContext;
|
||||
return evaluate(context, executionContext);
|
||||
} // evaluate
|
||||
|
||||
virtual bool evaluateAsBool(const DOM::Node<std::string>& context) const { return evaluate(context)->asBool(); }
|
||||
virtual double evaluateAsNumber(const DOM::Node<std::string>& context) const { return evaluate(context)->asNumber(); }
|
||||
virtual std::string evaluateAsString(const DOM::Node<std::string>& context) const { return evaluate(context)->asString(); }
|
||||
virtual NodeSet evaluateAsNodeSet(const DOM::Node<std::string>& context) const { return evaluate(context)->asNodeSet(); }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const Arabica::XPath::ExecutionContext& executionContext) const = 0;
|
||||
|
||||
private:
|
||||
XPathExpression(const XPathExpression&);
|
||||
bool operator==(const XPathExpression&);
|
||||
XPathExpression& operator=(const XPathExpression&);
|
||||
}; // class XPathExpression
|
||||
|
||||
class UnaryExpression
|
||||
{
|
||||
public:
|
||||
UnaryExpression(XPathExpression* expr) :
|
||||
expr_(expr) { }
|
||||
|
||||
protected:
|
||||
~UnaryExpression()
|
||||
{
|
||||
delete expr_;
|
||||
} // ~UnaryExpression
|
||||
|
||||
XPathExpression* expr() const { return expr_; }
|
||||
|
||||
private:
|
||||
XPathExpression* expr_;
|
||||
}; // class UnaryExpression
|
||||
|
||||
class BinaryExpression
|
||||
{
|
||||
public:
|
||||
BinaryExpression(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
lhs_(lhs), rhs_(rhs) { }
|
||||
|
||||
protected:
|
||||
~BinaryExpression()
|
||||
{
|
||||
delete lhs_;
|
||||
delete rhs_;
|
||||
} // ~BinaryExpression
|
||||
|
||||
XPathExpression* lhs() const { return lhs_; }
|
||||
XPathExpression* rhs() const { return rhs_; }
|
||||
|
||||
private:
|
||||
XPathExpression* lhs_;
|
||||
XPathExpression* rhs_;
|
||||
}; // class BinaryExpression
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
97
XPath/impl/xpath_parser.hpp
Normal file
97
XPath/impl/xpath_parser.hpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_PARSER_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_PARSER_HPP
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/tree/ast.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "xpath_object.hpp"
|
||||
#include "xpath_ast.hpp"
|
||||
#include "xpath_grammar.hpp"
|
||||
#include "xpath_namespace_context.hpp"
|
||||
#include "xpath_function_resolver.hpp"
|
||||
#include "xpath_resolver_holder.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class SyntaxException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
SyntaxException(const std::string& thing) : std::runtime_error("Bad XPath: " + thing) { }
|
||||
}; // class SyntaxException
|
||||
|
||||
class RuntimeException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
RuntimeException(const std::string& thing) : std::runtime_error("Cannot evaluate XPath: " + thing) { }
|
||||
}; // class RuntimeException
|
||||
|
||||
class UnsupportedException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
UnsupportedException(const std::string& thing) : std::runtime_error("Sorry, haven't implemented '" + thing + "' yet") { }
|
||||
}; // class UnsupportedException
|
||||
|
||||
class CompilationContext;
|
||||
|
||||
class XPath
|
||||
{
|
||||
public:
|
||||
XPath();
|
||||
~XPath();
|
||||
|
||||
XPathExpressionPtr compile(const std::string& xpath) const;
|
||||
XPathExpressionPtr compile_expr(const std::string& xpath) const;
|
||||
|
||||
XPathValuePtr evaluate(const std::string& xpath, const DOM::Node<std::string>& context) const;
|
||||
XPathValuePtr evaluate_expr(const std::string& xpath, const DOM::Node<std::string>& context) const;
|
||||
|
||||
void setNamespaceContext(const NamespaceContext& namespaceContext) { namespaceContext_.set(namespaceContext); }
|
||||
void setNamespaceContext(NamespaceContextPtr namespaceContext) { namespaceContext_.set(namespaceContext); }
|
||||
const NamespaceContext& getNamespaceContext() const { return namespaceContext_.get(); }
|
||||
void resetNamespaceContext() { namespaceContext_.set(NamespaceContextPtr(new NullNamespaceContext())); }
|
||||
|
||||
void setVariableResolver(const VariableResolver& variableResolver) { variableResolver_.set(variableResolver); }
|
||||
void setVariableResolver(VariableResolverPtr variableResolver) { variableResolver_.set(variableResolver); }
|
||||
const VariableResolver& getVariableResolver() const { return variableResolver_.get(); }
|
||||
void resetVariableResolver() { variableResolver_.set(VariableResolverPtr(new NullVariableResolver())); }
|
||||
|
||||
void setFunctionResolver(const FunctionResolver& functionResolver) { functionResolver_.set(functionResolver); }
|
||||
void setFunctionResolver(FunctionResolverPtr functionResolver) { functionResolver_.set(functionResolver); }
|
||||
const FunctionResolver& getFunctionResolver() const { return functionResolver_.get(); }
|
||||
void resetFunctionResolver() { functionResolver_.set(FunctionResolverPtr(new NullFunctionResolver())); }
|
||||
|
||||
private:
|
||||
XPathExpressionPtr do_compile(const std::string& xpath, tree_info_t(XPath::*fn)(const std::string& str) const) const;
|
||||
tree_info_t parse_xpath(const std::string& str) const;
|
||||
tree_info_t parse_xpath_expr(const std::string& str) const;
|
||||
|
||||
xpath_grammar xpathg_;
|
||||
|
||||
ResolverHolder<const NamespaceContext> namespaceContext_;
|
||||
ResolverHolder<const VariableResolver> variableResolver_;
|
||||
ResolverHolder<const FunctionResolver> functionResolver_;
|
||||
|
||||
typedef XPathExpression* (*compileFn)(node_iter_t const& i, CompilationContext& context);
|
||||
static std::map<int, compileFn> factory_;
|
||||
static std::map<int, std::string> names_;
|
||||
static const std::map<int, compileFn> createFunctions();
|
||||
static const std::map<int, std::string> debugNames();
|
||||
static void dump(node_iter_t const& i, int depth);
|
||||
|
||||
friend XPathExpression* Arabica::XPath::compile_expression(node_iter_t const& i, CompilationContext& context);
|
||||
|
||||
|
||||
XPath(const XPath&);
|
||||
XPath& operator=(const XPath&);
|
||||
bool operator==(const XPath&) const;
|
||||
}; // class XPath
|
||||
|
||||
} // namespace XPath
|
||||
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
97
XPath/impl/xpath_relational.hpp
Normal file
97
XPath/impl/xpath_relational.hpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_RELATIONAL_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_RELATIONAL_HPP
|
||||
|
||||
#include "xpath_value.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class EqualsOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
EqualsOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return BoolValue::createValue(areEqual(lhs()->evaluate(context, executionContext),
|
||||
rhs()->evaluate(context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class EqualsOperator
|
||||
|
||||
class NotEqualsOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
NotEqualsOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return BoolValue::createValue(!areEqual(lhs()->evaluate(context, executionContext),
|
||||
rhs()->evaluate(context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class NotEqualsOperator
|
||||
|
||||
class LessThanOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
LessThanOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return BoolValue::createValue(isLessThan(lhs()->evaluate(context, executionContext),
|
||||
rhs()->evaluate(context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class LessThanOperator
|
||||
|
||||
class LessThanEqualsOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
LessThanEqualsOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return BoolValue::createValue(isLessThanEquals(lhs()->evaluate(context, executionContext),
|
||||
rhs()->evaluate(context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class LessThanEqualsOperator
|
||||
|
||||
class GreaterThanOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
GreaterThanOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return BoolValue::createValue(isGreaterThan(lhs()->evaluate(context, executionContext),
|
||||
rhs()->evaluate(context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class GreaterThanOperator
|
||||
|
||||
class GreaterThanEqualsOperator : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
GreaterThanEqualsOperator(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return BoolValue::createValue(isGreaterThanEquals(lhs()->evaluate(context, executionContext),
|
||||
rhs()->evaluate(context, executionContext)));
|
||||
} // evaluate
|
||||
}; // class GreaterThanEqualsOperator
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
#endif
|
69
XPath/impl/xpath_resolver_holder.hpp
Normal file
69
XPath/impl/xpath_resolver_holder.hpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef ARABICA_XPATH_RESOLVER_HOLDER_HPP
|
||||
#define ARABICA_XPATH_RESOLVER_HOLDER_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
template<typename ResolverT>
|
||||
class ResolverHolder
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<ResolverT> ResolverPtrT;
|
||||
|
||||
ResolverHolder() :
|
||||
unowned_(0),
|
||||
shared_()
|
||||
{
|
||||
} // ResolverHolder
|
||||
|
||||
ResolverHolder(const ResolverHolder& rhs) :
|
||||
unowned_(rhs.unowned_),
|
||||
shared_(rhs.shared_)
|
||||
{
|
||||
} // ResolverHolder
|
||||
|
||||
ResolverHolder& operator=(const ResolverHolder& rhs)
|
||||
{
|
||||
if(rhs == *this)
|
||||
return *this;
|
||||
|
||||
unowned_ = rhs_.unowned_;
|
||||
shared_ = rhs_.shared_;
|
||||
|
||||
return *this;
|
||||
} // operator=
|
||||
|
||||
ResolverT& get() const
|
||||
{
|
||||
if(unowned_)
|
||||
return *unowned_;
|
||||
return *(shared_.get());
|
||||
} // get()
|
||||
|
||||
void set(ResolverT& resolver)
|
||||
{
|
||||
unowned_ = &resolver;
|
||||
shared_.reset();
|
||||
} // set
|
||||
|
||||
void set(ResolverPtrT resolver)
|
||||
{
|
||||
unowned_ = 0;
|
||||
shared_ = resolver;
|
||||
} // set
|
||||
|
||||
private:
|
||||
ResolverT* unowned_;
|
||||
ResolverPtrT shared_;
|
||||
|
||||
bool operator==(const ResolverHolder&);
|
||||
}; // ResolverHolder
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
416
XPath/impl/xpath_step.hpp
Normal file
416
XPath/impl/xpath_step.hpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_STEP_H
|
||||
#define ARABICA_XPATHIC_XPATH_STEP_H
|
||||
|
||||
#include <DOM/Document.h>
|
||||
#include <algorithm>
|
||||
#include "xpath_object.hpp"
|
||||
#include "xpath_value.hpp"
|
||||
#include "xpath_axis_enumerator.hpp"
|
||||
#include "xpath_node_test.hpp"
|
||||
#include "xpath_ast.hpp"
|
||||
#include "xpath_ast_ids.hpp"
|
||||
#include "xpath_namespace_context.hpp"
|
||||
#include "xpath_compile_context.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class StepExpression : public XPathExpression
|
||||
{
|
||||
public:
|
||||
StepExpression() { }
|
||||
StepExpression(std::vector<XPathExpression*> predicates) : predicates_(predicates) { }
|
||||
|
||||
virtual ~StepExpression()
|
||||
{
|
||||
for(std::vector<XPathExpression*>::iterator p = predicates_.begin(), e = predicates_.end(); p != e; ++p)
|
||||
delete *p;
|
||||
} // ~StepExpression
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const = 0;
|
||||
virtual XPathValuePtr evaluate(NodeSet& context, const ExecutionContext& executionContext) const = 0;
|
||||
|
||||
bool has_predicates() const { return !predicates_.empty(); }
|
||||
|
||||
protected:
|
||||
NodeSet applyPredicates(NodeSet& nodes, const ExecutionContext& parentContext) const
|
||||
{
|
||||
for(std::vector<XPathExpression*>::const_iterator p = predicates_.begin(), e = predicates_.end();
|
||||
(p != e) && (!nodes.empty()); ++p)
|
||||
nodes = applyPredicate(nodes, *p, parentContext);
|
||||
return nodes;
|
||||
} // applyPredicates
|
||||
|
||||
private:
|
||||
NodeSet applyPredicate(NodeSet& nodes, XPathExpression* predicate, const ExecutionContext& parentContext) const
|
||||
{
|
||||
ExecutionContext executionContext(nodes.size(), parentContext);
|
||||
NodeSet results(nodes.forward());
|
||||
unsigned int position = 1;
|
||||
for(NodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i, ++position)
|
||||
{
|
||||
executionContext.setPosition(position);
|
||||
XPathValuePtr v = predicate->evaluate(*i, executionContext);
|
||||
|
||||
if((v->type() == NUMBER) && (position != v->asNumber()))
|
||||
continue;
|
||||
if(v->asBool() == false)
|
||||
continue;
|
||||
|
||||
results.push_back(*i);
|
||||
} // for ...
|
||||
return results;
|
||||
} // applyPredicate
|
||||
|
||||
std::vector<XPathExpression*> predicates_;
|
||||
}; // StepExpression
|
||||
|
||||
class TestStepExpression : public StepExpression
|
||||
{
|
||||
public:
|
||||
TestStepExpression(Axis axis, NodeTest* test) :
|
||||
StepExpression(),
|
||||
axis_(axis),
|
||||
test_(test)
|
||||
{
|
||||
} // TestStepExpression
|
||||
|
||||
TestStepExpression(Axis axis, NodeTest* test, std::vector<XPathExpression*> predicates) :
|
||||
StepExpression(predicates),
|
||||
axis_(axis),
|
||||
test_(test)
|
||||
{
|
||||
} // TestStepExpression
|
||||
|
||||
virtual ~TestStepExpression()
|
||||
{
|
||||
delete test_;
|
||||
} // StepExpression
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
NodeSet nodes;
|
||||
enumerateOver(context, nodes, executionContext);
|
||||
return XPathValuePtr(new NodeSetValue(nodes));
|
||||
} // evaluate
|
||||
|
||||
virtual XPathValuePtr evaluate(NodeSet& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
NodeSet nodes;
|
||||
for(NodeSet::iterator n = context.begin(); n != context.end(); ++n)
|
||||
enumerateOver(*n, nodes, executionContext);
|
||||
return XPathValuePtr(new NodeSetValue(nodes));
|
||||
} // evaluate
|
||||
|
||||
private:
|
||||
void enumerateOver(const DOM::Node<std::string>& context, NodeSet& results,
|
||||
const ExecutionContext& parentContext) const
|
||||
{
|
||||
AxisEnumerator enumerator(context, axis_);
|
||||
NodeSet intermediate(enumerator.forward());
|
||||
NodeSet& d = (!has_predicates()) ? results : intermediate;
|
||||
while(*enumerator != 0)
|
||||
{
|
||||
// if test
|
||||
DOM::Node<std::string> node = *enumerator;
|
||||
if((*test_)(node))
|
||||
d.push_back(node);
|
||||
++enumerator;
|
||||
} // while ...
|
||||
|
||||
if(!has_predicates())
|
||||
{
|
||||
results.forward(enumerator.forward());
|
||||
return;
|
||||
} // if ...
|
||||
|
||||
intermediate = applyPredicates(intermediate, parentContext);
|
||||
|
||||
results.swap(intermediate);
|
||||
} // enumerateOver
|
||||
|
||||
Axis axis_;
|
||||
NodeTest* test_;
|
||||
}; // class TestStepExpression
|
||||
|
||||
class ExprStepExpression : public StepExpression
|
||||
{
|
||||
public:
|
||||
ExprStepExpression(XPathExpression* expr, std::vector<XPathExpression*> predicates) :
|
||||
StepExpression(predicates),
|
||||
expr_(expr)
|
||||
{
|
||||
} // ExprStepExpression
|
||||
|
||||
virtual ~ExprStepExpression()
|
||||
{
|
||||
delete expr_;
|
||||
} // ExprStepExpression
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
if(!has_predicates())
|
||||
return expr_->evaluate(context, executionContext);
|
||||
|
||||
NodeSet ns = expr_->evaluate(context, executionContext)->asNodeSet();
|
||||
return XPathValuePtr(new NodeSetValue(applyPredicates(ns, executionContext)));
|
||||
} // evaluate
|
||||
|
||||
virtual XPathValuePtr evaluate(NodeSet& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
DOM::Node<std::string> c = context.top();
|
||||
return evaluate(c, executionContext);
|
||||
} // evaluate
|
||||
|
||||
private:
|
||||
XPathExpression* expr_;
|
||||
std::vector<XPathExpression*> predicates_;
|
||||
}; // class ExprStepExpression
|
||||
|
||||
class StepFactory
|
||||
{
|
||||
public:
|
||||
static StepExpression* createStep(node_iter_t& node, node_iter_t const& end, CompilationContext& context)
|
||||
{
|
||||
Axis axis = getAxis(node);
|
||||
NodeTest* test = getTest(node, context.namespaceContext());
|
||||
XPathExpression* thing = 0;
|
||||
if(!test)
|
||||
thing = compile_expression(node++, context);
|
||||
|
||||
std::vector<XPathExpression*> preds;
|
||||
|
||||
while((node != end) && (getNodeId(node) == Predicate_id))
|
||||
{
|
||||
node_iter_t c = node->children.begin();
|
||||
assert(getNodeId(c) == LeftSquare_id);
|
||||
++c;
|
||||
preds.push_back(compile_expression(c, context));
|
||||
++c;
|
||||
assert(getNodeId(c) == RightSquare_id);
|
||||
|
||||
++node;
|
||||
} // if ...
|
||||
if(!test)
|
||||
return new ExprStepExpression(thing, preds);
|
||||
return new TestStepExpression(axis, test, preds);
|
||||
} // createStep
|
||||
|
||||
static StepExpression* createStep(node_iter_t& node, CompilationContext& context)
|
||||
{
|
||||
Axis axis = getAxis(node);
|
||||
NodeTest* test = getTest(node, context.namespaceContext());
|
||||
return new TestStepExpression(axis, test);
|
||||
} // createStep
|
||||
|
||||
private:
|
||||
static Axis getAxis(node_iter_t& node)
|
||||
{
|
||||
long id = getNodeId(node);
|
||||
|
||||
switch(id)
|
||||
{
|
||||
case Slash_id:
|
||||
case SelfSelect_id:
|
||||
return SELF; // don't advance node, SelfSelect is axis specifier and node test in one
|
||||
case ParentSelect_id:
|
||||
return PARENT;
|
||||
case SlashSlash_id:
|
||||
return DESCENDANT_OR_SELF;
|
||||
|
||||
case AbbreviatedAxisSpecifier_id:
|
||||
++node;
|
||||
return ATTRIBUTE;
|
||||
|
||||
case AxisSpecifier_id:
|
||||
// skip on to the next bit
|
||||
break;
|
||||
|
||||
default:
|
||||
return CHILD;
|
||||
} // switch(id)
|
||||
|
||||
node_iter_t axis_node = node->children.begin();
|
||||
long axis = getNodeId(skipWhitespace(axis_node));
|
||||
++node;
|
||||
switch(axis)
|
||||
{
|
||||
case AncestorOrSelf_id:
|
||||
return ANCESTOR_OR_SELF;
|
||||
case Ancestor_id:
|
||||
return ANCESTOR;
|
||||
case AbbreviatedAxisSpecifier_id:
|
||||
case Attribute_id:
|
||||
return ATTRIBUTE;
|
||||
case Child_id:
|
||||
return CHILD;
|
||||
case DescendantOrSelf_id:
|
||||
return DESCENDANT_OR_SELF;
|
||||
case Descendant_id:
|
||||
return DESCENDANT;
|
||||
case FollowingSibling_id:
|
||||
return FOLLOWING_SIBLING;
|
||||
case Following_id:
|
||||
return FOLLOWING;
|
||||
case Namespace_id:
|
||||
return NAMESPACE;
|
||||
case Parent_id:
|
||||
return PARENT;
|
||||
case PrecedingSibling_id:
|
||||
return PRECEDING_SIBLING;
|
||||
case Preceding_id:
|
||||
return PRECEDING;
|
||||
case Self_id:
|
||||
return SELF;
|
||||
} // switch ...
|
||||
|
||||
assert(false);
|
||||
return CHILD;
|
||||
} // getAxis
|
||||
|
||||
static NodeTest* getTest(node_iter_t& node, const NamespaceContext& namespaceContext)
|
||||
{
|
||||
long id = getNodeId(skipWhitespace(node));
|
||||
|
||||
switch(id)
|
||||
{
|
||||
case NodeTest_id:
|
||||
{
|
||||
node_iter_t c = node->children.begin();
|
||||
NodeTest* t = getTest(c, namespaceContext);
|
||||
++node;
|
||||
return t;
|
||||
} // case NodeTest_id
|
||||
|
||||
case QName_id:
|
||||
{
|
||||
node_iter_t c = node->children.begin();
|
||||
std::string prefix(c->value.begin(), c->value.end());
|
||||
std::string uri = namespaceContext.namespaceURI(prefix);
|
||||
++c;
|
||||
std::string name(c->value.begin(), c->value.end());
|
||||
++node;
|
||||
return new QNameNodeTest(uri, name);
|
||||
} //case QName_id
|
||||
|
||||
case NCName_id:
|
||||
{
|
||||
std::string name(node->value.begin(), node->value.end());
|
||||
++node;
|
||||
return new NameNodeTest(name);
|
||||
} // case NameNodeTest
|
||||
|
||||
case Comment_id:
|
||||
{
|
||||
++node;
|
||||
return new CommentNodeTest();
|
||||
} // case CommentTest_id
|
||||
|
||||
case Text_id:
|
||||
{
|
||||
++node;
|
||||
return new TextNodeTest();
|
||||
} // case Text_id
|
||||
|
||||
case ProcessingInstruction_id:
|
||||
{
|
||||
++node;
|
||||
if(getNodeId(node) != Literal_id) // not sure if this is always safe
|
||||
return new ProcessingInstructionNodeTest();
|
||||
|
||||
std::string target(node->value.begin(), node->value.end());
|
||||
++node;
|
||||
return new ProcessingInstructionNodeTest(target);
|
||||
} // case ProcessingInstruction_id
|
||||
|
||||
case SlashSlash_id:
|
||||
case Node_id:
|
||||
{
|
||||
++node;
|
||||
return new AnyNodeTest();
|
||||
} // case Node_id
|
||||
|
||||
case Slash_id:
|
||||
return new RootNodeTest();
|
||||
|
||||
case AnyName_id:
|
||||
case SelfSelect_id:
|
||||
case ParentSelect_id:
|
||||
{
|
||||
++node;
|
||||
return new StarNodeTest();
|
||||
} // case AnyName_id:
|
||||
|
||||
case NameTest_id:
|
||||
{
|
||||
node_iter_t prefixNode = node->children.begin();
|
||||
++node;
|
||||
std::string prefix(prefixNode->value.begin(), prefixNode->value.end());
|
||||
std::string uri = namespaceContext.namespaceURI(prefix);
|
||||
return new QStarNodeTest(uri);
|
||||
} // case
|
||||
} // switch(id)
|
||||
|
||||
return 0;
|
||||
} // getTest
|
||||
|
||||
StepFactory();
|
||||
}; // class StepFactory
|
||||
|
||||
class RelativeLocationPath : public XPathExpression
|
||||
{
|
||||
public:
|
||||
typedef std::vector<StepExpression*> StepList;
|
||||
|
||||
public:
|
||||
RelativeLocationPath(StepExpression* step) : steps_() { steps_.push_back(step); }
|
||||
RelativeLocationPath(const StepList& steps) : steps_(steps) { }
|
||||
|
||||
virtual ~RelativeLocationPath()
|
||||
{
|
||||
for(StepList::const_iterator i = steps_.begin(); i != steps_.end(); ++i)
|
||||
delete *i;
|
||||
} // ~LocationPath
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
NodeSet nodes;
|
||||
nodes.push_back(context);
|
||||
|
||||
for(StepList::const_iterator i = steps_.begin(); i != steps_.end(); ++i)
|
||||
{
|
||||
XPathValuePtr v = (*i)->evaluate(nodes, executionContext);
|
||||
nodes = v->asNodeSet();
|
||||
} // for ...
|
||||
|
||||
return XPathValuePtr(new NodeSetValue(nodes));
|
||||
} // do_evaluate
|
||||
|
||||
private:
|
||||
StepList steps_;
|
||||
}; // LocationPath
|
||||
|
||||
class AbsoluteLocationPath : public RelativeLocationPath
|
||||
{
|
||||
public:
|
||||
AbsoluteLocationPath(StepExpression* step) : RelativeLocationPath(step) { }
|
||||
AbsoluteLocationPath(const RelativeLocationPath::StepList& steps) : RelativeLocationPath(steps) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
int type = context.getNodeType();
|
||||
if((type == DOM::Node<std::string>::DOCUMENT_NODE) ||
|
||||
(type == DOM::Node<std::string>::DOCUMENT_FRAGMENT_NODE))
|
||||
return RelativeLocationPath::evaluate(context, executionContext);
|
||||
|
||||
DOM::Document<std::string> document = context.getOwnerDocument();
|
||||
return RelativeLocationPath::evaluate(document, executionContext);
|
||||
} // evaluate
|
||||
}; // class AbsoluteLocationPath
|
||||
|
||||
|
||||
} // XPath
|
||||
} // Arabica
|
||||
#endif
|
75
XPath/impl/xpath_union.hpp
Normal file
75
XPath/impl/xpath_union.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_UNION_HPP
|
||||
#define ARABICA_XPATHIC_XPATH_UNION_HPP
|
||||
|
||||
#include "xpath_value.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class UnionExpression : private BinaryExpression, public XPathExpression
|
||||
{
|
||||
public:
|
||||
UnionExpression(XPathExpression* lhs, XPathExpression* rhs) :
|
||||
BinaryExpression(lhs, rhs) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
XPathValuePtr p1 = lhs()->evaluate(context, executionContext);
|
||||
if(p1->type() != NODE_SET)
|
||||
throw RuntimeException("Union operator joins node-sets. First argument is not a node-set.");
|
||||
XPathValuePtr p2 = rhs()->evaluate(context, executionContext);
|
||||
if(p2->type() != NODE_SET)
|
||||
throw RuntimeException("Union operator joins node-sets. First argument is not a node-set.");
|
||||
|
||||
NodeSet ns1(p1->asNodeSet());
|
||||
NodeSet ns2(p2->asNodeSet());
|
||||
|
||||
// do the obvious optimizations
|
||||
if(ns1.empty())
|
||||
return wrap(ns2);
|
||||
if(ns2.empty())
|
||||
return wrap(ns1);
|
||||
|
||||
ns1.to_document_order();
|
||||
ns2.to_document_order();
|
||||
NodeSet::const_iterator n1 = ns1.begin(), n1e = ns1.end();
|
||||
NodeSet::const_iterator n2 = ns2.begin(), n2e = ns2.end();
|
||||
|
||||
NodeSet result(true);
|
||||
|
||||
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:
|
||||
XPathValuePtr wrap(const NodeSet& ns) const
|
||||
{
|
||||
return XPathValuePtr(new NodeSetValue(ns));
|
||||
} // wrap
|
||||
}; // UnionExpression
|
||||
|
||||
} // namespace XPath
|
||||
|
||||
} // namespace Arabica
|
||||
#endif
|
148
XPath/impl/xpath_value.hpp
Normal file
148
XPath/impl/xpath_value.hpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
#ifndef ARABICA_XPATHIC_XPATH_VALUE_H
|
||||
#define ARABICA_XPATHIC_XPATH_VALUE_H
|
||||
|
||||
#include <string>
|
||||
#include <DOM/Node.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <vector>
|
||||
#include "xpath_object.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class BoolValue : public XPathValue, public XPathExpression
|
||||
{
|
||||
public:
|
||||
BoolValue(bool value) :
|
||||
value_(value) { }
|
||||
|
||||
static XPathValuePtr createValue(bool value) { return XPathValuePtr(new BoolValue(value)); }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
return XPathValuePtr(new BoolValue(value_));
|
||||
} // evaluate
|
||||
virtual bool evaluateAsBool(const DOM::Node<std::string>& context) { return asBool(); }
|
||||
virtual double evaluateAsNumber(const DOM::Node<std::string>& context) { return asNumber(); }
|
||||
virtual std::string evaluateAsString(const DOM::Node<std::string>& context) { return asString(); }
|
||||
virtual NodeSet evaluateAsNodeSet(const DOM::Node<std::string>& context) { return asNodeSet(); }
|
||||
|
||||
virtual bool asBool() const { return value_; }
|
||||
virtual double asNumber() const { return value_ ? 1 : 0; }
|
||||
virtual std::string asString() const { return value_ ? "true" : "false"; }
|
||||
virtual const NodeSet& asNodeSet() const { static NodeSet empty; return empty; }
|
||||
|
||||
virtual ValueType type() const { return BOOL; }
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
}; // class BoolValue
|
||||
|
||||
class NumericValue : public XPathValue, public XPathExpression
|
||||
{
|
||||
public:
|
||||
NumericValue(double value) :
|
||||
value_(value) { }
|
||||
|
||||
static XPathValuePtr createValue(double value) { return XPathValuePtr(new NumericValue(value)); }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
return createValue(value_);
|
||||
} // evaluate
|
||||
virtual bool evaluateAsBool(const DOM::Node<std::string>& context) { return asBool(); }
|
||||
virtual double evaluateAsNumber(const DOM::Node<std::string>& context) { return asNumber(); }
|
||||
virtual std::string evaluateAsString(const DOM::Node<std::string>& context) { return asString(); }
|
||||
virtual NodeSet evaluateAsNodeSet(const DOM::Node<std::string>& context) { return asNodeSet(); }
|
||||
|
||||
virtual bool asBool() const { return (value_ != 0.0); }
|
||||
virtual double asNumber() const { return value_; }
|
||||
virtual std::string asString() const
|
||||
{
|
||||
if(isNaN(value_))
|
||||
return "NaN";
|
||||
if(isInfinity(value_))
|
||||
return "Infinity";
|
||||
if(isNegativeInfinity(value_))
|
||||
return "-Infinity";
|
||||
return boost::lexical_cast<std::string>(value_);
|
||||
} // asString
|
||||
virtual const NodeSet& asNodeSet() const { static NodeSet empty; return empty; }
|
||||
|
||||
virtual ValueType type() const { return NUMBER; }
|
||||
|
||||
private:
|
||||
double value_;
|
||||
}; // class NumberValue
|
||||
|
||||
class StringValue : public XPathValue, public XPathExpression
|
||||
{
|
||||
public:
|
||||
StringValue(const char* value) :
|
||||
value_(value) { }
|
||||
StringValue(const std::string& value) :
|
||||
value_(value) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
return XPathValuePtr(new StringValue(value_));
|
||||
} // evaluate
|
||||
virtual bool evaluateAsBool(const DOM::Node<std::string>& context) { return asBool(); }
|
||||
virtual double evaluateAsNumber(const DOM::Node<std::string>& context) { return asNumber(); }
|
||||
virtual std::string evaluateAsString(const DOM::Node<std::string>& context) { return asString(); }
|
||||
virtual NodeSet evaluateAsNodeSet() const { return asNodeSet(); }
|
||||
|
||||
virtual bool asBool() const { return !value_.empty(); }
|
||||
virtual double asNumber() const
|
||||
{
|
||||
return stringAsNumber(value_);
|
||||
} // asNumber
|
||||
virtual std::string asString() const { return value_; }
|
||||
virtual const NodeSet& asNodeSet() const { static NodeSet empty; return empty; }
|
||||
|
||||
virtual ValueType type() const { return STRING; }
|
||||
|
||||
private:
|
||||
std::string value_;
|
||||
}; // class StringValue
|
||||
|
||||
class NodeSetValue : public XPathValue, public XPathExpression
|
||||
{
|
||||
public:
|
||||
NodeSetValue(const NodeSet& set) : set_(set) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context, const ExecutionContext& executionContext) const
|
||||
{
|
||||
return XPathValuePtr(this);
|
||||
} // evaluate
|
||||
virtual bool evaluateAsBool(const DOM::Node<std::string>& context) const{ return asBool(); }
|
||||
virtual double evaluateAsNumber(const DOM::Node<std::string>& context) const { return asNumber(); }
|
||||
virtual std::string evaluateAsString(const DOM::Node<std::string>& context) const { return asString(); }
|
||||
virtual const NodeSet& evaluateAsNodeSet() const { return asNodeSet(); }
|
||||
|
||||
virtual bool asBool() const
|
||||
{
|
||||
return !set_.empty();
|
||||
} // asBool
|
||||
virtual double asNumber() const
|
||||
{
|
||||
return stringAsNumber(asString());
|
||||
} // asNumber
|
||||
virtual std::string asString() const
|
||||
{
|
||||
return !set_.empty() ? nodeStringValue(set_.top()) : "";
|
||||
} // asStringx
|
||||
virtual const NodeSet& asNodeSet() const { return set_; }
|
||||
|
||||
virtual ValueType type() const { return NODE_SET; }
|
||||
|
||||
private:
|
||||
NodeSet set_;
|
||||
}; // NodeSetValue
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
31
XPath/impl/xpath_variable.hpp
Normal file
31
XPath/impl/xpath_variable.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef ARABICA_XPATH_VARIABLE_HPP
|
||||
#define ARABICA_XPATH_VARIABLE_HPP
|
||||
|
||||
#include "xpath_value.hpp"
|
||||
#include "xpath_execution_context.hpp"
|
||||
#include "xpath_variable_resolver.hpp"
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class Variable : public XPathExpression
|
||||
{
|
||||
public:
|
||||
Variable(const std::string& name) : name_(name) { }
|
||||
|
||||
virtual XPathValuePtr evaluate(const DOM::Node<std::string>& context,
|
||||
const ExecutionContext& executionContext) const
|
||||
{
|
||||
return executionContext.variableResolver().resolveVariable(name_);
|
||||
} // evaluate
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
}; // class Variable
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
42
XPath/impl/xpath_variable_resolver.hpp
Normal file
42
XPath/impl/xpath_variable_resolver.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef ARABICA_XPATH_VARIABLE_RESOLVER_HPP
|
||||
#define ARABICA_XPATH_VARIABLE_RESOLVER_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace Arabica
|
||||
{
|
||||
namespace XPath
|
||||
{
|
||||
|
||||
class XPathValue;
|
||||
typedef boost::shared_ptr<const XPathValue> XPathValuePtr;
|
||||
|
||||
class UnboundVariableException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
UnboundVariableException(const std::string& thing) : std::runtime_error("The variable '" + thing + "' is undefined.") { }
|
||||
}; // class UnboundVariableException
|
||||
|
||||
class VariableResolver
|
||||
{
|
||||
public:
|
||||
virtual ~VariableResolver() { }
|
||||
|
||||
virtual XPathValuePtr resolveVariable(const std::string& name) const = 0;
|
||||
}; // class VariableResolver
|
||||
|
||||
typedef boost::shared_ptr<VariableResolver> VariableResolverPtr;
|
||||
|
||||
class NullVariableResolver : public VariableResolver
|
||||
{
|
||||
public:
|
||||
virtual XPathValuePtr resolveVariable(const std::string& name) const
|
||||
{
|
||||
throw UnboundVariableException(name);
|
||||
} // resolveVariable
|
||||
}; // NullVariableResolver
|
||||
|
||||
} // namespace XPath
|
||||
} // namespace Arabica
|
||||
|
||||
#endif
|
20
XPath/src/xpath_axis_enumerator.cpp
Normal file
20
XPath/src/xpath_axis_enumerator.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <XPath/impl/xpath_axis_enumerator.hpp>
|
||||
|
||||
using namespace Arabica::XPath;
|
||||
|
||||
const AxisEnumerator::NamedAxis AxisEnumerator::AxisLookupTable[] = {
|
||||
{ ANCESTOR, AxisEnumerator::CreateAxis<AxisEnumerator::AncestorAxisWalker> },
|
||||
{ ANCESTOR_OR_SELF, AxisEnumerator::CreateAxis<AxisEnumerator::AncestorOrSelfAxisWalker> },
|
||||
{ ATTRIBUTE, AxisEnumerator::CreateAxis<AxisEnumerator::AttributeAxisWalker> },
|
||||
{ CHILD, AxisEnumerator::CreateAxis<AxisEnumerator::ChildAxisWalker> },
|
||||
{ DESCENDANT, AxisEnumerator::CreateAxis<AxisEnumerator::DescendantAxisWalker> },
|
||||
{ DESCENDANT_OR_SELF, AxisEnumerator::CreateAxis<AxisEnumerator::DescendantOrSelfAxisWalker> },
|
||||
{ FOLLOWING, AxisEnumerator::CreateAxis<AxisEnumerator::FollowingAxisWalker> },
|
||||
{ FOLLOWING_SIBLING, AxisEnumerator::CreateAxis<AxisEnumerator::FollowingSiblingAxisWalker> },
|
||||
{ NAMESPACE, AxisEnumerator::CreateAxis<AxisEnumerator::NamespaceAxisWalker> },
|
||||
{ PARENT, AxisEnumerator::CreateAxis<AxisEnumerator::ParentAxisWalker> },
|
||||
{ PRECEDING, AxisEnumerator::CreateAxis<AxisEnumerator::PrecedingAxisWalker> },
|
||||
{ PRECEDING_SIBLING, AxisEnumerator::CreateAxis<AxisEnumerator::PrecedingSiblingAxisWalker> },
|
||||
{ SELF, AxisEnumerator::CreateAxis<AxisEnumerator::SelfAxisWalker> },
|
||||
{ static_cast<Axis>(0), 0 }
|
||||
};
|
369
XPath/src/xpath_object.cpp
Normal file
369
XPath/src/xpath_object.cpp
Normal file
|
@ -0,0 +1,369 @@
|
|||
#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
|
||||
{
|
||||
|
||||
bool nodeSetsEqual(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
bool nodeSetAndValueEqual(const XPathValuePtr& lhs, const XPathValuePtr& rhs);
|
||||
|
||||
double minValue(const NodeSet& ns);
|
||||
double maxValue(const NodeSet& ns);
|
||||
|
||||
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& lhs, const XPathValuePtr& rhs)
|
||||
{
|
||||
return Op()(minValue(lhs->asNodeSet()), maxValue(rhs->asNodeSet()));
|
||||
} // compareNodeSets
|
||||
|
||||
template<class Op>
|
||||
bool compareNodeSetWith(const XPathValuePtr& lhs, const XPathValuePtr& rhs)
|
||||
{
|
||||
const NodeSet& lns = lhs->asNodeSet();
|
||||
return std::find_if(lns.begin(),
|
||||
lns.end(),
|
||||
compareNodeWith<Op>(rhs->asNumber())) != lns.end();
|
||||
} // compareNodeSetAndValue
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
bool areEqual(const XPathValuePtr& lhs, const XPathValuePtr& 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 nodeSetsEqual(const XPathValuePtr& lhs, const XPathValuePtr& rhs)
|
||||
{
|
||||
const NodeSet& lns = lhs->asNodeSet();
|
||||
const NodeSet& rns = rhs->asNodeSet();
|
||||
|
||||
if((lns.size() == 0) || (rns.size() == 0))
|
||||
return false;
|
||||
|
||||
std::set<std::string> values;
|
||||
NodeSet::const_iterator l = lns.begin();
|
||||
std::string lvalue = nodeStringValue(*l);
|
||||
|
||||
for(NodeSet::const_iterator r = rns.begin(), rend = rns.end(); r != rend; ++r)
|
||||
{
|
||||
std::string rvalue = nodeStringValue(*r);
|
||||
if(lvalue == rvalue)
|
||||
return true;
|
||||
values.insert(rvalue);
|
||||
} // for ...
|
||||
|
||||
++l;
|
||||
for(NodeSet::const_iterator lend = lns.end(); l != lend; ++l)
|
||||
if(values.find(nodeStringValue(*l)) != values.end())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} // nodeSetsEqual
|
||||
|
||||
bool nodeSetAndValueEqual(const XPathValuePtr& lhs, const XPathValuePtr& rhs)
|
||||
{
|
||||
const NodeSet& 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<std::string> >(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
|
||||
|
||||
///////////////////////////////
|
||||
bool isLessThan(const XPathValuePtr& lhs, const XPathValuePtr& 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& lhs, const XPathValuePtr& 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& lhs, const XPathValuePtr& rhs)
|
||||
{
|
||||
return isLessThan(rhs, lhs);
|
||||
} // isGreaterThan
|
||||
|
||||
bool isGreaterThanEquals(const XPathValuePtr& lhs, const XPathValuePtr& rhs)
|
||||
{
|
||||
return isLessThanEquals(rhs, lhs);
|
||||
} // isGreaterThanEquals
|
||||
|
||||
double minValue(const NodeSet& ns)
|
||||
{
|
||||
double v = nodeNumberValue(ns[0]);
|
||||
for(NodeSet::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
|
||||
|
||||
double maxValue(const NodeSet& ns)
|
||||
{
|
||||
double v = nodeNumberValue(ns[0]);
|
||||
for(NodeSet::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
|
||||
|
||||
////////////////////////////////////
|
||||
double stringAsNumber(const std::string& str)
|
||||
{
|
||||
try {
|
||||
return boost::lexical_cast<double>(str);
|
||||
} // try
|
||||
catch(const boost::bad_lexical_cast&) {
|
||||
return NaN;
|
||||
} // catch
|
||||
} // stringAsNumber
|
||||
|
||||
double nodeNumberValue(const DOM::Node<std::string>& node)
|
||||
{
|
||||
return stringAsNumber(nodeStringValue(node));
|
||||
} // nodeNumberValue
|
||||
|
||||
std::string nodeStringValue(const DOM::Node<std::string>& node)
|
||||
{
|
||||
switch(node.getNodeType())
|
||||
{
|
||||
case DOM::Node<std::string>::DOCUMENT_NODE:
|
||||
case DOM::Node<std::string>::DOCUMENT_FRAGMENT_NODE:
|
||||
case DOM::Node<std::string>::ELEMENT_NODE:
|
||||
{
|
||||
std::ostringstream os;
|
||||
AxisEnumerator ae(node, DESCENDANT);
|
||||
while(*ae != 0)
|
||||
{
|
||||
if((ae->getNodeType() == DOM::Node<std::string>::TEXT_NODE) ||
|
||||
(ae->getNodeType() == DOM::Node<std::string>::CDATA_SECTION_NODE))
|
||||
os << ae->getNodeValue();
|
||||
++ae;
|
||||
} // while
|
||||
return os.str();
|
||||
} // case
|
||||
|
||||
case DOM::Node<std::string>::ATTRIBUTE_NODE:
|
||||
case DOM::Node<std::string>::PROCESSING_INSTRUCTION_NODE:
|
||||
case DOM::Node<std::string>::COMMENT_NODE:
|
||||
case DOM::Node<std::string>::TEXT_NODE:
|
||||
case DOM::Node<std::string>::CDATA_SECTION_NODE:
|
||||
return node.getNodeValue();
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Don't know how to calculate string-value of " + node.getNodeName());
|
||||
} // switch
|
||||
} // nodeStringValue
|
||||
|
||||
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
|
462
XPath/src/xpath_parser.cpp
Normal file
462
XPath/src/xpath_parser.cpp
Normal file
|
@ -0,0 +1,462 @@
|
|||
#pragma warning(disable:4224 4180 4244)
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <XPath/impl/xpath_parser.hpp>
|
||||
#include <XPath/impl/xpath_value.hpp>
|
||||
#include <XPath/impl/xpath_arithmetic.hpp>
|
||||
#include <XPath/impl/xpath_relational.hpp>
|
||||
#include <XPath/impl/xpath_logical.hpp>
|
||||
#include <XPath/impl/xpath_step.hpp>
|
||||
#include <XPath/impl/xpath_compile_context.hpp>
|
||||
#include <XPath/impl/xpath_variable.hpp>
|
||||
#include <XPath/impl/xpath_function_holder.hpp>
|
||||
#include <XPath/impl/xpath_union.hpp>
|
||||
|
||||
using namespace Arabica::XPath;
|
||||
|
||||
long Arabica::XPath::getNodeId(node_iter_t const& node)
|
||||
{
|
||||
return static_cast<long>(node->value.id().to_long());
|
||||
} // getNodeId
|
||||
|
||||
node_iter_t& Arabica::XPath::skipWhitespace(node_iter_t& node)
|
||||
{
|
||||
while(getNodeId(node) == S_id)
|
||||
++node;
|
||||
return node;
|
||||
} // skipWhitespace
|
||||
|
||||
XPath::XPath()
|
||||
{
|
||||
resetNamespaceContext();
|
||||
resetVariableResolver();
|
||||
resetFunctionResolver();
|
||||
} // XPath
|
||||
|
||||
XPath::~XPath()
|
||||
{
|
||||
} // ~XPath
|
||||
|
||||
std::map<int, std::string> XPath::names_ = debugNames();
|
||||
std::map<int, XPath::compileFn> XPath::factory_ = createFunctions();
|
||||
|
||||
void XPath::dump(node_iter_t const& i, int depth)
|
||||
{
|
||||
long id = static_cast<long>(i->value.id().to_long());
|
||||
|
||||
for(int d = 0; d < depth; ++d)
|
||||
std::cout << ' ';
|
||||
std::cout << names_[id] << " - " << std::string(i->value.begin(), i->value.end()) << std::endl;
|
||||
|
||||
for(node_iter_t c = i->children.begin(); c != i->children.end(); ++c)
|
||||
dump(c, depth+2);
|
||||
} // dump
|
||||
|
||||
XPathExpression* createExpression(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
node_iter_t c = i->children.begin();
|
||||
skipWhitespace(c);
|
||||
return compile_expression(c, context);
|
||||
} // createExpression
|
||||
|
||||
XPathExpression* createFunction(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
// dump(i);
|
||||
node_iter_t c = i->children.begin();
|
||||
std::string name(c->value.begin(), c->value.end());
|
||||
++c;
|
||||
skipWhitespace(c);
|
||||
assert(getNodeId(c) == LeftBracket_id);
|
||||
++c;
|
||||
skipWhitespace(c);
|
||||
|
||||
std::vector<XPathExpressionPtr> args;
|
||||
while(getNodeId(c) != RightBracket_id)
|
||||
{
|
||||
XPathExpressionPtr arg(compile_expression(c++, context));
|
||||
args.push_back(arg);
|
||||
|
||||
skipWhitespace(c);
|
||||
} // while ...
|
||||
// maybe trailing whitespace ...
|
||||
|
||||
return FunctionHolder::createFunction(name, args, context);
|
||||
} // createFunction
|
||||
|
||||
XPathExpression* createNumber(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
return new NumericValue(boost::lexical_cast<double>(std::string(i->value.begin(), i->value.end())));
|
||||
} // createNumber
|
||||
|
||||
XPathExpression* createVariable(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
return new Variable(std::string(i->value.begin()+1, i->value.end())); // skip $
|
||||
} // createVariable
|
||||
|
||||
XPathExpression* createLiteral(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
std::string str(i->value.begin(), i->value.end());
|
||||
return new StringValue(str);
|
||||
} // createLiteral
|
||||
|
||||
XPathExpression* createBinaryExpression(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
node_iter_t c = i->children.begin();
|
||||
XPathExpression* p1 = compile_expression(c, context);
|
||||
++c;
|
||||
|
||||
do
|
||||
{
|
||||
long op = getNodeId(c);
|
||||
++c;
|
||||
XPathExpression* p2 = compile_expression(c, context);
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case PlusOperator_id:
|
||||
p1 = new PlusOperator(p1, p2);
|
||||
break;
|
||||
case MinusOperator_id:
|
||||
p1 = new MinusOperator(p1, p2);
|
||||
break;
|
||||
case MultiplyOperator_id:
|
||||
p1 = new MultiplyOperator(p1, p2);
|
||||
break;
|
||||
case DivOperator_id:
|
||||
p1 = new DivideOperator(p1, p2);
|
||||
break;
|
||||
case ModOperator_id:
|
||||
p1 = new ModOperator(p1, p2);
|
||||
break;
|
||||
case EqualsOperator_id:
|
||||
p1 = new EqualsOperator(p1, p2);
|
||||
break;
|
||||
case NotEqualsOperator_id:
|
||||
p1 = new NotEqualsOperator(p1, p2);
|
||||
break;
|
||||
case LessThanOperator_id:
|
||||
p1 = new LessThanOperator(p1, p2);
|
||||
break;
|
||||
case LessThanEqualsOperator_id:
|
||||
p1 = new LessThanEqualsOperator(p1, p2);
|
||||
break;
|
||||
case GreaterThanOperator_id:
|
||||
p1 = new GreaterThanOperator(p1, p2);
|
||||
break;
|
||||
case GreaterThanEqualsOperator_id:
|
||||
p1 = new GreaterThanEqualsOperator(p1, p2);
|
||||
break;
|
||||
case OrOperator_id:
|
||||
p1 = new OrOperator(p1, p2);
|
||||
break;
|
||||
case AndOperator_id:
|
||||
p1 = new AndOperator(p1, p2);
|
||||
break;
|
||||
case UnionOperator_id:
|
||||
p1 = new UnionExpression(p1, p2);
|
||||
break;
|
||||
default:
|
||||
throw UnsupportedException(boost::lexical_cast<std::string>(op));
|
||||
} // switch
|
||||
}
|
||||
while(++c != i->children.end());
|
||||
|
||||
return p1;
|
||||
} // createBinaryExpression
|
||||
|
||||
RelativeLocationPath::StepList createStepList(node_iter_t const& from, node_iter_t const& to, CompilationContext& context)
|
||||
{
|
||||
RelativeLocationPath::StepList steps;
|
||||
|
||||
node_iter_t c = from;
|
||||
node_iter_t end = to;
|
||||
|
||||
while(c != end)
|
||||
switch(getNodeId(c))
|
||||
{
|
||||
case S_id:
|
||||
case Slash_id:
|
||||
++c; // just drop it
|
||||
break;
|
||||
case RelativeLocationPath_id:
|
||||
// might get here when handling an absolute path
|
||||
end = c->children.end();
|
||||
c = c->children.begin();
|
||||
break;
|
||||
case Step_id:
|
||||
{
|
||||
node_iter_t step = c->children.begin();
|
||||
steps.push_back(StepFactory::createStep(step, c->children.end(), context));
|
||||
++c;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
steps.push_back(StepFactory::createStep(c, end, context));
|
||||
} // switch(getNodeId(c))
|
||||
|
||||
return steps;
|
||||
} // createStepList
|
||||
|
||||
XPathExpression* createAbsoluteLocationPath(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
return new AbsoluteLocationPath(createStepList(i->children.begin(), i->children.end(), context));
|
||||
} // createAbsoluteLocationPath
|
||||
|
||||
XPathExpression* createRelativeLocationPath(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
return new RelativeLocationPath(createStepList(i->children.begin(), i->children.end(), context));
|
||||
} // createRelativeLocationPath
|
||||
|
||||
XPathExpression* createSingleStepRelativeLocationPath(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
node_iter_t n = i;
|
||||
return new RelativeLocationPath(StepFactory::createStep(n, context));
|
||||
} // createSingleStepRelativeLocationPath
|
||||
|
||||
XPathExpression* createSingleStepAbsoluteLocationPath(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
node_iter_t n = i;
|
||||
return new AbsoluteLocationPath(StepFactory::createStep(n, context));
|
||||
} // createSingleStepAbsoluteLocationPath
|
||||
|
||||
XPathExpression* createUnaryExpression(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
return compile_expression(i->children.begin(), context);
|
||||
} // createUnaryExpression
|
||||
|
||||
XPathExpression* createUnaryNegativeExpr(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
return new UnaryNegative(compile_expression(i+1, context));
|
||||
} // createUnaryNegativeExpr
|
||||
|
||||
XPathExpressionPtr XPath::compile(const std::string& xpath) const
|
||||
{
|
||||
return do_compile(xpath, &XPath::parse_xpath);
|
||||
} // compile
|
||||
|
||||
XPathExpressionPtr XPath::compile_expr(const std::string& xpath) const
|
||||
{
|
||||
return do_compile(xpath, &XPath::parse_xpath_expr);
|
||||
} // compile_expr
|
||||
|
||||
XPathExpressionPtr XPath::do_compile(const std::string& xpath, tree_info_t(XPath::*fn)(const std::string& str) const) const
|
||||
{
|
||||
debugNames();
|
||||
createFunctions();
|
||||
tree_info_t ast;
|
||||
try {
|
||||
ast = (this->*fn)(xpath);
|
||||
if(!ast.full)
|
||||
throw SyntaxException(xpath);
|
||||
|
||||
CompilationContext context(*this, getNamespaceContext(), getFunctionResolver());
|
||||
return XPathExpressionPtr(compile_expression(ast.trees.begin(), context));
|
||||
} // try
|
||||
catch(std::exception& ex)
|
||||
{
|
||||
//dump(ast.trees.begin());
|
||||
std::cerr << "\n\t'" << xpath << "' threw " << ex.what() << '\n' << std::endl;
|
||||
throw SyntaxException(xpath);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "\n\t'" << xpath << "' threw something\n" << std::endl;
|
||||
throw SyntaxException(xpath);
|
||||
}
|
||||
} // compile
|
||||
|
||||
tree_info_t XPath::parse_xpath(const std::string& str) const
|
||||
{
|
||||
str_iter_t first = str.begin();
|
||||
str_iter_t last = str.end();
|
||||
|
||||
return ast_parse(first, last, xpathg_);
|
||||
} // parse_xpath
|
||||
|
||||
tree_info_t XPath::parse_xpath_expr(const std::string& str) const
|
||||
{
|
||||
str_iter_t first = str.begin();
|
||||
str_iter_t last = str.end();
|
||||
|
||||
xpath_grammar_expr xpathg;
|
||||
return ast_parse(first, last, xpathg);
|
||||
} // parse_xpath_expr
|
||||
|
||||
XPathValuePtr XPath::evaluate(const std::string& xpath, const DOM::Node<std::string>& context) const
|
||||
{
|
||||
ExecutionContext executionContext;
|
||||
executionContext.setVariableResolver(getVariableResolver());
|
||||
|
||||
return compile(xpath)->evaluate(context, executionContext);
|
||||
} // evaluate
|
||||
|
||||
XPathValuePtr XPath::evaluate_expr(const std::string& xpath, const DOM::Node<std::string>& context) const
|
||||
{
|
||||
ExecutionContext executionContext;
|
||||
executionContext.setVariableResolver(getVariableResolver());
|
||||
|
||||
return compile_expr(xpath)->evaluate(context, executionContext);
|
||||
} // evaluate_expr
|
||||
|
||||
XPathExpression* Arabica::XPath::compile_expression(node_iter_t const& i, CompilationContext& context)
|
||||
{
|
||||
//dump(i);
|
||||
|
||||
long id = getNodeId(i);
|
||||
|
||||
if(XPath::factory_.find(id) == XPath::factory_.end())
|
||||
{
|
||||
//return XPathExpressionPtr();
|
||||
XPath::dump(i, 0);
|
||||
throw UnsupportedException(XPath::names_[id]);
|
||||
}
|
||||
|
||||
return XPath::factory_[id](i, context);
|
||||
} // compile_expression
|
||||
|
||||
const std::map<int, XPath::compileFn> XPath::createFunctions()
|
||||
{
|
||||
std::map<int, XPath::compileFn> factory;
|
||||
|
||||
factory[AbsoluteLocationPath_id] = createAbsoluteLocationPath;
|
||||
factory[RelativeLocationPath_id] = createRelativeLocationPath;
|
||||
factory[AbbreviatedAbsoluteLocationPath_id] = createAbsoluteLocationPath;
|
||||
factory[Step_id] = createRelativeLocationPath;
|
||||
factory[PathExpr_id] = createRelativeLocationPath;
|
||||
factory[FilterExpr_id] = createRelativeLocationPath;
|
||||
|
||||
factory[PrimaryExpr_id] = createExpression;
|
||||
|
||||
factory[FunctionCall_id] = createFunction;
|
||||
|
||||
factory[AdditiveExpr_id] = createBinaryExpression;
|
||||
factory[MultiplicativeExpr_id] = createBinaryExpression;
|
||||
factory[EqualityExpr_id] = createBinaryExpression;
|
||||
factory[RelationalExpr_id] = createBinaryExpression;
|
||||
factory[OrExpr_id] = createBinaryExpression;
|
||||
factory[AndExpr_id] = createBinaryExpression;
|
||||
factory[UnionExpr_id] = createBinaryExpression;
|
||||
|
||||
factory[Literal_id] = createLiteral;
|
||||
factory[Number_id] = createNumber;
|
||||
factory[Digits_id] = createNumber;
|
||||
|
||||
factory[VariableReference_id] = createVariable;
|
||||
|
||||
factory[NodeTest_id] = createSingleStepRelativeLocationPath;
|
||||
factory[QName_id] = createSingleStepRelativeLocationPath;
|
||||
factory[NCName_id] = createSingleStepRelativeLocationPath;
|
||||
factory[AnyName_id] = createSingleStepRelativeLocationPath;
|
||||
factory[Text_id] = createSingleStepRelativeLocationPath;
|
||||
factory[Comment_id] = createSingleStepRelativeLocationPath;
|
||||
factory[ProcessingInstruction_id] = createSingleStepRelativeLocationPath;
|
||||
factory[Slash_id] = createSingleStepAbsoluteLocationPath;
|
||||
|
||||
factory[SelfSelect_id] = createSingleStepRelativeLocationPath;
|
||||
factory[ParentSelect_id] = createSingleStepRelativeLocationPath;
|
||||
|
||||
factory[UnaryExpr_id] = createUnaryExpression;
|
||||
factory[UnaryMinusOperator_id] = createUnaryNegativeExpr;
|
||||
|
||||
return factory;
|
||||
} // createFunctions
|
||||
|
||||
const std::map<int, std::string> XPath::debugNames()
|
||||
{
|
||||
std::map<int, std::string> names;
|
||||
|
||||
names[LocationPath_id] = "LocationPath";
|
||||
names[AbsoluteLocationPath_id] = "AbsoluteLocationPath";
|
||||
names[RelativeLocationPath_id] = "RelativeLocationPath";
|
||||
names[Step_id] = "Step";
|
||||
names[AxisSpecifier_id] = "AxisSpecifier";
|
||||
names[NodeTest_id] = "NodeTest";
|
||||
names[Predicate_id] = "Predicate";
|
||||
names[PredicateExpr_id] = "PredicateExpr";
|
||||
names[AbbreviatedAbsoluteLocationPath_id] = "AbbreviatedAbsoluteLocationPath";
|
||||
names[AbbreviatedStep_id] = "AbbreviatedStep";
|
||||
names[AbbreviatedAxisSpecifier_id] = "AbbreviatedAxisSpecifier";
|
||||
names[Expr_id] = "Expr";
|
||||
names[PrimaryExpr_id] = "PrimaryExpr";
|
||||
names[FunctionCall_id] = "FunctionCall";
|
||||
names[Argument_id] = "Argument";
|
||||
names[UnionExpr_id] = "UnionExpr";
|
||||
names[PathExpr_id] = "PathExpr";
|
||||
names[FilterExpr_id] = "FilterExpr";
|
||||
names[OrExpr_id] = "OrExpr";
|
||||
names[AndExpr_id] = "AndExpr";
|
||||
names[EqualityExpr_id] = "EqualityExpr";
|
||||
names[RelationalExpr_id] = "RelationalExpr";
|
||||
names[AdditiveExpr_id] = "AdditiveExpr";
|
||||
names[MultiplicativeExpr_id] = "MultiplicativeExpr";
|
||||
names[UnaryExpr_id] = "UnaryExpr";
|
||||
names[Literal_id] = "Literal";
|
||||
names[Number_id] = "Number";
|
||||
names[Digits_id] = "Digits";
|
||||
names[MultiplyOperator_id] = "MultiplyOperator";
|
||||
names[FunctionName_id] = "FunctionName";
|
||||
names[VariableReference_id] = "VariableReference";
|
||||
names[NameTest_id] = "NameTest";
|
||||
names[S_id] = "S";
|
||||
names[NodeType_id] = "NodeType";
|
||||
names[AxisName_id] = "AxisName";
|
||||
|
||||
names[QName_id] = "QName";
|
||||
names[Prefix_id] = "Prefix";
|
||||
names[LocalPart_id] = "LocalPart";
|
||||
names[NCName_id] = "NCName";
|
||||
names[NCNameChar_id] = "NCNameChar";
|
||||
|
||||
names[Slash_id] = "/";
|
||||
names[SlashSlash_id] = "//";
|
||||
|
||||
names[AncestorOrSelf_id] = "ancestor-or-self::";
|
||||
names[Ancestor_id] = "ancestor::";
|
||||
names[Attribute_id] = "attribute::";
|
||||
names[Child_id] = "child::";
|
||||
names[DescendantOrSelf_id] = "descendant-or-self::";
|
||||
names[Descendant_id] = "descendant::";
|
||||
names[FollowingSibling_id] = "following-sibling::";
|
||||
names[Following_id] = "following::";
|
||||
names[Namespace_id] = "namespace::";
|
||||
names[Parent_id] = "parent::";
|
||||
names[PrecedingSibling_id] = "preceding-sibling::";
|
||||
names[Preceding_id] = "preceding::";
|
||||
names[Self_id] = "self::";
|
||||
|
||||
names[Comment_id] = "comment()";
|
||||
names[Text_id] = "text()";
|
||||
names[ProcessingInstruction_id] = "processing-instruction()";
|
||||
names[Node_id] = "node()";
|
||||
names[AnyName_id] = "AnyName";
|
||||
|
||||
names[SelfSelect_id] = "SelfSelect";
|
||||
names[ParentSelect_id] = "ParentSelect";
|
||||
|
||||
names[LeftSquare_id] = "[";
|
||||
names[RightSquare_id] = "]";
|
||||
|
||||
names[LeftBracket_id] = "(";
|
||||
names[RightBracket_id] = ")";
|
||||
|
||||
names[PlusOperator_id] = "+";
|
||||
names[MinusOperator_id] = "-";
|
||||
names[ModOperator_id] = "mod";
|
||||
names[DivOperator_id] = "div";
|
||||
names[EqualsOperator_id] = "=";
|
||||
names[NotEqualsOperator_id] = "!=";
|
||||
names[LessThanOperator_id] = "<";
|
||||
names[LessThanEqualsOperator_id] = "<=";
|
||||
names[GreaterThanOperator_id] = ">";
|
||||
names[GreaterThanEqualsOperator_id] = ">=";
|
||||
|
||||
names[OrOperator_id] = "or";
|
||||
names[AndOperator_id] = "and";
|
||||
names[UnionOperator_id] = "union";
|
||||
names[UnaryMinusOperator_id] = "minus";
|
||||
|
||||
return names;
|
||||
} // debugNames
|
||||
|
||||
// end
|
Loading…
Reference in a new issue