Class: Oga::XPath::Evaluator Private
- Inherits:
-
Object
- Object
- Oga::XPath::Evaluator
- Defined in:
- lib/oga/xpath/evaluator.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
The Evaluator class evaluates XPath expressions, either as a String or an
AST of AST::Node
instances.
Thread Safety
This class is not thread-safe, you can not share the same instance between multiple threads. This is due to the use of an internal stack (see below for more information). It is however perfectly fine to use multiple separated instances as this class does not use a thread global state.
Node Set Stack
This class uses an internal stack of XML node sets. This stack is used for
functions that require access to the set of nodes a predicate belongs to.
An example of such a function is position()
.
An alternative would be to pass the node sets a predicate belongs to as an
extra argument to the various on_*
methods. The problematic part of
this approach is that it requires every method to take and pass along the
argument. It's far too easy to make mistakes in such a setup and as such
I've chosen to use an internal stack instead.
See #with_node_set and #current_node_set for more information.
Set Indices
XPath node sets start at index 1 instead of index 0. In other words, if you want to access the first node in a set you have to use index 1, not 0. Certain methods such as #on_call_last and #on_call_position take care of converting indices from Ruby to XPath.
Number Types
The XPath specification states that all numbers produced by an expression
should be returned as double-precision 64bit IEEE 754 floating point
numbers. For example, the return value of position()
should be a float
(e.g. "1.0", not "1").
Oga takes care internally of converting numbers to integers and/or floats where needed. The output types however will always be floats.
For more information on the specification, see http://www.w3.org/TR/xpath/#numbers.
Variables
The evaluator supports the binding of custom variables in the
#initialize method. Variables can be bound by passing in a Hash with the
keys set to the variable names (minus the $
sign) and their values to
the variable values. The keys of the variables Hash must be Strings.
A basic example:
evaluator = Evaluator.new(document, 'number' => 10)
evaluator.evaluate('$number') # => 10
Constant Summary collapse
- STAR =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Wildcard for node names/namespace prefixes.
'*'
Instance Method Summary collapse
-
#child_nodes(nodes) ⇒ Oga::XML::NodeSet
private
Returns a node set containing all the child nodes of the given set of nodes.
- #current_node_set ⇒ Oga::XML::NodeSet private
-
#evaluate(string) ⇒ Mixed
private
Evaluates an XPath expression as a String.
-
#evaluate_ast(ast) ⇒ Mixed
private
Evaluates a pre-parsed XPath expression.
-
#first_node_text(set) ⇒ String
private
Returns the text of the first node in the node set, or an empty string if the node set is empty.
-
#function_node(context, expression = nil) ⇒ Oga::XML::Node
private
Returns the node for a function call.
- #has_parent?(ast_node) ⇒ TrueClass|FalseClass private
-
#initialize(document, variables = {}) ⇒ Evaluator
constructor
private
A new instance of Evaluator.
-
#name_matches?(xml_node, name) ⇒ Boolean
private
Returns
true
if the name of the XML node matches the given name or matches a wildcard. -
#namespace_matches?(xml_node, ns) ⇒ Boolean
private
Returns
true
if the namespace of the XML node matches the given namespace or matches a wildcard. -
#node_matches?(xml_node, ast_node) ⇒ Oga::XML::NodeSet
private
Checks if a given Oga::XML::Node instance matches a
AST::Node
instance. -
#on_absolute_path(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes an absolute XPath expression such as
/foo
. -
#on_add(ast_node, context) ⇒ Float
private
Processes the
+
operator. -
#on_and(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
and
operator. -
#on_axis(ast_node, context) ⇒ Oga::XML::NodeSet
private
Dispatches the processing of axes to dedicated methods.
-
#on_axis_ancestor(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the
ancestor
axis. -
#on_axis_ancestor_or_self(ast_node, context) ⇒ Object
private
Processes the
ancestor-or-self
axis. -
#on_axis_attribute(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the
attribute
axis. -
#on_axis_child(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
child
axis. -
#on_axis_descendant(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
descendant
axis. -
#on_axis_descendant_or_self(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
descendant-or-self
axis. -
#on_axis_following(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
following
axis. -
#on_axis_following_sibling(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
following-sibling
axis. -
#on_axis_namespace(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
namespace
axis. -
#on_axis_parent(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
parent
axis. -
#on_axis_preceding(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
preceding
axis. -
#on_axis_preceding_sibling(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
preceding-sibling
axis. -
#on_axis_self(ast_node, context) ⇒ Oga::XML::NodeSet
private
Evaluates the
self
axis. -
#on_call(ast_node, context) ⇒ Oga::XML::NodeSet
private
Delegates function calls to specific handlers.
-
#on_call_boolean(context, expression) ⇒ TrueClass|FalseClass
private
Processes the
boolean()
function call. -
#on_call_ceiling(context, expression) ⇒ Float
private
Processes the
ceiling()
function call. -
#on_call_concat(context, first, second, *rest) ⇒ Object
private
Processes the
concat()
function call. -
#on_call_contains(context, haystack, needle) ⇒ String
private
Processes the
contains()
function call. -
#on_call_count(context, expression) ⇒ Float
private
Processes the
count()
function call. -
#on_call_false(context) ⇒ FalseClass
private
Processes the
false()
function call. -
#on_call_floor(context, expression) ⇒ Float
private
Processes the
floor()
function call. -
#on_call_id(context, expression) ⇒ Oga::XML::NodeSet
private
Processes the
id()
function call. -
#on_call_lang(context, language) ⇒ TrueClass|FalseClass
private
Processes the
lang()
function call. -
#on_call_last(context) ⇒ Float
private
Processes the
last()
function call. -
#on_call_local_name(context, expression = nil) ⇒ Oga::XML::NodeSet
private
Processes the
local-name()
function call. -
#on_call_name(context, expression = nil) ⇒ Oga::XML::NodeSet
private
Processes the
name()
function call. -
#on_call_namespace_uri(context, expression = nil) ⇒ Oga::XML::NodeSet
private
Processes the
namespace-uri()
function call. -
#on_call_normalize_space(context, expression = nil) ⇒ String
private
Processes the
normalize-space()
function call. -
#on_call_not(context, expression) ⇒ TrueClass|FalseClass
private
Processes the
not()
function call. -
#on_call_number(context, expression = nil) ⇒ Float
private
Evaluates the
number()
function call. -
#on_call_position(context) ⇒ Float
private
Processes the
position()
function call. -
#on_call_round(context, expression) ⇒ Float
private
Processes the
round()
function call. -
#on_call_starts_with(context, haystack, needle) ⇒ TrueClass|FalseClass
private
Processes the
starts-with()
function call. -
#on_call_string(context, expression = nil) ⇒ String
private
Evaluates the
string()
function call. -
#on_call_string_length(context, expression = nil) ⇒ Float
private
Processes the
string-length()
function. -
#on_call_substring(context, haystack, start, length = nil) ⇒ String
private
Processes the
substring()
function call. -
#on_call_substring_after(context, haystack, needle) ⇒ String
private
Processes the
substring-after()
function call. -
#on_call_substring_before(context, haystack, needle) ⇒ String
private
Processes the
substring-before()
function call. -
#on_call_sum(context, expression) ⇒ Float
private
Processes the
sum()
function call. -
#on_call_translate(context, input, find, replace) ⇒ String
private
Processes the
translate()
function call. -
#on_call_true(context) ⇒ TrueClass
private
Processes the
true()
function call. -
#on_div(ast_node, context) ⇒ Float
private
Processes the
div
operator. -
#on_eq(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
=
operator. -
#on_float(ast_node, context) ⇒ Float
private
Processes an
(float)
node. -
#on_gt(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
>
operator. -
#on_gte(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
>=
operator. -
#on_int(ast_node, context) ⇒ Float
private
Processes an
(int)
node. -
#on_lt(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
<
operator. -
#on_lte(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
<=
operator. -
#on_mod(ast_node, context) ⇒ Float
private
Processes the
mod
operator. -
#on_mul(ast_node, context) ⇒ Float
private
Processes the
*
operator. -
#on_neq(ast_node, context) ⇒ Object
private
Processes the
!=
operator. -
#on_or(ast_node, context) ⇒ TrueClass|FalseClass
private
Processes the
or
operator. -
#on_path(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes a relative XPath expression such as
foo
. -
#on_pipe(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the pipe (
|
) operator. -
#on_predicate(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes a predicate.
-
#on_string(ast_node, context) ⇒ String
private
Processes a
(string)
node. -
#on_sub(ast_node, context) ⇒ Float
private
Processes the
-
operator. -
#on_test(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes a node test.
-
#on_type_test(ast_node, context) ⇒ Oga::XML::NodeSet
private
Dispatches node type matching to dedicated handlers.
-
#on_type_test_comment(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the
comment()
type test. -
#on_type_test_node(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the
node
type matcher. -
#on_type_test_processing_instruction(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the
processing-instruction()
type test. -
#on_type_test_text(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes the
text()
type test. -
#on_var(ast_node, context) ⇒ Mixed
private
Processes a variable reference.
-
#parent_node(node) ⇒ Oga::XML::Node|Oga::XML::Document
private
Returns the parent node of
node
, ornode
itself if its a Document. -
#process(ast_node, context) ⇒ Oga::XML::NodeSet
private
Processes an XPath node by dispatching it and the given context to a dedicated handler method.
-
#root_node(node) ⇒ Oga::XML::Node|Oga::XML::Document
private
Returns the root node of
node
, ornode
itself if its a Document. -
#to_float(value) ⇒ Float
private
Converts the given value to a float.
-
#to_string(value) ⇒ String
private
Converts the given value to a string according to the XPath string conversion rules.
- #type_matches?(xml_node, ast_node) ⇒ TrueClass|FalseClass private
-
#with_node_set(nodes) ⇒ Object
private
Stores the specified node set and yields the supplied block.
Constructor Details
#initialize(document, variables = {}) ⇒ Evaluator
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of Evaluator.
72 73 74 75 76 |
# File 'lib/oga/xpath/evaluator.rb', line 72 def initialize(document, variables = {}) @document = document @variables = variables @node_sets = [] end |
Instance Method Details
#child_nodes(nodes) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a node set containing all the child nodes of the given set of nodes.
1610 1611 1612 1613 1614 1615 1616 1617 1618 |
# File 'lib/oga/xpath/evaluator.rb', line 1610 def child_nodes(nodes) children = XML::NodeSet.new nodes.each do |xml_node| children.concat(xml_node.children) end children end |
#current_node_set ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
1773 1774 1775 |
# File 'lib/oga/xpath/evaluator.rb', line 1773 def current_node_set @node_sets.last end |
#evaluate(string) ⇒ Mixed
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates an XPath expression as a String.
89 90 91 92 93 |
# File 'lib/oga/xpath/evaluator.rb', line 89 def evaluate(string) ast = Parser.parse_with_cache(string) evaluate_ast(ast) end |
#evaluate_ast(ast) ⇒ Mixed
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates a pre-parsed XPath expression.
101 102 103 104 105 |
# File 'lib/oga/xpath/evaluator.rb', line 101 def evaluate_ast(ast) context = XML::NodeSet.new([@document]) process(ast, context) end |
#first_node_text(set) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the text of the first node in the node set, or an empty string if the node set is empty.
1599 1600 1601 |
# File 'lib/oga/xpath/evaluator.rb', line 1599 def first_node_text(set) set[0].respond_to?(:text) ? set[0].text : '' end |
#function_node(context, expression = nil) ⇒ Oga::XML::Node
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the node for a function call. This node is either the first node in the supplied node set, or the first node in the current context.
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 |
# File 'lib/oga/xpath/evaluator.rb', line 1576 def function_node(context, expression = nil) if expression node = process(expression, context) if node.is_a?(XML::NodeSet) node = node.first else raise TypeError, 'only node sets can be used as arguments' end else node = context.first end node end |
#has_parent?(ast_node) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
1716 1717 1718 |
# File 'lib/oga/xpath/evaluator.rb', line 1716 def has_parent?(ast_node) ast_node.respond_to?(:parent) && !!ast_node.parent end |
#name_matches?(xml_node, name) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns true
if the name of the XML node matches the given name or
matches a wildcard.
1691 1692 1693 1694 1695 |
# File 'lib/oga/xpath/evaluator.rb', line 1691 def name_matches?(xml_node, name) return false unless xml_node.respond_to?(:name) name == STAR ? true : xml_node.name == name end |
#namespace_matches?(xml_node, ns) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns true
if the namespace of the XML node matches the given
namespace or matches a wildcard.
1704 1705 1706 1707 1708 1709 1710 |
# File 'lib/oga/xpath/evaluator.rb', line 1704 def namespace_matches?(xml_node, ns) return false unless xml_node.respond_to?(:namespace) return true if ns == STAR xml_node.namespace && xml_node.namespace.name == ns end |
#node_matches?(xml_node, ast_node) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Checks if a given Oga::XML::Node instance matches a AST::Node
instance.
This method can use both "test" and "type-test" nodes. In case of "type-test" nodes the procedure is as following:
- Evaluate the expression
- If the return value is non empty return
true
, otherwise returnfalse
For "test" nodes the procedure is as following instead:
- Match the name
- Match the namespace
For both the name and namespace a wildcard (*
) can be used.
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 |
# File 'lib/oga/xpath/evaluator.rb', line 1642 def node_matches?(xml_node, ast_node) ns, name = *ast_node.children if ast_node.type.equal?(:type_test) return type_matches?(xml_node, ast_node) end # If only the name is given and is a wildcard then we'll also want to # match the namespace as a wildcard. if !ns and name == STAR ns = STAR end name_matches = name_matches?(xml_node, name) ns_matches = false if ns ns_matches = namespace_matches?(xml_node, ns) elsif name_matches and !xml_node.namespace ns_matches = true end if !ns and !ns_matches ns_matches = xml_node.respond_to?(:default_namespace?) && xml_node.default_namespace? end name_matches && ns_matches end |
#on_absolute_path(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes an absolute XPath expression such as /foo
.
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/oga/xpath/evaluator.rb', line 132 def on_absolute_path(ast_node, context) if @document.respond_to?(:root_node) context = XML::NodeSet.new([@document.root_node]) else context = XML::NodeSet.new([@document]) end # If the expression is just "/" we'll just return the current context. ast_node.children.empty? ? context : on_path(ast_node, context) end |
#on_add(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the +
operator.
This operator converts the left and right expressions to numbers and adds them together.
695 696 697 698 699 |
# File 'lib/oga/xpath/evaluator.rb', line 695 def on_add(ast_node, context) left, right = *ast_node.children on_call_number(context, left) + on_call_number(context, right) end |
#on_and(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the and
operator.
This operator returns true if both the left and right expression
evaluate to true
. If the first expression evaluates to false
the
right expression is ignored.
662 663 664 665 666 |
# File 'lib/oga/xpath/evaluator.rb', line 662 def on_and(ast_node, context) left, right = *ast_node.children on_call_boolean(context, left) && on_call_boolean(context, right) end |
#on_axis(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Dispatches the processing of axes to dedicated methods. This works similar to #process except the handler names are "on_axis_X" with "X" being the axis name.
236 237 238 239 240 241 242 |
# File 'lib/oga/xpath/evaluator.rb', line 236 def on_axis(ast_node, context) name, test = *ast_node.children handler = name.gsub('-', '_') send("on_axis_#{handler}", test, context) end |
#on_axis_ancestor(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the ancestor
axis. This axis walks through the entire
ancestor chain until a matching node is found.
Evaluation happens using a "short-circuit" mechanism. The moment a matching node is found it is returned immediately.
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/oga/xpath/evaluator.rb', line 255 def on_axis_ancestor(ast_node, context) nodes = XML::NodeSet.new context.each do |xml_node| while has_parent?(xml_node) xml_node = xml_node.parent if node_matches?(xml_node, ast_node) nodes << xml_node break end end end nodes end |
#on_axis_ancestor_or_self(ast_node, context) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the ancestor-or-self
axis.
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/oga/xpath/evaluator.rb', line 277 def on_axis_ancestor_or_self(ast_node, context) nodes = XML::NodeSet.new context.each do |xml_node| while has_parent?(xml_node) if node_matches?(xml_node, ast_node) nodes << xml_node break end xml_node = xml_node.parent end end nodes end |
#on_axis_attribute(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the attribute
axis. The node test is performed against all
the attributes of the nodes in the current context.
Evaluation of the nodes continues until the node set has been exhausted (unlike some other methods which return the moment they find a matching node).
306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/oga/xpath/evaluator.rb', line 306 def on_axis_attribute(ast_node, context) nodes = XML::NodeSet.new context.each do |xml_node| next unless xml_node.is_a?(XML::Element) nodes += on_test(ast_node, xml_node.attributes) end nodes end |
#on_axis_child(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the child
axis. This axis simply takes all the child nodes
of the current context nodes.
326 327 328 |
# File 'lib/oga/xpath/evaluator.rb', line 326 def on_axis_child(ast_node, context) process(ast_node, child_nodes(context)) end |
#on_axis_descendant(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the descendant
axis. This method processes child nodes until
the very end of the tree, no "short-circuiting" mechanism is used.
338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/oga/xpath/evaluator.rb', line 338 def on_axis_descendant(ast_node, context) nodes = XML::NodeSet.new context.each do |context_node| context_node.each_node do |node| nodes.concat(process(ast_node, XML::NodeSet.new([node]))) end end nodes end |
#on_axis_descendant_or_self(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the descendant-or-self
axis.
357 358 359 360 361 362 363 |
# File 'lib/oga/xpath/evaluator.rb', line 357 def on_axis_descendant_or_self(ast_node, context) nodes = on_test(ast_node, context) nodes.concat(on_axis_descendant(ast_node, context)) nodes end |
#on_axis_following(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the following
axis.
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/oga/xpath/evaluator.rb', line 372 def on_axis_following(ast_node, context) nodes = XML::NodeSet.new root = root_node(@document) context.each do |context_node| check = false root.each_node do |doc_node| # Skip child nodes of the current context node, compare all # following nodes. if doc_node == context_node check = true throw :skip_children end next unless check nodes << doc_node if node_matches?(doc_node, ast_node) end end nodes end |
#on_axis_following_sibling(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the following-sibling
axis.
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/oga/xpath/evaluator.rb', line 403 def on_axis_following_sibling(ast_node, context) nodes = XML::NodeSet.new root = parent_node(@document) context.each do |context_node| check = false parent = has_parent?(context_node) ? context_node.parent : nil root.each_node do |doc_node| # Skip child nodes of the current context node, compare all # following nodes. if doc_node == context_node check = true throw :skip_children end if !check or parent != doc_node.parent next end if node_matches?(doc_node, ast_node) nodes << doc_node throw :skip_children end end end nodes end |
#on_axis_namespace(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the namespace
axis.
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
# File 'lib/oga/xpath/evaluator.rb', line 534 def on_axis_namespace(ast_node, context) nodes = XML::NodeSet.new name = ast_node.children[1] context.each do |context_node| next unless context_node.respond_to?(:available_namespaces) context_node.available_namespaces.each do |_, namespace| if namespace.name == name or name == STAR nodes << namespace end end end nodes end |
#on_axis_parent(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the parent
axis.
441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/oga/xpath/evaluator.rb', line 441 def on_axis_parent(ast_node, context) nodes = XML::NodeSet.new context.each do |context_node| next unless has_parent?(context_node) parent = context_node.parent nodes << parent if node_matches?(parent, ast_node) end nodes end |
#on_axis_preceding(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the preceding
axis.
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/oga/xpath/evaluator.rb', line 462 def on_axis_preceding(ast_node, context) nodes = XML::NodeSet.new root = root_node(@document) context.each do |context_node| check = true root.each_node do |doc_node| # Test everything *until* we hit the current context node. if doc_node == context_node break elsif node_matches?(doc_node, ast_node) nodes << doc_node end end end nodes end |
#on_axis_preceding_sibling(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the preceding-sibling
axis.
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
# File 'lib/oga/xpath/evaluator.rb', line 489 def on_axis_preceding_sibling(ast_node, context) nodes = XML::NodeSet.new root = parent_node(@document) context.each do |context_node| check = true parent = has_parent?(context_node) ? context_node.parent : nil root.each_node do |doc_node| # Test everything *until* we hit the current context node. if doc_node == context_node break elsif doc_node.parent == parent and node_matches?(doc_node, ast_node) nodes << doc_node end end end nodes end |
#on_axis_self(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the self
axis.
517 518 519 520 521 522 523 524 525 |
# File 'lib/oga/xpath/evaluator.rb', line 517 def on_axis_self(ast_node, context) nodes = XML::NodeSet.new context.each do |context_node| nodes << context_node if node_matches?(context_node, ast_node) end nodes end |
#on_call(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Delegates function calls to specific handlers.
Handler functions take two arguments:
- The context node set
- A variable list of XPath function arguments, passed as individual Ruby method arguments.
892 893 894 895 896 897 898 |
# File 'lib/oga/xpath/evaluator.rb', line 892 def on_call(ast_node, context) name, *args = *ast_node.children handler = name.gsub('-', '_') send("on_call_#{handler}", context, *args) end |
#on_call_boolean(context, expression) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the boolean()
function call.
This function converts the 1st argument to a boolean.
The boolean true
is returned for the following:
- A non empty string
- A non empty node set
- A non zero number, either positive or negative
The boolean false
is returned for all other cases.
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 |
# File 'lib/oga/xpath/evaluator.rb', line 1353 def on_call_boolean(context, expression) retval = process(expression, context) bool = false if retval.is_a?(Numeric) bool = !retval.nan? && !retval.zero? elsif retval bool = !retval.respond_to?(:empty?) || !retval.empty? end bool end |
#on_call_ceiling(context, expression) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the ceiling()
function call.
This function call rounds the 1st argument up to the closest integer, and then returns that number as a float.
1494 1495 1496 1497 1498 |
# File 'lib/oga/xpath/evaluator.rb', line 1494 def on_call_ceiling(context, expression) number = on_call_number(context, expression) number.nan? ? number : number.ceil.to_f end |
#on_call_concat(context, first, second, *rest) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the concat()
function call.
This function call converts its arguments to strings and concatenates them. In case of node sets the text of the set is used.
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 |
# File 'lib/oga/xpath/evaluator.rb', line 1130 def on_call_concat(context, first, second, *rest) args = [first, second] + rest retval = '' args.each do |arg| retval << on_call_string(context, arg) end retval end |
#on_call_contains(context, haystack, needle) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the contains()
function call.
This function call returns true
if the string in the 1st argument
contains the string in the 2nd argument. Node sets can also be used.
1177 1178 1179 1180 1181 1182 |
# File 'lib/oga/xpath/evaluator.rb', line 1177 def on_call_contains(context, haystack, needle) haystack_str = on_call_string(context, haystack) needle_str = on_call_string(context, needle) haystack_str.include?(needle_str) end |
#on_call_count(context, expression) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the count()
function call. This function counts the amount
of nodes in expression
and returns the result as a float.
933 934 935 936 937 938 939 940 941 |
# File 'lib/oga/xpath/evaluator.rb', line 933 def on_call_count(context, expression) retval = process(expression, context) unless retval.is_a?(XML::NodeSet) raise TypeError, 'count() can only operate on NodeSet instances' end retval.length.to_f end |
#on_call_false(context) ⇒ FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the false()
function call.
This function simply returns the boolean false
.
1401 1402 1403 |
# File 'lib/oga/xpath/evaluator.rb', line 1401 def on_call_false(context) false end |
#on_call_floor(context, expression) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the floor()
function call.
This function call rounds the 1st argument down to the closest integer, and then returns that number as a float.
1478 1479 1480 1481 1482 |
# File 'lib/oga/xpath/evaluator.rb', line 1478 def on_call_floor(context, expression) number = on_call_number(context, expression) number.nan? ? number : number.floor.to_f end |
#on_call_id(context, expression) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the id()
function call.
The XPath specification states that this function's behaviour should be controlled by a DTD. If a DTD were to specify that the ID attribute for a certain element would be "foo" then this function should use said attribute.
Oga does not support DTD parsing/evaluation and as such always uses the "id" attribute.
This function searches the entire document for a matching node, regardless of the current position.
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
# File 'lib/oga/xpath/evaluator.rb', line 961 def on_call_id(context, expression) id = process(expression, context) nodes = XML::NodeSet.new # Based on Nokogiri's/libxml behaviour it appears that when using a node # set the text of the set is used as the ID. id = id.is_a?(XML::NodeSet) ? id.text : id.to_s ids = id.split(' ') @document.each_node do |node| next unless node.is_a?(XML::Element) attr = node.attribute('id') if attr and ids.include?(attr.value) nodes << node end end nodes end |
#on_call_lang(context, language) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the lang()
function call.
This function returns true
if the current context node is in the given
language, false
otherwise.
The language is based on the value of the "xml:lang" attribute of either the context node or an ancestor node (in case the context node has no such attribute).
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 |
# File 'lib/oga/xpath/evaluator.rb', line 1419 def on_call_lang(context, language) lang_str = on_call_string(context, language) node = context.first while node.respond_to?(:attribute) found = node.attribute('xml:lang') return found.value == lang_str if found node = node.parent end false end |
#on_call_last(context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the last()
function call. This function call returns the
index of the last node in the current set.
907 908 909 910 |
# File 'lib/oga/xpath/evaluator.rb', line 907 def on_call_last(context) # XPath uses indexes 1 to N instead of 0 to N. current_node_set.length.to_f end |
#on_call_local_name(context, expression = nil) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the local-name()
function call.
This function call returns the name of one of the following:
- The current context node (if any)
- The first node in the supplied node set
995 996 997 998 999 |
# File 'lib/oga/xpath/evaluator.rb', line 995 def on_call_local_name(context, expression = nil) node = function_node(context, expression) node.respond_to?(:name) ? node.name : '' end |
#on_call_name(context, expression = nil) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the name()
function call.
This function call is similar to local-name()
(see
#on_call_local_name) except that it includes the namespace name if
present.
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
# File 'lib/oga/xpath/evaluator.rb', line 1012 def on_call_name(context, expression = nil) node = function_node(context, expression) if node.respond_to?(:name) and node.respond_to?(:namespace) if node.namespace return "#{node.namespace.name}:#{node.name}" else return node.name end else return '' end end |
#on_call_namespace_uri(context, expression = nil) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the namespace-uri()
function call.
This function call returns the namespace URI of one of the following:
- The current context node (if any)
- The first node in the supplied node set
1038 1039 1040 1041 1042 1043 1044 1045 1046 |
# File 'lib/oga/xpath/evaluator.rb', line 1038 def on_call_namespace_uri(context, expression = nil) node = function_node(context, expression) if node.respond_to?(:namespace) and node.namespace return node.namespace.uri else return '' end end |
#on_call_normalize_space(context, expression = nil) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the normalize-space()
function call.
This function strips the 1st argument string or the current context node of leading/trailing whitespace as well as replacing multiple whitespace sequences with single spaces.
1301 1302 1303 1304 1305 |
# File 'lib/oga/xpath/evaluator.rb', line 1301 def on_call_normalize_space(context, expression = nil) str = on_call_string(context, expression) str.strip.gsub(/\s+/, ' ') end |
#on_call_not(context, expression) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the not()
function call.
This function converts the 1st argument to a boolean and returns the
opposite boolean value. For example, if the first argument results in
true
then this function returns false
instead.
1377 1378 1379 |
# File 'lib/oga/xpath/evaluator.rb', line 1377 def on_call_not(context, expression) !on_call_boolean(context, expression) end |
#on_call_number(context, expression = nil) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the number()
function call.
This function call converts its first argument or the current context
node to a number, similar to the string()
function.
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 |
# File 'lib/oga/xpath/evaluator.rb', line 1094 def on_call_number(context, expression = nil) convert = nil if expression exp_retval = process(expression, context) if exp_retval.is_a?(XML::NodeSet) convert = first_node_text(exp_retval) elsif exp_retval == true convert = 1.0 elsif exp_retval == false convert = 0.0 elsif exp_retval convert = exp_retval end else convert = context.first.text end to_float(convert) end |
#on_call_position(context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the position()
function call. This function returns the
position of the current node in the current node set.
919 920 921 922 923 |
# File 'lib/oga/xpath/evaluator.rb', line 919 def on_call_position(context) index = current_node_set.index(context.first) + 1 index.to_f end |
#on_call_round(context, expression) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the round()
function call.
This function call rounds the 1st argument to the closest integer, and then returns that number as a float.
1510 1511 1512 1513 1514 |
# File 'lib/oga/xpath/evaluator.rb', line 1510 def on_call_round(context, expression) number = on_call_number(context, expression) number.nan? ? number : number.round.to_f end |
#on_call_starts_with(context, haystack, needle) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the starts-with()
function call.
This function call returns true
if the string in the 1st argument
starts with the string in the 2nd argument. Node sets can also be used.
1155 1156 1157 1158 1159 1160 1161 |
# File 'lib/oga/xpath/evaluator.rb', line 1155 def on_call_starts_with(context, haystack, needle) haystack_str = on_call_string(context, haystack) needle_str = on_call_string(context, needle) # https://github.com/jruby/jruby/issues/1923 needle_str.empty? || haystack_str.start_with?(needle_str) end |
#on_call_string(context, expression = nil) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluates the string()
function call.
This function call converts the given argument or the current context node to a string. If a node set is given then only the first node is converted to a string.
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 |
# File 'lib/oga/xpath/evaluator.rb', line 1062 def on_call_string(context, expression = nil) if expression convert = process(expression, context) if convert.is_a?(XML::NodeSet) convert = convert[0] end else convert = context.first end if convert.respond_to?(:text) return convert.text else return to_string(convert) end end |
#on_call_string_length(context, expression = nil) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the string-length()
function.
This function returns the length of the string given in the 1st argument
or the current context node. If the expression is not a string it's
converted to a string using the string()
function.
1283 1284 1285 |
# File 'lib/oga/xpath/evaluator.rb', line 1283 def on_call_string_length(context, expression = nil) on_call_string(context, expression).length.to_f end |
#on_call_substring(context, haystack, start, length = nil) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the substring()
function call.
This function call returns the substring of the 1st argument, starting at the position given in the 2nd argument. If the third argument is given it is used as the length for the substring, otherwise the string is consumed until the end.
XPath string indexes start from position 1, not position 0.
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
# File 'lib/oga/xpath/evaluator.rb', line 1257 def on_call_substring(context, haystack, start, length = nil) haystack_str = on_call_string(context, haystack) start_index = on_call_number(context, start).to_i - 1 if length length_int = on_call_number(context, length).to_i - 1 stop_index = start_index + length_int else stop_index = -1 end haystack_str[start_index..stop_index] end |
#on_call_substring_after(context, haystack, needle) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the substring-after()
function call.
This function call returns the substring of the 1st argument that occurs after the string given in the 2nd argument. For example:
substring-after("2014-08-25", "-")
This would return "08-25" as it occurs after the first "-".
1223 1224 1225 1226 1227 1228 1229 1230 |
# File 'lib/oga/xpath/evaluator.rb', line 1223 def on_call_substring_after(context, haystack, needle) haystack_str = on_call_string(context, haystack) needle_str = on_call_string(context, needle) before, sep, after = haystack_str.partition(needle_str) sep.empty? ? sep : after end |
#on_call_substring_before(context, haystack, needle) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the substring-before()
function call.
This function call returns the substring of the 1st argument that occurs before the string given in the 2nd argument. For example:
substring-before("2014-08-25", "-")
This would return "2014" as it occurs before the first "-".
1199 1200 1201 1202 1203 1204 1205 1206 |
# File 'lib/oga/xpath/evaluator.rb', line 1199 def on_call_substring_before(context, haystack, needle) haystack_str = on_call_string(context, haystack) needle_str = on_call_string(context, needle) before, sep, after = haystack_str.partition(needle_str) sep.empty? ? sep : before end |
#on_call_sum(context, expression) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the sum()
function call.
This function call takes a node set, converts each node to a number and then sums the values.
As an example, take the following XML:
<root>
<a>1</a>
<b>2</b>
</root>
Using the expression sum(root/*)
the return value would be 3.0
.
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 |
# File 'lib/oga/xpath/evaluator.rb', line 1453 def on_call_sum(context, expression) nodes = process(expression, context) sum = 0.0 unless nodes.is_a?(XML::NodeSet) raise TypeError, 'sum() can only operate on NodeSet instances' end nodes.each do |node| sum += node.text.to_f end sum end |
#on_call_translate(context, input, find, replace) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the translate()
function call.
This function takes the string of the 1st argument and replaces all characters of the 2nd argument with those specified in the 3rd argument.
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 |
# File 'lib/oga/xpath/evaluator.rb', line 1322 def on_call_translate(context, input, find, replace) input_str = on_call_string(context, input) find_chars = on_call_string(context, find).chars.to_a replace_chars = on_call_string(context, replace).chars.to_a replaced = input_str find_chars.each_with_index do |char, index| replace_with = replace_chars[index] ? replace_chars[index] : '' replaced = replaced.gsub(char, replace_with) end replaced end |
#on_call_true(context) ⇒ TrueClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the true()
function call.
This function simply returns the boolean true
.
1389 1390 1391 |
# File 'lib/oga/xpath/evaluator.rb', line 1389 def on_call_true(context) true end |
#on_div(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the div
operator.
This operator converts the left and right expressions to numbers and divides the left number with the right number.
711 712 713 714 715 |
# File 'lib/oga/xpath/evaluator.rb', line 711 def on_div(ast_node, context) left, right = *ast_node.children on_call_number(context, left) / on_call_number(context, right) end |
#on_eq(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the =
operator.
This operator evaluates the expression on the left and right and returns
true
if they are equal. This operator can be used to compare strings,
numbers and node sets. When using node sets the text of the set is
compared instead of the nodes themselves. That is, nodes with different
names but the same text are considered to be equal.
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/oga/xpath/evaluator.rb', line 778 def on_eq(ast_node, context) left = process(ast_node.children[0], context) right = process(ast_node.children[1], context) if left.is_a?(XML::NodeSet) left = first_node_text(left) end if right.is_a?(XML::NodeSet) right = first_node_text(right) end if left.is_a?(Numeric) and !right.is_a?(Numeric) right = to_float(right) end if left.is_a?(String) and !right.is_a?(String) right = to_string(right) end left == right end |
#on_float(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes an (float)
node.
1534 1535 1536 |
# File 'lib/oga/xpath/evaluator.rb', line 1534 def on_float(ast_node, context) ast_node.children[0] end |
#on_gt(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the >
operator.
This operator converts the left and right expression to a number and
returns true
if the first number is greater than the second number.
839 840 841 842 843 |
# File 'lib/oga/xpath/evaluator.rb', line 839 def on_gt(ast_node, context) left, right = *ast_node.children on_call_number(context, left) > on_call_number(context, right) end |
#on_gte(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the >=
operator.
This operator converts the left and right expression to a number and
returns true
if the first number is greater-than or equal to the
second number.
873 874 875 876 877 |
# File 'lib/oga/xpath/evaluator.rb', line 873 def on_gte(ast_node, context) left, right = *ast_node.children on_call_number(context, left) >= on_call_number(context, right) end |
#on_int(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes an (int)
node.
1523 1524 1525 |
# File 'lib/oga/xpath/evaluator.rb', line 1523 def on_int(ast_node, context) ast_node.children[0].to_f end |
#on_lt(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the <
operator.
This operator converts the left and right expression to a number and
returns true
if the first number is lower than the second number.
823 824 825 826 827 |
# File 'lib/oga/xpath/evaluator.rb', line 823 def on_lt(ast_node, context) left, right = *ast_node.children on_call_number(context, left) < on_call_number(context, right) end |
#on_lte(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the <=
operator.
This operator converts the left and right expression to a number and
returns true
if the first number is lower-than or equal to the second
number.
856 857 858 859 860 |
# File 'lib/oga/xpath/evaluator.rb', line 856 def on_lte(ast_node, context) left, right = *ast_node.children on_call_number(context, left) <= on_call_number(context, right) end |
#on_mod(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the mod
operator.
This operator converts the left and right expressions to numbers and returns the modulo of the two numbers.
727 728 729 730 731 |
# File 'lib/oga/xpath/evaluator.rb', line 727 def on_mod(ast_node, context) left, right = *ast_node.children on_call_number(context, left) % on_call_number(context, right) end |
#on_mul(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the *
operator.
This operator converts the left and right expressions to numbers and multiplies the left number with the right number.
743 744 745 746 747 |
# File 'lib/oga/xpath/evaluator.rb', line 743 def on_mul(ast_node, context) left, right = *ast_node.children on_call_number(context, left) * on_call_number(context, right) end |
#on_neq(ast_node, context) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the !=
operator.
This operator does the exact opposite of the =
operator. See #on_eq
for more information.
809 810 811 |
# File 'lib/oga/xpath/evaluator.rb', line 809 def on_neq(ast_node, context) !on_eq(ast_node, context) end |
#on_or(ast_node, context) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the or
operator.
This operator returns true
if one of the expressions evaluates to
true, otherwise false is returned. If the first expression evaluates to
true
the second expression is ignored.
679 680 681 682 683 |
# File 'lib/oga/xpath/evaluator.rb', line 679 def on_or(ast_node, context) left, right = *ast_node.children on_call_boolean(context, left) || on_call_boolean(context, right) end |
#on_path(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes a relative XPath expression such as foo
.
Paths are evaluated using a "short-circuit" mechanism similar to Ruby's
&&
/ and
operator. Whenever a path results in an empty node set the
evaluation is aborted immediately.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/oga/xpath/evaluator.rb', line 154 def on_path(ast_node, context) nodes = XML::NodeSet.new ast_node.children.each do |test| nodes = process(test, context) if nodes.empty? break else context = nodes end end nodes end |
#on_pipe(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the pipe (|
) operator. This operator creates a union of two
sets.
645 646 647 648 649 |
# File 'lib/oga/xpath/evaluator.rb', line 645 def on_pipe(ast_node, context) left, right = *ast_node.children process(left, context) + process(right, context) end |
#on_predicate(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes a predicate.
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/oga/xpath/evaluator.rb', line 194 def on_predicate(ast_node, context) test, predicate = *ast_node.children final_nodes = XML::NodeSet.new context.each do |context_node| initial_nodes = process(test, XML::NodeSet.new([context_node])) xpath_index = 1 initial_nodes.each do |xml_node| retval = with_node_set(initial_nodes) do process(predicate, XML::NodeSet.new([xml_node])) end # Numeric values are used as node set indexes. if retval.is_a?(Numeric) final_nodes << xml_node if retval.to_i == xpath_index # Node sets, strings, booleans, etc elsif retval if retval.respond_to?(:empty?) and retval.empty? next end final_nodes << xml_node end xpath_index += 1 end end final_nodes end |
#on_string(ast_node, context) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes a (string)
node.
1545 1546 1547 |
# File 'lib/oga/xpath/evaluator.rb', line 1545 def on_string(ast_node, context) ast_node.children[0] end |
#on_sub(ast_node, context) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the -
operator.
This operator converts the left and right expressions to numbers and subtracts the right number of the left number.
759 760 761 762 763 |
# File 'lib/oga/xpath/evaluator.rb', line 759 def on_sub(ast_node, context) left, right = *ast_node.children on_call_number(context, left) - on_call_number(context, right) end |
#on_test(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes a node test.
177 178 179 180 181 182 183 184 185 |
# File 'lib/oga/xpath/evaluator.rb', line 177 def on_test(ast_node, context) nodes = XML::NodeSet.new context.each do |xml_node| nodes << xml_node if node_matches?(xml_node, ast_node) end nodes end |
#on_type_test(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Dispatches node type matching to dedicated handlers.
558 559 560 561 562 563 564 |
# File 'lib/oga/xpath/evaluator.rb', line 558 def on_type_test(ast_node, context) name, test = *ast_node.children handler = name.gsub('-', '_') send("on_type_test_#{handler}", test, context) end |
#on_type_test_comment(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the comment()
type test. This matches only comment nodes.
609 610 611 612 613 614 615 616 617 |
# File 'lib/oga/xpath/evaluator.rb', line 609 def on_type_test_comment(ast_node, context) nodes = XML::NodeSet.new context.each do |node| nodes << node if node.is_a?(XML::Comment) end nodes end |
#on_type_test_node(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the node
type matcher. This matcher matches all node types.
573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/oga/xpath/evaluator.rb', line 573 def on_type_test_node(ast_node, context) nodes = XML::NodeSet.new context.each do |node| if node.is_a?(XML::Node) or node.is_a?(XML::Document) nodes << node end end nodes end |
#on_type_test_processing_instruction(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the processing-instruction()
type test. This matches only
processing-instruction nodes.
627 628 629 630 631 632 633 634 635 |
# File 'lib/oga/xpath/evaluator.rb', line 627 def on_type_test_processing_instruction(ast_node, context) nodes = XML::NodeSet.new context.each do |node| nodes << node if node.is_a?(XML::ProcessingInstruction) end nodes end |
#on_type_test_text(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes the text()
type test. This matches only text nodes.
592 593 594 595 596 597 598 599 600 |
# File 'lib/oga/xpath/evaluator.rb', line 592 def on_type_test_text(ast_node, context) nodes = XML::NodeSet.new context.each do |node| nodes << node if node.is_a?(XML::Text) end nodes end |
#on_var(ast_node, context) ⇒ Mixed
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes a variable reference. If the variable is not defined an error is raised.
1558 1559 1560 1561 1562 1563 1564 1565 1566 |
# File 'lib/oga/xpath/evaluator.rb', line 1558 def on_var(ast_node, context) name = ast_node.children[0] if @variables.key?(name) return @variables[name] else raise "Undefined XPath variable: #{name}" end end |
#parent_node(node) ⇒ Oga::XML::Node|Oga::XML::Document
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the parent node of node
, or node
itself if its a Document.
1793 1794 1795 |
# File 'lib/oga/xpath/evaluator.rb', line 1793 def parent_node(node) node.respond_to?(:parent) ? node.parent : node end |
#process(ast_node, context) ⇒ Oga::XML::NodeSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Processes an XPath node by dispatching it and the given context to a dedicated handler method. Handler methods are called "on_X" where "X" is the node type.
119 120 121 122 123 |
# File 'lib/oga/xpath/evaluator.rb', line 119 def process(ast_node, context) handler = "on_#{ast_node.type}" send(handler, ast_node, context) end |
#root_node(node) ⇒ Oga::XML::Node|Oga::XML::Document
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the root node of node
, or node
itself if its a Document.
1783 1784 1785 |
# File 'lib/oga/xpath/evaluator.rb', line 1783 def root_node(node) node.respond_to?(:root_node) ? node.root_node : node end |
#to_float(value) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Converts the given value to a float. If the value can't be converted to a float NaN is returned instead.
1727 1728 1729 |
# File 'lib/oga/xpath/evaluator.rb', line 1727 def to_float(value) return Float(value) rescue Float::NAN end |
#to_string(value) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Converts the given value to a string according to the XPath string conversion rules.
1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 |
# File 'lib/oga/xpath/evaluator.rb', line 1738 def to_string(value) # If we have a number that has a zero decimal (e.g. 10.0) we want to # get rid of that decimal. For this we'll first convert the number to # an integer. if value.is_a?(Float) and value.modulo(1).zero? value = value.to_i end value.to_s end |
#type_matches?(xml_node, ast_node) ⇒ TrueClass|FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
1678 1679 1680 1681 1682 |
# File 'lib/oga/xpath/evaluator.rb', line 1678 def type_matches?(xml_node, ast_node) context = XML::NodeSet.new([xml_node]) process(ast_node, context).length > 0 end |
#with_node_set(nodes) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Stores the specified node set and yields the supplied block. The return value of this method is whatever the block returned.
1760 1761 1762 1763 1764 1765 1766 1767 1768 |
# File 'lib/oga/xpath/evaluator.rb', line 1760 def with_node_set(nodes) @node_sets << nodes retval = yield @node_sets.pop retval end |