Class: XML::XXPath

Inherits:
Object
  • Object
show all
Defined in:
lib/xml/xxpath.rb,
lib/xml/rexml_ext.rb,
lib/xml/xxpath/steps.rb

Overview

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.

Defined Under Namespace

Modules: Accessors Classes: AllElementsStep, AlternativeNamesStep, AttrNameStep, AttrStep, NameAndAttrStep, NameAndIndexStep, NameStep, Step, TextNodesStep, ThisNodeStep

Instance Method Summary collapse

Constructor Details

#initialize(xpathstr) ⇒ XXPath

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



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 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

Instance Method Details

#all(node, options = {}) ⇒ Object

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.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 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) ⇒ Object

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).



111
112
113
# File 'lib/xml/xxpath.rb', line 111

def create_new(base_node)
  first(base_node,:create_new=>true)
end

#each(node, options = {}, &block) ⇒ Object

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



57
58
59
# File 'lib/xml/xxpath.rb', line 57

def each(node,options={},&block)
  all(node,options).each(&block)
end

#first(node, options = {}) ⇒ Object

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).



69
70
71
72
73
74
75
76
77
78
79
80
# 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