Class: REXML::Elements
- Inherits:
-
Object
- Object
- REXML::Elements
- Includes:
- Enumerable
- Defined in:
- lib/rexml/element.rb
Overview
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> ... </>>
Instance Method Summary collapse
- #[](index, name = nil) ⇒ Object
-
#[]=(index, element) ⇒ Object
:call-seq: elements[] = index, replacement_element -> replacement_element or nil.
-
#add(element = nil) ⇒ Object
(also: #<<)
:call-seq: add -> new_element add(name) -> new_element add(element) -> element.
-
#collect(xpath = nil) ⇒ Object
:call-seq: collect(xpath = nil) {|element| … } -> array.
-
#delete(element) ⇒ Object
:call-seq: delete(index) -> removed_element or nil delete(element) -> removed_element or nil delete(xpath) -> removed_element or nil.
-
#delete_all(xpath) ⇒ Object
:call-seq: delete_all(xpath).
-
#each(xpath = nil) ⇒ Object
:call-seq: each(xpath = nil) {|element| … } -> self.
-
#empty? ⇒ Boolean
:call-seq: empty? -> true or false.
-
#index(element) ⇒ Object
:call-seq: index(element).
-
#initialize(parent) ⇒ Elements
constructor
:call-seq: new(parent) -> new_elements_object.
-
#inject(xpath = nil, initial = nil) ⇒ Object
:call-seq: inject(xpath = nil, initial = nil) -> object.
-
#parent ⇒ Object
:call-seq: parent.
-
#size ⇒ Object
:call-seq: size -> integer.
-
#to_a(xpath = nil) ⇒ Object
:call-seq: to_a(xpath = nil) -> array_of_elements.
Constructor Details
#initialize(parent) ⇒ Elements
:call-seq:
new(parent) -> new_elements_object
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
1604 1605 1606 |
# File 'lib/rexml/element.rb', line 1604 def initialize parent @element = parent end |
Instance Method Details
#[](index, name = nil) ⇒ Object
:call-seq:
elements[index] -> element or nil
elements[xpath] -> element or nil
elements[n, name] -> element or nil
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
1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 |
# File 'lib/rexml/element.rb', line 1676 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 |
#[]=(index, element) ⇒ Object
:call-seq:
elements[] = index, replacement_element -> replacement_element or nil
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
1731 1732 1733 1734 1735 1736 1737 1738 1739 |
# File 'lib/rexml/element.rb', line 1731 def []=( index, element ) previous = self[index] if previous.nil? @element.add element else previous.replace_with element end return previous end |
#add(element = nil) ⇒ Object Also known as: <<
:call-seq:
add -> new_element
add(name) -> new_element
add(element) -> element
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}
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 |
# File 'lib/rexml/element.rb', line 1921 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 |
#collect(xpath = nil) ⇒ Object
:call-seq:
collect(xpath = nil) {|element| ... } -> array
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]
1984 1985 1986 1987 1988 1989 1990 |
# File 'lib/rexml/element.rb', line 1984 def collect( xpath=nil ) collection = [] XPath::each( @element, xpath ) {|e| collection << yield(e) if e.kind_of?(Element) } collection end |
#delete(element) ⇒ Object
:call-seq:
delete(index) -> removed_element or nil
delete(element) -> removed_element or nil
delete(xpath) -> removed_element or nil
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
1821 1822 1823 1824 1825 1826 1827 1828 |
# File 'lib/rexml/element.rb', line 1821 def delete element if element.kind_of? Element @element.delete element else el = self[element] el.remove if el end end |
#delete_all(xpath) ⇒ Object
:call-seq:
delete_all(xpath)
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') # => []
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 |
# File 'lib/rexml/element.rb', line 1847 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 |
#each(xpath = nil) ⇒ Object
:call-seq:
each(xpath = nil) {|element| ... } -> self
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'> ... </>
1963 1964 1965 |
# File 'lib/rexml/element.rb', line 1963 def each( xpath=nil ) XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } end |
#empty? ⇒ Boolean
1751 1752 1753 |
# File 'lib/rexml/element.rb', line 1751 def empty? @element.find{ |child| child.kind_of? Element}.nil? end |
#index(element) ⇒ Object
:call-seq:
index(element)
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
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 |
# File 'lib/rexml/element.rb', line 1769 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 |
#inject(xpath = nil, initial = nil) ⇒ Object
:call-seq:
inject(xpath = nil, initial = nil) -> object
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
2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 |
# File 'lib/rexml/element.rb', line 2069 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 |
#parent ⇒ Object
1619 1620 1621 |
# File 'lib/rexml/element.rb', line 1619 def parent @element end |
#size ⇒ Object
2093 2094 2095 2096 2097 |
# File 'lib/rexml/element.rb', line 2093 def size count = 0 @element.each {|child| count+=1 if child.kind_of? Element } count end |
#to_a(xpath = nil) ⇒ Object
:call-seq:
to_a(xpath = nil) -> array_of_elements
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/>]
2117 2118 2119 2120 2121 |
# File 'lib/rexml/element.rb', line 2117 def to_a( xpath=nil ) rv = XPath.match( @element, xpath ) return rv.find_all{|e| e.kind_of? Element} if xpath rv end |