Method: REXML::QuickPath.predicate

Defined in:
lib/rexml/quickpath.rb

.predicate(elements, path) ⇒ Object

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 is equivalent to para.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# 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_}/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