class XPath::XPathNodeSet

Constants

IteratorForAxis

Attributes

nodes[R]

Public Class Methods

def_comparison_operator(*ops) click to toggle source
# File lib/xml/xpath.rb, line 2778
    def self.def_comparison_operator(*ops)
      ops.each { |op|
        module_eval <<_, __FILE__, __LINE__ + 1
        def #{op}(other)
          if other.is_a? XPathBoolean then
            other #{op} self.to_boolean
          else
            visitor = @visitor
            str = @context.make_string('')
            ret = false
            @nodes.each { |node|
              str.replace visitor.visit(node).string_value
              break if ret = (other #{op} str)
            }
            ret
          end
        end
_
      }
    end
new(context, *nodes) click to toggle source
# File lib/xml/xpath.rb, line 2746
def initialize(context, *nodes)
  @context = context.dup
  @visitor = context.visitor
  nodes.sort! { |a,b| compare_position a, b }
  @nodes = nodes
end

Public Instance Methods

**(other) click to toggle source
Calls superclass method XPath::XPathObject#**
# File lib/xml/xpath.rb, line 2805
def **(other)
  super unless other.is_a? XPathNodeSet
  merge other.nodes
  self
end
at(pos) click to toggle source
# File lib/xml/xpath.rb, line 2997
def at(pos)
  n = pos.to_i
  if n != pos or n <= 0 then
    node = nil
  else
    node = @nodes[n - 1]
  end
  @nodes.clear
  @nodes.push node if node
  self
end
count() click to toggle source
# File lib/xml/xpath.rb, line 2812
def count
  @nodes.size
end
each(&block) click to toggle source
# File lib/xml/xpath.rb, line 2820
def each(&block)
  @nodes.each(&block)
end
first() click to toggle source
# File lib/xml/xpath.rb, line 2816
def first
  @nodes[0]
end
funcall(name) { |c| ... } click to toggle source
Calls superclass method XPath::XPathObject#funcall
# File lib/xml/xpath.rb, line 2825
def funcall(name)   # for XPointer
  raise "BUG" unless block_given?
  func = ('f_' + name.tr('-', '_')).intern
  super unless respond_to? func, true
  size = @nodes.size
  pos = 1
  c = @context.dup
  begin
    @nodes.collect! { |node|
      c.reuse node, pos, size
      pos += 1
      args = yield(c)
      send(func, node, *args)
    }
  rescue Object::ArgumentError
    if $@[1] == "#{__FILE__}:#{__LINE__-3}:in `send'" then
      raise XPath::ArgumentError, "#{$!} for `#{name}'"
    end
    raise
  end
  self
end
predicate() { |context| ... } click to toggle source
# File lib/xml/xpath.rb, line 2976
def predicate
  context = @context
  size = @nodes.size
  pos = 1
  result = nil
  newnodes = @nodes.reject { |node|
    context.reuse node, pos, size
    pos += 1
    result = yield(context)
    break if result.is_a? Numeric
    not result
  }
  if result.is_a? Numeric then
    at result
  else
    @nodes = newnodes
  end
  self
end
select_all(axis) click to toggle source
# File lib/xml/xpath.rb, line 2961
def select_all(axis)
  iterator = get_iterator(axis)
  visitor = @visitor
  oldnodes = @nodes
  @nodes = []
  oldnodes.each { |start|
    nodes = []
    iterator.each(start, visitor) { |i| nodes.push i.node }
    nodes.reverse! if iterator.reverse_order?
    merge nodes
  }
  self
end
step(axis) { |lstep| ... } click to toggle source
# File lib/xml/xpath.rb, line 2945
def step(axis)
  iterator = get_iterator(axis)
  lstep = make_location_step
  lstep.set_iterator iterator
  oldnodes = @nodes
  @nodes = []
  oldnodes.each { |node|
    lstep.reuse node
    nodes = yield(lstep).nodes
    nodes.reverse! if iterator.reverse_order?
    merge nodes
  }
  self
end
to_f() click to toggle source
# File lib/xml/xpath.rb, line 2765
def to_f
  to_string(@context).to_f
end
to_ruby() click to toggle source
# File lib/xml/xpath.rb, line 2773
def to_ruby
  @nodes
end
to_str() click to toggle source
# File lib/xml/xpath.rb, line 2757
def to_str
  if @nodes.empty? then
    ''
  else
    @visitor.visit(@nodes[0]).string_value
  end
end
true?() click to toggle source
# File lib/xml/xpath.rb, line 2769
def true?
  not @nodes.empty?
end

Private Instance Methods

compare_position(node1, node2) click to toggle source
# File lib/xml/xpath.rb, line 2851
def compare_position(node1, node2)
  visitor = @visitor
  ancestors1 = []
  ancestors2 = []
  p1 = visitor.visit(node1).parent
  while p1
    ancestors1.push node1
    p1 = visitor.visit(node1 = p1).parent
  end
  p2 = visitor.visit(node2).parent
  while p2
    ancestors2.push node2
    p2 = visitor.visit(node2 = p2).parent
  end
  unless node1 == node2 then
    raise XPath::Error, "can't compare the positions of given two nodes"
  end
  n = -1
  ancestors1.reverse_each { |node1|
    node2 = ancestors2[n]
    unless node1 == node2 then
      break unless node2
      return visitor.visit(node1).index - visitor.visit(node2).index
    end
    n -= 1
  }
  ancestors1.size - ancestors2.size
end
get_iterator(axis) click to toggle source
# File lib/xml/xpath.rb, line 2926
def get_iterator(axis)
  ret = IteratorForAxis[axis]
  unless ret then
    raise XPath::NameError, "invalid axis `#{axis.id2name.tr('_','-')}'"
  end
  ret
end
make_location_step() click to toggle source
# File lib/xml/xpath.rb, line 2934
def make_location_step
  if defined? @__lstep__ then
    @__lstep__
  else
    @__lstep__ = LocationStep.new(@context)
  end
end
merge(other) click to toggle source
# File lib/xml/xpath.rb, line 2881
def merge(other)
  if @nodes.empty? or other.empty? then
    @nodes.concat other
  elsif (n = compare_position(@nodes.last, other.first)) <= 0 then
    @nodes.pop if n == 0
    @nodes.concat other
  elsif (n = compare_position(other.last, @nodes.first)) <= 0 then
    other.pop if n == 0
    @nodes = other.concat(@nodes)
  else
    newnodes = []
    nodes = @nodes
    until nodes.empty? or other.empty?
      n = compare_position(nodes.last, other.last)
      if n > 0 then
        newnodes.push nodes.pop
      elsif n < 0 then
        newnodes.push other.pop
      else
        newnodes.push nodes.pop
        other.pop
      end
    end
    newnodes.reverse!
    @nodes.concat(other).concat(newnodes)
  end
end