A predicate filters a
node-set with respect to an axis to produce a new node-set. For each node in the node-set to be
filtered, the PredicateExpr is evaluated with that node as the context
node, with the number of nodes in the node-set as the context size, and
with the proximity position of the node in the node-set with respect to the
axis as the context position; if PredicateExpr evaluates to true for that
node, the node is included in the new node-set; otherwise, it is not
included.
A PredicateExpr is evaluated by evaluating the Expr and converting the
result to a boolean. If the result is a number, the result will be
converted to true if the number is equal to the context position and will
be converted to false otherwise; if the result is not a number, then the
result will be converted as if by a call to the boolean function. Thus a location
path para[3] is equivalent to para[position()=3].
# File lib/rexml/quickpath.rb, line 161
def QuickPath::predicate( elements, path )
ind = 1
bcount = 1
while bcount > 0
bcount += 1 if path[ind] == [[
bcount -= 1 if path[ind] == ]]
ind += 1
end
ind -= 1
predicate = path[1..ind-1]
rest = path[ind+1..-1]
# have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
#
predicate.gsub!(
/#{OPERAND_}\s*([<>=])\s*#{OPERAND_}\s*([<>=])\s*#{OPERAND_}/,
'\1 \2 \3 and \3 \4 \5' )
# Let's do some Ruby trickery to avoid some work:
predicate.gsub!( /&/, "&&" )
predicate.gsub!( /=/, "==" )
predicate.gsub!( /@(\w[-\w.]*)/, 'attribute("\1")' )
predicate.gsub!( /\bmod\b/, "%" )
predicate.gsub!( /\b(\w[-\w.]*\()/ ) {
fname = $1
fname.gsub( /-/, "_" )
}
Functions.pair = [ 0, elements.size ]
results = []
elements.each do |element|
Functions.pair[0] += 1
Functions.node = element
res = eval( predicate )
case res
when true
results << element
when Integer
results << element if Functions.pair[0] == res
when String
results << element
end
end
return filter( results, rest )
end