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
1608 1609 1610 |
# File 'lib/rexml/element.rb', line 1608 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
1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 |
# File '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 |
#[]=(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
1735 1736 1737 1738 1739 1740 1741 1742 1743 |
# File '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 |
#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}
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 |
# File '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 |
#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]
1988 1989 1990 1991 1992 1993 1994 |
# File '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 |
#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
1825 1826 1827 1828 1829 1830 1831 1832 |
# File '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 |
#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') # => []
1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 |
# File '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 |
#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'> ... </>
1967 1968 1969 |
# File 'lib/rexml/element.rb', line 1967 def each( xpath=nil ) XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } end |
#empty? ⇒ Boolean
1755 1756 1757 |
# File 'lib/rexml/element.rb', line 1755 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
1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 |
# File '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 |
#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
2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 |
# File '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 |
#parent ⇒ Object
1623 1624 1625 |
# File 'lib/rexml/element.rb', line 1623 def parent @element end |
#size ⇒ Object
2097 2098 2099 2100 2101 |
# File 'lib/rexml/element.rb', line 2097 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/>]
2121 2122 2123 2124 2125 |
# File '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 |