Object
A class which provides filtering of children for Elements, and XPath
search support. You are expected to only encounter this class as the
element.elements
object. Therefore, you are not
expected to instantiate this yourself.
xml_string = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <bookstore> <book category="cooking"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="web"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <price>49.99</price> </book> <book category="web" cover="paperback"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore> EOT d = REXML::Document.new(xml_string) elements = d.root.elements elements # => #<REXML::Elements @element=<bookstore> ... </>>
Returns a new Elements object with the given parent
. Does
not assign parent.elements = self
:
d = REXML::Document.new(xml_string) eles = REXML::Elements.new(d.root) eles # => #<REXML::Elements @element=<bookstore> ... </>> eles == d.root.elements # => false
# File rexml-3.2.5/lib/rexml/element.rb, line 1608 def initialize parent @element = parent end
Returns the first Element object selected by the arguments, if any found,
or nil
if none found.
Notes:
The index
is 1-based, not 0-based, so that:
The first element has index 1
The nth element has index n
.
The selection ignores non-Element nodes.
When the single argument index
is given, returns the element
given by the index, if any; otherwise, nil
:
d = REXML::Document.new(xml_string) eles = d.root.elements eles # => #<REXML::Elements @element=<bookstore> ... </>> eles[1] # => <book category='cooking'> ... </> eles.size # => 4 eles[4] # => <book category='web' cover='paperback'> ... </> eles[5] # => nil
The node at this index is not an Element, and so is not returned:
eles = d.root.first.first # => <title lang='en'> ... </> eles.to_a # => ["Everyday Italian"] eles[1] # => nil
When the single argument xpath
is given, returns the first
element found via that xpath
, if any; otherwise,
nil
:
eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>> eles['/bookstore'] # => <bookstore> ... </> eles['//book'] # => <book category='cooking'> ... </> eles['//book [@category="children"]'] # => <book category='children'> ... </> eles['/nosuch'] # => nil eles['//nosuch'] # => nil eles['//book [@category="nosuch"]'] # => nil eles['.'] # => <bookstore> ... </> eles['..'].class # => REXML::Document
With arguments n
and name
given, returns the
nth found element that has the given name
, or
nil
if there is no such nth element:
eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>> eles[1, 'book'] # => <book category='cooking'> ... </> eles[4, 'book'] # => <book category='web' cover='paperback'> ... </> eles[5, 'book'] # => nil
# File rexml-3.2.5/lib/rexml/element.rb, line 1680 def []( index, name=nil) if index.kind_of? Integer raise "index (#{index}) must be >= 1" if index < 1 name = literalize(name) if name num = 0 @element.find { |child| child.kind_of? Element and (name.nil? ? true : child.has_name?( name )) and (num += 1) == index } else return XPath::first( @element, index ) #{ |element| # return element if element.kind_of? Element #} #return nil end end
Replaces or adds an element.
When eles[index]
exists, replaces it with
replacement_element
and returns
replacement_element
:
d = REXML::Document.new(xml_string) eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>> eles[1] # => <book category='cooking'> ... </> eles[1] = REXML::Element.new('foo') eles[1] # => <foo/>
Does nothing (or raises an exception) if replacement_element
is not an Element:
eles[2] # => <book category='web' cover='paperback'> ... </> eles[2] = REXML::Text.new('bar') eles[2] # => <book category='web' cover='paperback'> ... </>
When eles[index]
does not exist, adds
replacement_element
to the element and returns
d = REXML::Document.new(xml_string) eles = d.root.elements # => #<REXML::Elements @element=<bookstore> ... </>> eles.size # => 4 eles[50] = REXML::Element.new('foo') # => <foo/> eles.size # => 5 eles[5] # => <foo/>
Does nothing (or raises an exception) if replacement_element
is not an Element:
eles[50] = REXML::Text.new('bar') # => "bar" eles.size # => 5
# File rexml-3.2.5/lib/rexml/element.rb, line 1735 def []=( index, element ) previous = self[index] if previous.nil? @element.add element else previous.replace_with element end return previous end
Adds an element; returns the element added.
With no argument, creates and adds a new element. The new element has:
No name.
Parent from the Elements object.
Context from the that parent.
Example:
d = REXML::Document.new(xml_string) elements = d.root.elements parent = elements.parent # => <bookstore> ... </> parent.context = {raw: :all} elements.size # => 4 new_element = elements.add # => </> elements.size # => 5 new_element.name # => nil new_element.parent # => <bookstore> ... </> new_element.context # => {:raw=>:all}
With string argument name
, creates and adds a new element. The
new element has:
Name name
.
Parent from the Elements object.
Context from the that parent.
Example:
d = REXML::Document.new(xml_string) elements = d.root.elements parent = elements.parent # => <bookstore> ... </> parent.context = {raw: :all} elements.size # => 4 new_element = elements.add('foo') # => <foo/> elements.size # => 5 new_element.name # => "foo" new_element.parent # => <bookstore> ... </> new_element.context # => {:raw=>:all}
With argument element
, creates and adds a clone of the given
element
. The new element has name, parent, and context from
the given element
.
d = REXML::Document.new(xml_string) elements = d.root.elements elements.size # => 4 e0 = REXML::Element.new('foo') e1 = REXML::Element.new('bar', e0, {raw: :all}) element = elements.add(e1) # => <bar/> elements.size # => 5 element.name # => "bar" element.parent # => <bookstore> ... </> element.context # => {:raw=>:all}
# File rexml-3.2.5/lib/rexml/element.rb, line 1925 def add element=nil if element.nil? Element.new("", self, @element.context) elsif not element.kind_of?(Element) Element.new(element, self, @element.context) else @element << element element.context = @element.context element end end
Iterates over the elements; returns the array of block return values.
With no argument, iterates over all elements:
d = REXML::Document.new(xml_string) elements = d.root.elements elements.collect {|element| element.size } # => [9, 9, 17, 9]
With argument xpath
, iterates over elements that match the
given xpath
:
xpath = '//book [@category="web"]' elements.collect(xpath) {|element| element.size } # => [17, 9]
# File rexml-3.2.5/lib/rexml/element.rb, line 1988 def collect( xpath=nil ) collection = [] XPath::each( @element, xpath ) {|e| collection << yield(e) if e.kind_of?(Element) } collection end
Removes an element; returns the removed element, or nil
if
none removed.
With integer argument index
given, removes the child element
at that offset:
d = REXML::Document.new(xml_string) elements = d.root.elements elements.size # => 4 elements[2] # => <book category='children'> ... </> elements.delete(2) # => <book category='children'> ... </> elements.size # => 3 elements[2] # => <book category='web'> ... </> elements.delete(50) # => nil
With element argument element
given, removes that child
element:
d = REXML::Document.new(xml_string) elements = d.root.elements ele_1, ele_2, ele_3, ele_4 = *elements elements.size # => 4 elements[2] # => <book category='children'> ... </> elements.delete(ele_2) # => <book category='children'> ... </> elements.size # => 3 elements[2] # => <book category='web'> ... </> elements.delete(ele_2) # => nil
With string argument xpath
given, removes the first element
found via that xpath:
d = REXML::Document.new(xml_string) elements = d.root.elements elements.delete('//book') # => <book category='cooking'> ... </> elements.delete('//book [@category="children"]') # => <book category='children'> ... </> elements.delete('//nosuch') # => nil
# File rexml-3.2.5/lib/rexml/element.rb, line 1825 def delete element if element.kind_of? Element @element.delete element else el = self[element] el.remove if el end end
Removes all elements found via the given xpath
; returns the
array of removed elements, if any, else nil
.
d = REXML::Document.new(xml_string) elements = d.root.elements elements.size # => 4 deleted_elements = elements.delete_all('//book [@category="web"]') deleted_elements.size # => 2 elements.size # => 2 deleted_elements = elements.delete_all('//book') deleted_elements.size # => 2 elements.size # => 0 elements.delete_all('//book') # => []
# File rexml-3.2.5/lib/rexml/element.rb, line 1851 def delete_all( xpath ) rv = [] XPath::each( @element, xpath) {|element| rv << element if element.kind_of? Element } rv.each do |element| @element.delete element element.remove end return rv end
Iterates over the elements.
With no argument, calls the block with each element:
d = REXML::Document.new(xml_string) elements = d.root.elements elements.each {|element| p element }
Output:
<book category='cooking'> ... </> <book category='children'> ... </> <book category='web'> ... </> <book category='web' cover='paperback'> ... </>
With argument xpath
, calls the block with each element that
matches the given xpath
:
elements.each('//book [@category="web"]') {|element| p element }
Output:
<book category='web'> ... </> <book category='web' cover='paperback'> ... </>
# File rexml-3.2.5/lib/rexml/element.rb, line 1967 def each( xpath=nil ) XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } end
Returns true
if there are no children, false
otherwise.
d = REXML::Document.new('') d.elements.empty? # => true d = REXML::Document.new(xml_string) d.elements.empty? # => false
# File rexml-3.2.5/lib/rexml/element.rb, line 1755 def empty? @element.find{ |child| child.kind_of? Element}.nil? end
Returns the 1-based index of the given element
, if found;
otherwise, returns -1:
d = REXML::Document.new(xml_string) elements = d.root.elements ele_1, ele_2, ele_3, ele_4 = *elements elements.index(ele_4) # => 4 elements.delete(ele_3) elements.index(ele_4) # => 3 elements.index(ele_3) # => -1
# File rexml-3.2.5/lib/rexml/element.rb, line 1773 def index element rv = 0 found = @element.find do |child| child.kind_of? Element and (rv += 1) and child == element end return rv if found == element return -1 end
Calls the block with elements; returns the last block return value.
With no argument, iterates over the elements, calling the block
elements.size - 1
times.
The first call passes the first and second elements.
The second call passes the first block return value and the third element.
The third call passes the second block return value and the fourth element.
And so on.
In this example, the block returns the passed element, which is then the object argument to the next call:
d = REXML::Document.new(xml_string) elements = d.root.elements elements.inject do |object, element| p [elements.index(object), elements.index(element)] element end
Output:
[1, 2] [2, 3] [3, 4]
With the single argument xpath
, calls the block only with
elements matching that xpath:
elements.inject('//book [@category="web"]') do |object, element| p [elements.index(object), elements.index(element)] element end
Output:
[3, 4]
With argument xpath
given as nil
and argument
initial
also given, calls the block once for each element.
The first call passes the initial
and the first element.
The second call passes the first block return value and the second element.
The third call passes the second block return value and the third element.
And so on.
In this example, the first object index is -1
elements.inject(nil, 'Initial') do |object, element| p [elements.index(object), elements.index(element)] element end
Output:
[-1, 1] [1, 2] [2, 3] [3, 4]
In this form the passed object can be used as an accumulator:
elements.inject(nil, 0) do |total, element| total += element.size end # => 44
With both arguments xpath
and initial
are given,
calls the block only with elements matching that xpath:
elements.inject('//book [@category="web"]', 0) do |total, element| total += element.size end # => 26
# File rexml-3.2.5/lib/rexml/element.rb, line 2073 def inject( xpath=nil, initial=nil ) first = true XPath::each( @element, xpath ) {|e| if (e.kind_of? Element) if (first and initial == nil) initial = e first = false else initial = yield( initial, e ) if e.kind_of? Element end end } initial end
Returns the parent element cited in creating the Elements object. This element is also the default starting point for searching in the Elements object.
d = REXML::Document.new(xml_string) elements = REXML::Elements.new(d.root) elements.parent == d.root # => true
# File rexml-3.2.5/lib/rexml/element.rb, line 1623 def parent @element end
Returns the count of Element children:
d = REXML::Document.new '<a>sean<b/>elliott<b/>russell<b/></a>' d.root.elements.size # => 3 # Three elements. d.root.size # => 6 # Three elements plus three text nodes..
# File rexml-3.2.5/lib/rexml/element.rb, line 2097 def size count = 0 @element.each {|child| count+=1 if child.kind_of? Element } count end
Returns an array of element children (not including non-element children).
With no argument, returns an array of all element children:
d = REXML::Document.new '<a>sean<b/>elliott<c/></a>' elements = d.root.elements elements.to_a # => [<b/>, <c/>] # Omits non-element children. children = d.root.children children # => ["sean", <b/>, "elliott", <c/>] # Includes non-element children.
With argument xpath
, returns an array of element children that
match the xpath:
elements.to_a('//c') # => [<c/>]
# File rexml-3.2.5/lib/rexml/element.rb, line 2121 def to_a( xpath=nil ) rv = XPath.match( @element, xpath ) return rv.find_all{|e| e.kind_of? Element} if xpath rv end