In Files

  • rexml/quickpath.rb

Class/Module Index [+]

Quicksearch

REXML::QuickPath

Constants

EMPTY_HASH

Public Class Methods

attribute( name ) click to toggle source
 
               # File rexml/quickpath.rb, line 203
def QuickPath::attribute( name )
  return Functions.node.attributes[name] if Functions.node.kind_of? Element
end
            
axe( elements, axe_name, rest ) click to toggle source
 
               # File rexml/quickpath.rb, line 106
def QuickPath::axe( elements, axe_name, rest )
  matches = []
  matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
  case axe_name
  when /^descendant/u
    elements.each do |element|
      matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
    end
  when /^ancestor/u
    elements.each do |element|
      while element.parent
        matches << element.parent
        element = element.parent
      end
    end
    matches = filter( matches, rest )
  when "self"
    matches = filter( elements, rest )
  when "child"
    elements.each do |element|
      matches |= filter( element.to_a, rest ) if element.kind_of? Element
    end
  when "attribute"
    elements.each do |element|
      matches << element.attributes[ rest ] if element.kind_of? Element
    end
  when "parent"
    matches = filter(elements.collect{|element| element.parent}.uniq, rest)
  when "following-sibling"
    matches = filter(elements.collect{|element| element.next_sibling}.uniq,
      rest)
  when "previous-sibling"
    matches = filter(elements.collect{|element| 
      element.previous_sibling}.uniq, rest )
  end
  return matches.uniq
end
            
each(element, path, namespaces=EMPTY_HASH, &block) click to toggle source
 
               # File rexml/quickpath.rb, line 15
def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
  path = "*" unless path
  match(element, path, namespaces).each( &block )
end
            
filter(elements, path) click to toggle source

Given an array of nodes it filters the array based on the path. The result is that when this method returns, the array will contain elements which match the path

 
               # File rexml/quickpath.rb, line 48
def QuickPath::filter elements, path
  return elements if path.nil? or path == '' or elements.size == 0
  case path
  when /^\/\//u                                                                                     # Descendant
    return axe( elements, "descendant-or-self", $' )
  when /^\/?\b(\w[-\w]*)\b::/u                                                      # Axe
    axe_name = $1
    rest = $'
    return axe( elements, $1, $' )
  when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u      # Child
    rest = $'
    results = []
    elements.each do |element|
      results |= filter( element.to_a, rest )
    end
    return results
  when /^\/?(\w[-\w]*)\(/u                                                  # / Function
    return function( elements, $1, $' )
  when Namespace::NAMESPLIT         # Element name
    name = $2
    ns = $1
    rest = $'
    elements.delete_if do |element|
      !(element.kind_of? Element and 
        (element.expanded_name == name or
         (element.name == name and
          element.namespace == Functions.namespace_context[ns])))
    end
    return filter( elements, rest )
  when /^\/\[/u
    matches = []
    elements.each do |element|
      matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
    end
    return matches
  when /^\[/u                                                                                               # Predicate
    return predicate( elements, path )
  when /^\/?\.\.\./u                                                                                # Ancestor
    return axe( elements, "ancestor", $' )
  when /^\/?\.\./u                                                                                  # Parent
    return filter( elements.collect{|e|e.parent}, $' )
  when /^\/?\./u                                                                                            # Self
    return filter( elements, $' )
  when /^\*/u                                                                                                       # Any
    results = []
    elements.each do |element|
      results |= filter( [element], $' ) if element.kind_of? Element
      #if element.kind_of? Element
      #     children = element.to_a
      #     children.delete_if { |child| !child.kind_of?(Element) }
      #     results |= filter( children, $' )
      #end
    end
    return results
  end
  return []
end
            
first(element, path, namespaces=EMPTY_HASH) click to toggle source
 
               # File rexml/quickpath.rb, line 11
def QuickPath::first element, path, namespaces=EMPTY_HASH
  match(element, path, namespaces)[0]
end
            
function( elements, fname, rest ) click to toggle source
 
               # File rexml/quickpath.rb, line 219
def QuickPath::function( elements, fname, rest )
  args = parse_args( elements, rest )
  Functions.pair = [0, elements.size]
  results = []
  elements.each do |element|
    Functions.pair[0] += 1
    Functions.node = element
    res = Functions.send( fname, *args )
    case res
    when true
      results << element
    when Fixnum
      results << element if Functions.pair[0] == res
    end
  end
  return results
end
            
match(element, path, namespaces=EMPTY_HASH) click to toggle source
 
               # File rexml/quickpath.rb, line 20
def QuickPath::match element, path, namespaces=EMPTY_HASH
  raise "nil is not a valid xpath" unless path
  results = nil
  Functions::namespace_context = namespaces
  case path
  when /^\/([^\/]|$)/u
    # match on root
    path = path[1..-1]
    return [element.root.parent] if path == ''
    results = filter([element.root], path)
  when /^[-\w]*::/u
    results = filter([element], path)
  when /^\*/u
    results = filter(element.to_a, path)
  when /^[\[!\w:]/u
    # match on child
    matches = []
    children = element.to_a
    results = filter(children, path)
  else
    results = filter([element], path)
  end
  return results
end
            
method_missing( id, *args ) click to toggle source
 
               # File rexml/quickpath.rb, line 211
def QuickPath::method_missing( id, *args )
  begin
    Functions.send( id.id2name, *args )
  rescue Exception
    raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
  end
end
            
name() click to toggle source
 
               # File rexml/quickpath.rb, line 207
def QuickPath::name()
  return Functions.node.name if Functions.node.kind_of? Element
end
            
parse_args( element, string ) click to toggle source
 
               # File rexml/quickpath.rb, line 237
def QuickPath::parse_args( element, string )
  # /.*?(?:\)|,)/
  arguments = []
  buffer = ""
  while string and string != ""
    c = string[0]
    string.sub!(/^./u, "")
    case c
    when ?,
      # if depth = 1, then we start a new argument
      arguments << evaluate( buffer )
      #arguments << evaluate( string[0..count] )
    when ?(
      # start a new method call
      function( element, buffer, string )
      buffer = ""
    when ?)
      # close the method call and return arguments
      return arguments
    else
      buffer << c
    end
  end
  ""
end
            
predicate( elements, path ) click to toggle source

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.

 
               # File 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