class XML::XXPath

Instances of this class hold (in a pre-compiled form) an XPath pattern. You call instance methods like each, first, all, create_new on instances of this class to apply the pattern to REXML elements.

Public Class Methods

new(xpathstr) click to toggle source

create and compile a new XPath. xpathstr is the string representation (XPath pattern) of the path

# File lib/xml/xxpath.rb, line 21
def initialize(xpathstr)
  @xpathstr = xpathstr  # for error messages

  # TODO: write a real XPath parser sometime

  xpathstr='/'+xpathstr if xpathstr[0] != ?/

  @creator_procs = [ proc{|node,create_new| node} ]
  @reader_proc = proc {|nodes| nodes}
  
  part=nil; part_expected=true
  xpathstr.split(/(\/+)/)[1..-1].reverse.each do |x|
    if part_expected
      part=x
      part_expected = false
      next
    end
    part_expected = true
    axis = case x
           when '/'
             :child
           when '//'
             :descendant
           else
             raise XXPathError, "XPath (#{xpathstr}): unknown axis: #{x}"
           end
    axis=:self if axis==:child and (part[0]==?. or part=~/^self::/)  # yuck

    step = Step.compile(axis,part)
    @creator_procs << step.creator(@creator_procs[-1])
    @reader_proc = step.reader(@reader_proc, @creator_procs[-1])
  end
end

Public Instance Methods

all(node,options={}) click to toggle source

Return an Enumerable with all sub-nodes of node that match this XPath. Returns an empty Enumerable if no match was found.

If :ensure_created=>true is provided, all() ensures that a match exists in node, creating one (and returning it as the sole element of the returned enumerable) if none existed before.

# File lib/xml/xxpath.rb, line 88
def all(node,options={})
  raise "options not a hash" unless Hash===options
  if options[:create_new]
    return [ @creator_procs[-1].call(node,true) ]
  else
    last_nodes,rest_creator = catch(:not_found) do
      return @reader_proc.call([node])
    end
    if options[:ensure_created]
      [ rest_creator.call(last_nodes[0],false) ]
    else
      []
    end
  end
end
create_new(base_node) click to toggle source

create a completely new match of this XPath in base_node. “Completely new” means that a new node will be created for each path element, even if a matching node already existed in base_node.

path.create_new(node) is equivalent to path.first(node,:create_new=>true).

# File lib/xml/xxpath.rb, line 111
def create_new(base_node)
  first(base_node,:create_new=>true)
end
each(node,options={},&block) click to toggle source

loop over all sub-nodes of node that match this XPath.

# File lib/xml/xxpath.rb, line 57
def each(node,options={},&block)
  all(node,options).each(&block)
end
first(node,options={}) click to toggle source

the first sub-node of node that matches this XPath. If nothing matches, raise XXPathError unless :allow_nil=>true was provided.

If :ensure_created=>true is provided, first() ensures that a match exists in node, creating one if none existed before.

path.first(node,:create_new=>true) is equivalent to path.create_new(node).

# File lib/xml/xxpath.rb, line 69
def first(node,options={})
  a=all(node,options)
  if a.empty?
    if options[:allow_nil]
      nil
    else
      raise XXPathError, "path not found: #{@xpathstr}"
    end
  else
    a[0]
  end
end