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 160
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!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u ) {
"#$1 #$2 #$3 and #$3 #$4 #$5"
}
# Let's do some Ruby trickery to avoid some work:
predicate.gsub!( /&/u, "&&" )
predicate.gsub!( /=/u, "==" )
predicate.gsub!( /@(\w[-\w.]*)/u ) {
"attribute(\"#$1\")"
}
predicate.gsub!( /\bmod\b/u, "%" )
predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
fname = $1
fname.gsub( /-/u, "_" )
}
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 Fixnum
results << element if Functions.pair[0] == res
when String
results << element
end
end
return filter( results, rest )
end