Class: REXML::Element

Inherits:
Parent show all
Includes:
Namespace
Defined in:
lib/rexml/element.rb

Overview

An REXML::Element object represents an XML element.

An element:

  • Has a name (string).

  • May have a parent (another element).

  • Has zero or more children (other elements, text, CDATA, processing instructions, and comments).

  • Has zero or more siblings (other elements, text, CDATA, processing instructions, and comments).

  • Has zero or more named attributes.

In a Hurry?

If you’re somewhat familiar with XML and have a particular task in mind, you may want to see the tasks pages, and in particular, the tasks page for elements.

Name

An element has a name, which is initially set when the element is created:

e = REXML::Element.new('foo')
e.name # => "foo"

The name may be changed:

e.name = 'bar'
e.name # => "bar"

Parent

An element may have a parent.

Its parent may be assigned explicitly when the element is created:

e0 = REXML::Element.new('foo')
e1 = REXML::Element.new('bar', e0)
e1.parent # => <foo> ... </>

Note: the representation of an element always shows the element’s name. If the element has children, the representation indicates that by including an ellipsis (...).

The parent may be assigned explicitly at any time:

e2 = REXML::Element.new('baz')
e1.parent = e2
e1.parent # => <baz/>

When an element is added as a child, its parent is set automatically:

e1.add_element(e0)
e0.parent # => <bar> ... </>

For an element that has no parent, method parent returns nil.

Children

An element has zero or more children. The children are an ordered collection of all objects whose parent is the element itself.

The children may include any combination of elements, text, comments, processing instructions, and CDATA. (This example keeps things clean by controlling whitespace via a context setting.)

xml_string = <<-EOT
<root>
  <ele_0/>
  text 0
  <!--comment 0-->
  <?target_0 pi_0?>
  <![CDATA[cdata 0]]>
  <ele_1/>
  text 1
  <!--comment 1-->
  <?target_0 pi_1?>
  <![CDATA[cdata 1]]>
</root>
EOT
context = {ignore_whitespace_nodes: :all, compress_whitespace: :all}
d = REXML::Document.new(xml_string, context)
root = d.root
root.children.size # => 10
root.each {|child| p "#{child.class}: #{child}" }

Output:

"REXML::Element: <ele_0/>"
"REXML::Text: \n text 0\n "
"REXML::Comment: comment 0"
"REXML::Instruction: <?target_0 pi_0?>"
"REXML::CData: cdata 0"
"REXML::Element: <ele_1/>"
"REXML::Text: \n text 1\n "
"REXML::Comment: comment 1"
"REXML::Instruction: <?target_0 pi_1?>"
"REXML::CData: cdata 1"

A child may be added using inherited methods Parent#insert_before or Parent#insert_after:

xml_string = '<root><a/><c/><d/></root>'
d = REXML::Document.new(xml_string)
root = d.root
c = d.root[1] # => <c/>
root.insert_before(c, REXML::Element.new('b'))
root.to_a # => [<a/>, <b/>, <c/>, <d/>]

A child may be replaced using Parent#replace_child:

root.replace_child(c, REXML::Element.new('x'))
root.to_a # => [<a/>, <b/>, <x/>, <d/>]

A child may be removed using Parent#delete:

x = root[2] # => <x/>
root.delete(x)
root.to_a # => [<a/>, <b/>, <d/>]

Siblings

An element has zero or more siblings, which are the other children of the element’s parent.

In the example above, element ele_1 is between a CDATA sibling and a text sibling:

ele_1 = root[5]        # => <ele_1/>
ele_1.previous_sibling # => "cdata 0"
ele_1.next_sibling     # => "\n text 1\n "

Attributes

An element has zero or more named attributes.

A new element has no attributes:

e = REXML::Element.new('foo')
e.attributes      # => {}

Attributes may be added:

e.add_attribute('bar', 'baz')
e.add_attribute('bat', 'bam')
e.attributes.size # => 2
e['bar']          # => "baz"
e['bat']          # => "bam"

An existing attribute may be modified:

e.add_attribute('bar', 'bad')
e.attributes.size # => 2
e['bar']          # => "bad"

An existing attribute may be deleted:

e.delete_attribute('bar')
e.attributes.size # => 1
e['bar']          # => nil

What’s Here

To begin with, what’s elsewhere?

Class REXML::Element inherits from its ancestor classes:

  • REXML::Child

  • REXML::Parent

REXML::Element itself and its ancestors also include modules:

  • Enumerable

  • REXML::Namespace

  • REXML::Node

  • REXML::XMLTokens

Methods for Creating an Element

::new

Returns a new empty element.

#clone

Returns a clone of another element.

Methods for Attributes

[attribute_name]

Returns an attribute value.

#add_attribute

Adds a new attribute.

#add_attributes

Adds multiple new attributes.

#attribute

Returns the attribute value for a given name and optional namespace.

#delete_attribute

Removes an attribute.

Methods for Children

[index]

Returns the child at the given offset.

#add_element

Adds an element as the last child.

#delete_element

Deletes a child element.

#each_element

Calls the given block with each child element.

#each_element_with_attribute

Calls the given block with each child element that meets given criteria, which can include the attribute name.

#each_element_with_text

Calls the given block with each child element that meets given criteria, which can include text.

#get_elements

Returns an array of element children that match a given xpath.

Methods for Text Children

#add_text

Adds a text node to the element.

#get_text

Returns a text node that meets specified criteria.

#text

Returns the text string from the first node that meets specified criteria.

#texts

Returns an array of the text children of the element.

#text=

Adds, removes, or replaces the first text child of the element

Methods for Other Children

#cdatas

Returns an array of the cdata children of the element.

#comments

Returns an array of the comment children of the element.

#instructions

Returns an array of the instruction children of the element.

Methods for Namespaces

#add_namespace

Adds a namespace to the element.

#delete_namespace

Removes a namespace from the element.

#namespace

Returns the string namespace URI for the element.

#namespaces

Returns a hash of all defined namespaces in the element.

#prefixes

Returns an array of the string prefixes (names) of all defined namespaces in the element

Methods for Querying

#document

Returns the document, if any, that the element belongs to.

#root

Returns the most distant element (not document) ancestor of the element.

#root_node

Returns the most distant ancestor of the element.

#xpath

Returns the string xpath to the element relative to the most distant parent

#has_attributes?

Returns whether the element has attributes.

#has_elements?

Returns whether the element has elements.

#has_text?

Returns whether the element has text.

#next_element

Returns the next sibling that is an element.

#previous_element

Returns the previous sibling that is an element.

#raw

Returns whether raw mode is set for the element.

#whitespace

Returns whether whitespace is respected for the element.

#ignore_whitespace_nodes

Returns whether whitespace nodes are to be ignored for the element.

#node_type

Returns symbol :element.

One More Method

#inspect

Returns a string representation of the element.

Accessors

#elements

Returns the REXML::Elements object for the element.

#attributes

Returns the REXML::Attributes object for the element.

#context

Returns or sets the context hash for the element.

Direct Known Subclasses

Document

Constant Summary collapse

UNDEFINED =

The default name

"UNDEFINED"

Constants included from Namespace

Namespace::NAMESPLIT, Namespace::NAME_WITHOUT_NAMESPACE

Constants included from XMLTokens

XMLTokens::NAME, XMLTokens::NAMECHAR, XMLTokens::NAME_CHAR, XMLTokens::NAME_START_CHAR, XMLTokens::NAME_STR, XMLTokens::NCNAME_STR, XMLTokens::NMTOKEN, XMLTokens::NMTOKENS, XMLTokens::REFERENCE

Instance Attribute Summary collapse

Attributes included from Namespace

#expanded_name, #name, #prefix

Attributes inherited from Child

#parent

Instance Method Summary collapse

Methods included from Namespace

#fully_expanded_name, #has_name?

Methods inherited from Parent

#[]=, #add, #deep_clone, #delete, #delete_at, #delete_if, #each, #each_index, #index, #insert_after, #insert_before, #parent?, #replace_child, #size, #to_a, #unshift

Methods inherited from Child

#bytes, #next_sibling=, #previous_sibling=, #remove, #replace_with

Methods included from Node

#each_recursive, #find_first_recursive, #indent, #index_in_parent, #next_sibling_node, #parent?, #previous_sibling_node, #to_s

Constructor Details

#initialize(arg = UNDEFINED, parent = nil, context = nil) ⇒ Element

:call-seq:

Element.new(name = 'UNDEFINED', parent = nil, context = nil) -> new_element
Element.new(element, parent = nil, context = nil) -> new_element

Returns a new REXML::Element object.

When no arguments are given, returns an element with name 'UNDEFINED':

e = REXML::Element.new # => <UNDEFINED/>
e.class                # => REXML::Element
e.name                 # => "UNDEFINED"

When only argument name is given, returns an element of the given name:

REXML::Element.new('foo') # => <foo/>

When only argument element is given, it must be an REXML::Element object; returns a shallow copy of the given element:

e0 = REXML::Element.new('foo')
e1 = REXML::Element.new(e0) # => <foo/>

When argument parent is also given, it must be an REXML::Parent object:

e = REXML::Element.new('foo', REXML::Parent.new)
e.parent # => #<REXML::Parent @parent=nil, @children=[<foo/>]>

When argument context is also given, it must be a hash representing the context for the element; see Element Context:

e = REXML::Element.new('foo', nil, {raw: :all})
e.context # => {:raw=>:all}


319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/rexml/element.rb', line 319

def initialize( arg = UNDEFINED, parent=nil, context=nil )
  super(parent)

  @elements = Elements.new(self)
  @attributes = Attributes.new(self)
  @context = context

  if arg.kind_of? String
    self.name = arg
  elsif arg.kind_of? Element
    self.name = arg.expanded_name
    arg.attributes.each_attribute{ |attribute|
      @attributes << Attribute.new( attribute )
    }
    @context = arg.context
  end
end

Instance Attribute Details

#attributesObject (readonly)

Mechanisms for accessing attributes and child elements of this element.



278
279
280
# File 'lib/rexml/element.rb', line 278

def attributes
  @attributes
end

#contextObject

The context holds information about the processing environment, such as whitespace handling.



281
282
283
# File 'lib/rexml/element.rb', line 281

def context
  @context
end

#elementsObject (readonly)

Mechanisms for accessing attributes and child elements of this element.



278
279
280
# File 'lib/rexml/element.rb', line 278

def elements
  @elements
end

Instance Method Details

#[](name_or_index) ⇒ Object

:call-seq:

[index] -> object
[attr_name] -> attr_value
[attr_sym] -> attr_value

With integer argument index given, returns the child at offset index, or nil if none:

d = REXML::Document.new '><root><a/>text<b/>more<c/></root>'
root = d.root
(0..root.size).each do |index|
  node = root[index]
  p "#{index}: #{node} (#{node.class})"
end

Output:

"0: <a/> (REXML::Element)"
"1: text (REXML::Text)"
"2: <b/> (REXML::Element)"
"3: more (REXML::Text)"
"4: <c/> (REXML::Element)"
"5:  (NilClass)"

With string argument attr_name given, returns the string value for the given attribute name if it exists, otherwise nil:

d = REXML::Document.new('<root attr="value"></root>')
root = d.root
root['attr']   # => "value"
root['nosuch'] # => nil

With symbol argument attr_sym given, returns [attr_sym.to_s]:

root[:attr]   # => "value"
root[:nosuch] # => nil


1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
# File 'lib/rexml/element.rb', line 1246

def [](name_or_index)
  case name_or_index
  when String
    attributes[name_or_index]
  when Symbol
    attributes[name_or_index.to_s]
  else
    super
  end
end

#add_attribute(key, value = nil) ⇒ Object

:call-seq:

add_attribute(name, value) -> value
add_attribute(attribute) -> attribute

Adds an attribute to this element, overwriting any existing attribute by the same name.

With string argument name and object value are given, adds the attribute created with that name and value:

e = REXML::Element.new
e.add_attribute('attr', 'value') # => "value"
e['attr'] # => "value"
e.add_attribute('attr', 'VALUE') # => "VALUE"
e['attr'] # => "VALUE"

With only attribute object attribute given, adds the given attribute:

a = REXML::Attribute.new('attr', 'value')
e.add_attribute(a) # => attr='value'
e['attr'] # => "value"
a = REXML::Attribute.new('attr', 'VALUE')
e.add_attribute(a) # => attr='VALUE'
e['attr'] # => "VALUE"


1345
1346
1347
1348
1349
1350
1351
# File 'lib/rexml/element.rb', line 1345

def add_attribute( key, value=nil )
  if key.kind_of? Attribute
    @attributes << key
  else
    @attributes[key] = value
  end
end

#add_attributes(hash) ⇒ Object

:call-seq:

add_attributes(hash) -> hash
add_attributes(array)

Adds zero or more attributes to the element; returns the argument.

If hash argument hash is given, each key must be a string; adds each attribute created with the key/value pair:

e = REXML::Element.new
h = {'foo' => 'bar', 'baz' => 'bat'}
e.add_attributes(h)

If argument array is given, each array member must be a 2-element array <tt>[name, value]; each name must be a string:

e = REXML::Element.new
a = [['foo' => 'bar'], ['baz' => 'bat']]
e.add_attributes(a)


1376
1377
1378
1379
1380
1381
1382
# File 'lib/rexml/element.rb', line 1376

def add_attributes hash
  if hash.kind_of? Hash
    hash.each_pair {|key, value| @attributes[key] = value }
  elsif hash.kind_of? Array
    hash.each { |value| @attributes[ value[0] ] = value[1] }
  end
end

#add_element(element, attrs = nil) ⇒ Object

:call-seq:

add_element(name, attributes = nil) -> new_element
add_element(element, attributes = nil) -> element

Adds a child element, optionally setting attributes on the added element; returns the added element.

With string argument name, creates a new element with that name and adds the new element as a child:

e0 = REXML::Element.new('foo')
e0.add_element('bar')
e0[0] # => <bar/>

With argument name and hash argument attributes, sets attributes on the new element:

e0.add_element('baz', {'bat' => '0', 'bam' => '1'})
e0[1] # => <baz bat='0' bam='1'/>

With element argument element, adds that element as a child:

e0 = REXML::Element.new('foo')
e1 = REXML::Element.new('bar')
e0.add_element(e1)
e0[0] # => <bar/>

With argument element and hash argument attributes, sets attributes on the added element:

e0.add_element(e1, {'bat' => '0', 'bam' => '1'})
e0[1] # => <bar bat='0' bam='1'/>


732
733
734
735
736
737
738
739
# File 'lib/rexml/element.rb', line 732

def add_element element, attrs=nil
  raise "First argument must be either an element name, or an Element object" if element.nil?
  el = @elements.add(element)
  attrs.each do |key, value|
    el.attributes[key]=value
  end       if attrs.kind_of? Hash
  el
end

#add_namespace(prefix, uri = nil) ⇒ Object

:call-seq:

add_namespace(prefix, uri = nil) -> self

Adds a namespace to the element; returns self.

With the single argument prefix, adds a namespace using the given prefix and the namespace URI:

e = REXML::Element.new('foo')
e.add_namespace('bar')
e.namespaces # => {"xmlns"=>"bar"}

With both arguments prefix and uri given, adds a namespace using both arguments:

e.add_namespace('baz', 'bat')
e.namespaces # => {"xmlns"=>"bar", "baz"=>"bat"}


655
656
657
658
659
660
661
662
663
# File 'lib/rexml/element.rb', line 655

def add_namespace( prefix, uri=nil )
  unless uri
    @attributes["xmlns"] = prefix
  else
    prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/
    @attributes[ prefix ] = uri
  end
  self
end

#add_text(text) ⇒ Object

:call-seq:

add_text(string) -> nil
add_text(text_node) -> self

Adds text to the element.

When string argument string is given, returns nil.

If the element has no child text node, creates a REXML::Text object using the string, honoring the current settings for whitespace and raw, then adds that node to the element:

d = REXML::Document.new('<a><b/></a>')
a = d.root
a.add_text('foo')
a.to_a # => [<b/>, "foo"]

If the element has child text nodes, appends the string to the last text node:

d = REXML::Document.new('<a>foo<b/>bar</a>')
a = d.root
a.add_text('baz')
a.to_a # => ["foo", <b/>, "barbaz"]
a.add_text('baz')
a.to_a # => ["foo", <b/>, "barbazbaz"]

When text node argument text_node is given, appends the node as the last text node in the element; returns self:

d = REXML::Document.new('<a>foo<b/>bar</a>')
a = d.root
a.add_text(REXML::Text.new('baz'))
a.to_a # => ["foo", <b/>, "bar", "baz"]
a.add_text(REXML::Text.new('baz'))
a.to_a # => ["foo", <b/>, "bar", "baz", "baz"]


1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
# File 'lib/rexml/element.rb', line 1147

def add_text( text )
  if text.kind_of? String
    if @children[-1].kind_of? Text
      @children[-1] << text
      return
    end
    text = Text.new( text, whitespace(), nil, raw() )
  end
  self << text unless text.nil?
  return self
end

#attribute(name, namespace = nil) ⇒ Object

:call-seq:

attribute(name, namespace = nil)

Returns the string value for the given attribute name.

With only argument name given, returns the value of the named attribute if it exists, otherwise nil:

xml_string = <<-EOT
  <root xmlns="ns0">
    <a xmlns="ns1" attr="value"></a>
    <b xmlns="ns2" attr="value"></b>
    <c attr="value"/>
 </root>
EOT
d = REXML::Document.new(xml_string)
root = d.root
a = root[1] # => <a xmlns='ns1' attr='value'/>
a.attribute('attr') # => attr='value'
a.attribute('nope') # => nil

With arguments name and namespace given, returns the value of the named attribute if it exists, otherwise nil:

xml_string = "<root xmlns:a='a' a:x='a:x' x='x'/>"
document = REXML::Document.new(xml_string)
document.root.attribute("x")      # => x='x'
document.root.attribute("x", "a") # => a:x='a:x'


1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
# File 'lib/rexml/element.rb', line 1287

def attribute( name, namespace=nil )
  prefix = namespaces.key(namespace) if namespace
  prefix = nil if prefix == 'xmlns'

  ret_val =
    attributes.get_attribute( prefix ? "#{prefix}:#{name}" : name )

  return ret_val unless ret_val.nil?
  return nil if prefix.nil?

  # now check that prefix'es namespace is not the same as the
  # default namespace
  return nil unless ( namespaces[ prefix ] == namespaces[ 'xmlns' ] )

  attributes.get_attribute( name )

end

#cdatasObject

:call-seq:

cdatas -> array_of_cdata_children

Returns a frozen array of the REXML::CData children of the element:

xml_string = <<-EOT
  <root>
    <![CDATA[foo]]>
    <![CDATA[bar]]>
  </root>
EOT
d = REXML::Document.new(xml_string)
cds = d.root.cdatas      # => ["foo", "bar"]
cds.frozen?              # => true
cds.map {|cd| cd.class } # => [REXML::CData, REXML::CData]


1420
1421
1422
# File 'lib/rexml/element.rb', line 1420

def cdatas
  find_all { |child| child.kind_of? CData }.freeze
end

#cloneObject

:call-seq:

clone -> new_element

Returns a shallow copy of the element, containing the name and attributes, but not the parent or children:

e = REXML::Element.new('foo')
e.add_attributes({'bar' => 0, 'baz' => 1})
e.clone # => <foo bar='0' baz='1'/>


383
384
385
# File 'lib/rexml/element.rb', line 383

def clone
  self.class.new self
end

#commentsObject

:call-seq:

comments -> array_of_comment_children

Returns a frozen array of the REXML::Comment children of the element:

xml_string = <<-EOT
  <root>
    <!--foo-->
    <!--bar-->
  </root>
EOT
d = REXML::Document.new(xml_string)
cs = d.root.comments
cs.frozen?            # => true
cs.map {|c| c.class } # => [REXML::Comment, REXML::Comment]
cs.map {|c| c.to_s }  # => ["foo", "bar"]


1441
1442
1443
# File 'lib/rexml/element.rb', line 1441

def comments
  find_all { |child| child.kind_of? Comment }.freeze
end

#delete_attribute(key) ⇒ Object

:call-seq:

delete_attribute(name) -> removed_attribute or nil

Removes a named attribute if it exists; returns the removed attribute if found, otherwise nil:

e = REXML::Element.new('foo')
e.add_attribute('bar', 'baz')
e.delete_attribute('bar') # => <bar/>
e.delete_attribute('bar') # => nil


1395
1396
1397
1398
# File 'lib/rexml/element.rb', line 1395

def delete_attribute(key)
  attr = @attributes.get_attribute(key)
  attr.remove unless attr.nil?
end

#delete_element(element) ⇒ Object

:call-seq:

delete_element(index) -> removed_element or nil
delete_element(element) -> removed_element or nil
delete_element(xpath) -> removed_element or nil

Deletes a child element.

When 1-based integer argument index is given, removes and returns the child element at that offset if it exists; indexing does not include text nodes; returns nil if the element does not exist:

d = REXML::Document.new '<a><b/>text<c/></a>'
a = d.root          # => <a> ... </>
a.delete_element(1) # => <b/>
a.delete_element(1) # => <c/>
a.delete_element(1) # => nil

When element argument element is given, removes and returns that child element if it exists, otherwise returns nil:

d = REXML::Document.new '<a><b/>text<c/></a>'
a = d.root          # => <a> ... </>
c = a[2]            # => <c/>
a.delete_element(c) # => <c/>
a.delete_element(c) # => nil

When xpath argument xpath is given, removes and returns the element at xpath if it exists, otherwise returns nil:

d = REXML::Document.new '<a><b/>text<c/></a>'
a = d.root              # => <a> ... </>
a.delete_element('//c') # => <c/>
a.delete_element('//c') # => nil


778
779
780
# File 'lib/rexml/element.rb', line 778

def delete_element element
  @elements.delete element
end

#delete_namespace(namespace = "xmlns") ⇒ Object

:call-seq:

delete_namespace(namespace = 'xmlns') -> self

Removes a namespace from the element.

With no argument, removes the default namespace:

d = REXML::Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>"
d.to_s # => "<a xmlns:foo='bar' xmlns='twiddle'/>"
d.root.delete_namespace # => <a xmlns:foo='bar'/>
d.to_s # => "<a xmlns:foo='bar'/>"

With argument namespace, removes the specified namespace:

d.root.delete_namespace('foo')
d.to_s # => "<a/>"

Does nothing if no such namespace is found:

d.root.delete_namespace('nosuch')
d.to_s # => "<a/>"


687
688
689
690
691
692
# File 'lib/rexml/element.rb', line 687

def delete_namespace namespace="xmlns"
  namespace = "xmlns:#{namespace}" unless namespace == 'xmlns'
  attribute = attributes.get_attribute(namespace)
  attribute.remove unless attribute.nil?
  self
end

#documentObject

:call-seq:

document -> document or nil

If the element is part of a document, returns that document:

d = REXML::Document.new('<a><b><c/></b></a>')
top_element = d.first
child = top_element.first
top_element.document == d # => true
child.document == d       # => true

If the element is not part of a document, returns nil:

REXML::Element.new.document # => nil

For a document, returns self:

d.document == d           # => true

Related: #root, #root_node.



475
476
477
478
# File 'lib/rexml/element.rb', line 475

def document
  rt = root
  rt.parent if rt
end

#each_element(xpath = nil, &block) ⇒ Object

:call-seq:

each_element {|e| ... }

Calls the given block with each child element:

d = REXML::Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
a = d.root
a.each_element {|e| p e }

Output:

<b> ... </>
<c> ... </>
<d> ... </>
<e/>


930
931
932
# File 'lib/rexml/element.rb', line 930

def each_element( xpath=nil, &block ) # :yields: Element
  @elements.each( xpath, &block )
end

#each_element_with_attribute(key, value = nil, max = 0, name = nil, &block) ⇒ Object

:call-seq:

each_element_with_attribute(attr_name, value = nil, max = 0, xpath = nil) {|e| ... }

Calls the given block with each child element that meets given criteria.

When only string argument attr_name is given, calls the block with each child element that has that attribute:

d = REXML::Document.new '<a><b id="1"/><c id="2"/><d id="1"/><e/></a>'
a = d.root
a.each_element_with_attribute('id') {|e| p e }

Output:

<b id='1'/>
<c id='2'/>
<d id='1'/>

With argument attr_name and string argument value given, calls the block with each child element that has that attribute with that value:

a.each_element_with_attribute('id', '1') {|e| p e }

Output:

<b id='1'/>
<d id='1'/>

With arguments attr_name, value, and integer argument max given, calls the block with at most max child elements:

a.each_element_with_attribute('id', '1', 1) {|e| p e }

Output:

<b id='1'/>

With all arguments given, including xpath, calls the block with only those child elements that meet the first three criteria, and also match the given xpath:

a.each_element_with_attribute('id', '1', 2, '//d') {|e| p e }

Output:

<d id='1'/>


847
848
849
850
851
852
853
854
855
# File 'lib/rexml/element.rb', line 847

def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element
  each_with_something( proc {|child|
    if value.nil?
      child.attributes[key] != nil
    else
      child.attributes[key]==value
    end
  }, max, name, &block )
end

#each_element_with_text(text = nil, max = 0, name = nil, &block) ⇒ Object

:call-seq:

each_element_with_text(text = nil, max = 0, xpath = nil) {|e| ... }

Calls the given block with each child element that meets given criteria.

With no arguments, calls the block with each child element that has text:

d = REXML::Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
a = d.root
a.each_element_with_text {|e| p e }

Output:

<b> ... </>
<c> ... </>
<d> ... </>

With the single string argument text, calls the block with each element that has exactly that text:

a.each_element_with_text('b') {|e| p e }

Output:

<b> ... </>
<c> ... </>

With argument text and integer argument max, calls the block with at most max elements:

a.each_element_with_text('b', 1) {|e| p e }

Output:

<b> ... </>

With all arguments given, including xpath, calls the block with only those child elements that meet the first two criteria, and also match the given xpath:

a.each_element_with_text('b', 2, '//c') {|e| p e }

Output:

<c> ... </>


904
905
906
907
908
909
910
911
912
# File 'lib/rexml/element.rb', line 904

def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element
  each_with_something( proc {|child|
    if text.nil?
      child.has_text?
    else
      child.text == text
    end
  }, max, name, &block )
end

#get_elements(xpath) ⇒ Object

:call-seq:

get_elements(xpath)

Returns an array of the elements that match the given xpath:

xml_string = <<-EOT
<root>
  <a level='1'>
    <a level='2'/>
  </a>
</root>
EOT
d = REXML::Document.new(xml_string)
d.root.get_elements('//a') # => [<a level='1'> ... </>, <a level='2'/>]


949
950
951
# File 'lib/rexml/element.rb', line 949

def get_elements( xpath )
  @elements.to_a( xpath )
end

#get_text(path = nil) ⇒ Object

:call-seq:

get_text(xpath = nil) -> text_node or nil

Returns the first text node child in a specified element, if it exists, nil otherwise.

With no argument, returns the first text node from self:

d = REXML::Document.new "<p>some text <b>this is bold!</b> more text</p>"
d.root.get_text.class # => REXML::Text
d.root.get_text       # => "some text "

With argument xpath, returns the first text node from the element that matches xpath:

d.root.get_text(1) # => "this is bold!"


1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
# File 'lib/rexml/element.rb', line 1053

def get_text path = nil
  rv = nil
  if path
    element = @elements[ path ]
    rv = element.get_text unless element.nil?
  else
    rv = @children.find { |node| node.kind_of? Text }
  end
  return rv
end

#has_attributes?Boolean

:call-seq:

has_attributes? -> true or false

Returns true if the element has attributes, false otherwise:

d = REXML::Document.new('<root><a attr="val"/><b/></root>')
a, b = *d.root
a.has_attributes? # => true
b.has_attributes? # => false

Returns:

  • (Boolean)


1315
1316
1317
# File 'lib/rexml/element.rb', line 1315

def has_attributes?
  return !@attributes.empty?
end

#has_elements?Boolean

:call-seq:

has_elements?

Returns true if the element has one or more element children, false otherwise:

d = REXML::Document.new '<a><b/>text<c/></a>'
a = d.root              # => <a> ... </>
a.has_elements? # => true
b = a[0]        # => <b/>
b.has_elements? # => false

Returns:

  • (Boolean)


794
795
796
# File 'lib/rexml/element.rb', line 794

def has_elements?
  !@elements.empty?
end

#has_text?Boolean

:call-seq:

has_text? -> true or false

Returns true if the element has one or more text noded, false otherwise:

d = REXML::Document.new '<a><b/>text<c/></a>'
a = d.root
a.has_text? # => true
b = a[0]
b.has_text? # => false

Returns:

  • (Boolean)


1002
1003
1004
# File 'lib/rexml/element.rb', line 1002

def has_text?
  not text().nil?
end

#ignore_whitespace_nodesObject

:call-seq:

ignore_whitespace_nodes

Returns true if whitespace nodes are ignored for the element.

See Element Context.



513
514
515
516
517
518
519
520
521
522
# File 'lib/rexml/element.rb', line 513

def ignore_whitespace_nodes
  @ignore_whitespace_nodes = false
  if @context
    if @context[:ignore_whitespace_nodes]
      @ignore_whitespace_nodes =
        (@context[:ignore_whitespace_nodes] == :all or
         @context[:ignore_whitespace_nodes].include? expanded_name)
    end
  end
end

#inspectObject

:call-seq:

inspect -> string

Returns a string representation of the element.

For an element with no attributes and no children, shows the element name:

REXML::Element.new.inspect # => "<UNDEFINED/>"

Shows attributes, if any:

e = REXML::Element.new('foo')
e.add_attributes({'bar' => 0, 'baz' => 1})
e.inspect # => "<foo bar='0' baz='1'/>"

Shows an ellipsis (...), if there are child elements:

e.add_element(REXML::Element.new('bar'))
e.add_element(REXML::Element.new('baz'))
e.inspect # => "<foo bar='0' baz='1'> ... </>"


358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/rexml/element.rb', line 358

def inspect
  rv = "<#@expanded_name"

  @attributes.each_attribute do |attr|
    rv << " "
    attr.write( rv, 0 )
  end

  if children.size > 0
    rv << "> ... </>"
  else
    rv << "/>"
  end
end

#instructionsObject

:call-seq:

instructions -> array_of_instruction_children

Returns a frozen array of the REXML::Instruction children of the element:

xml_string = <<-EOT
  <root>
    <?target0 foo?>
    <?target1 bar?>
  </root>
EOT
d = REXML::Document.new(xml_string)
is = d.root.instructions
is.frozen?             # => true
is.map {|i| i.class } # => [REXML::Instruction, REXML::Instruction]
is.map {|i| i.to_s }  # => ["<?target0 foo?>", "<?target1 bar?>"]


1462
1463
1464
# File 'lib/rexml/element.rb', line 1462

def instructions
  find_all { |child| child.kind_of? Instruction }.freeze
end

#namespace(prefix = nil) ⇒ Object

:call-seq:

namespace(prefix = nil) -> string_uri or nil

Returns the string namespace URI for the element, possibly deriving from one of its ancestors.

xml_string = <<-EOT
  <root>
     <a xmlns='1' xmlns:y='2'>
       <b/>
       <c xmlns:z='3'/>
     </a>
  </root>
EOT
d = REXML::Document.new(xml_string)
b = d.elements['//b']
b.namespace      # => "1"
b.namespace('y') # => "2"
b.namespace('nosuch') # => nil


618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
# File 'lib/rexml/element.rb', line 618

def namespace(prefix=nil)
  if prefix.nil?
    prefix = prefix()
  end
  if prefix == ''
    prefix = "xmlns"
  else
    prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
  end
  ns = nil
  target = self
  while ns.nil? and target
    ns = target.attributes[prefix]
    target = target.parent
  end
  ns = '' if ns.nil? and prefix == 'xmlns'
  return ns
end

#namespacesObject

:call-seq:

namespaces -> array_of_namespace_names

Returns a hash of all defined namespaces in the element and its ancestors:

xml_string = <<-EOT
  <root>
     <a xmlns:x='1' xmlns:y='2'>
       <b/>
       <c xmlns:z='3'/>
     </a>
  </root>
EOT
d = REXML::Document.new(xml_string)
d.elements['//a'].namespaces # => {"x"=>"1", "y"=>"2"}
d.elements['//b'].namespaces # => {"x"=>"1", "y"=>"2"}
d.elements['//c'].namespaces # => {"x"=>"1", "y"=>"2", "z"=>"3"}


591
592
593
594
595
596
# File 'lib/rexml/element.rb', line 591

def namespaces
  namespaces = {}
  namespaces = parent.namespaces if parent
  namespaces = namespaces.merge( attributes.namespaces )
  return namespaces
end

#next_elementObject

:call-seq:

next_element

Returns the next sibling that is an element if it exists, niL otherwise:

d = REXML::Document.new '<a><b/>text<c/></a>'
d.root.elements['b'].next_element #-> <c/>
d.root.elements['c'].next_element #-> nil


963
964
965
966
967
# File 'lib/rexml/element.rb', line 963

def next_element
  element = next_sibling
  element = element.next_sibling until element.nil? or element.kind_of? Element
  return element
end

#node_typeObject

:call-seq:

node_type -> :element

Returns symbol :element:

d = REXML::Document.new('<a/>')
a = d.root  # => <a/>
a.node_type # => :element


1168
1169
1170
# File 'lib/rexml/element.rb', line 1168

def node_type
  :element
end

#prefixesObject

:call-seq:

prefixes -> array_of_namespace_prefixes

Returns an array of the string prefixes (names) of all defined namespaces in the element and its ancestors:

xml_string = <<-EOT
  <root>
     <a xmlns:x='1' xmlns:y='2'>
       <b/>
       <c xmlns:z='3'/>
     </a>
  </root>
EOT
d = REXML::Document.new(xml_string, {compress_whitespace: :all})
d.elements['//a'].prefixes # => ["x", "y"]
d.elements['//b'].prefixes # => ["x", "y"]
d.elements['//c'].prefixes # => ["x", "y", "z"]


565
566
567
568
569
570
# File 'lib/rexml/element.rb', line 565

def prefixes
  prefixes = []
  prefixes = parent.prefixes if parent
  prefixes |= attributes.prefixes
  return prefixes
end

#previous_elementObject

:call-seq:

previous_element

Returns the previous sibling that is an element if it exists, niL otherwise:

d = REXML::Document.new '<a><b/>text<c/></a>'
d.root.elements['c'].previous_element #-> <b/>
d.root.elements['b'].previous_element #-> nil


979
980
981
982
983
# File 'lib/rexml/element.rb', line 979

def previous_element
  element = previous_sibling
  element = element.previous_sibling until element.nil? or element.kind_of? Element
  return element
end

#rawObject

:call-seq:

raw

Returns true if raw mode is set for the element.

See Element Context.

The evaluation is tested against expanded_name, and so is namespace sensitive.



533
534
535
536
537
538
# File 'lib/rexml/element.rb', line 533

def raw
  @raw = (@context and @context[:raw] and
          (@context[:raw] == :all or
           @context[:raw].include? expanded_name))
  @raw
end

#rootObject

:call-seq:

root -> element

Returns the most distant element (not document) ancestor of the element:

d = REXML::Document.new('<a><b><c/></b></a>')
top_element = d.first
child = top_element.first
top_element.root == top_element # => true
child.root == top_element       # => true

For a document, returns the topmost element:

d.root == top_element # => true

Related: #root_node, #document.



443
444
445
446
447
448
449
450
451
452
# File 'lib/rexml/element.rb', line 443

def root
  target = self
  while target
    return target.elements[1] if target.kind_of? Document
    parent = target.parent
    return target if parent.kind_of? Document or parent.nil?
    target = parent
  end
  nil
end

#root_nodeObject

:call-seq:

root_node -> document or element

Returns the most distant ancestor of self.

When the element is part of a document, returns the root node of the document. Note that the root node is different from the document element; in this example a is document element and the root node is its parent:

d = REXML::Document.new('<a><b><c/></b></a>')
top_element = d.first      # => <a> ... </>
child = top_element.first  # => <b> ... </>
d.root_node == d           # => true
top_element.root_node == d # => true
child.root_node == d       # => true

When the element is not part of a document, but does have ancestor elements, returns the most distant ancestor element:

e0 = REXML::Element.new('foo')
e1 = REXML::Element.new('bar')
e1.parent = e0
e2 = REXML::Element.new('baz')
e2.parent = e1
e2.root_node == e0 # => true

When the element has no ancestor elements, returns self:

e = REXML::Element.new('foo')
e.root_node == e # => true

Related: #root, #document.



422
423
424
# File 'lib/rexml/element.rb', line 422

def root_node
  parent.nil? ? self : parent.root_node
end

#text(path = nil) ⇒ Object

:call-seq:

text(xpath = nil) -> text_string or nil

Returns the text string from the first text node child in a specified element, if it exists, nil otherwise.

With no argument, returns the text from the first text node in self:

d = REXML::Document.new "<p>some text <b>this is bold!</b> more text</p>"
d.root.text.class # => String
d.root.text       # => "some text "

With argument xpath, returns text from the first text node in the element that matches xpath:

d.root.text(1) # => "this is bold!"

Note that an element may have multiple text nodes, possibly separated by other non-text children, as above. Even so, the returned value is the string text from the first such node.

Note also that the text note is retrieved by method get_text, and so is always normalized text.



1030
1031
1032
1033
1034
# File 'lib/rexml/element.rb', line 1030

def text( path = nil )
  rv = get_text(path)
  return rv.value unless rv.nil?
  nil
end

#text=(text) ⇒ Object

:call-seq:

text = string -> string
text = nil -> nil

Adds, replaces, or removes the first text node child in the element.

With string argument string, creates a new REXML::Text node containing that string, honoring the current settings for whitespace and row, then places the node as the first text child in the element; returns string.

If the element has no text child, the text node is added:

d = REXML::Document.new '<a><b/></a>'
d.root.text = 'foo' #-> '<a><b/>foo</a>'

If the element has a text child, it is replaced:

d.root.text = 'bar' #-> '<a><b/>bar</a>'

With argument nil, removes the first text child:

d.root.text = nil   #-> '<a><b/><c/></a>'


1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
# File 'lib/rexml/element.rb', line 1089

def text=( text )
  if text.kind_of? String
    text = Text.new( text, whitespace(), nil, raw() )
  elsif !text.nil? and !text.kind_of? Text
    text = Text.new( text.to_s, whitespace(), nil, raw() )
  end
  old_text = get_text
  if text.nil?
    old_text.remove unless old_text.nil?
  else
    if old_text.nil?
      self << text
    else
      old_text.replace_with( text )
    end
  end
  return self
end

#textsObject

:call-seq:

texts -> array_of_text_children

Returns a frozen array of the REXML::Text children of the element:

xml_string = '<root><a/>text<b/>more<c/></root>'
d = REXML::Document.new(xml_string)
ts = d.root.texts
ts.frozen?            # => true
ts.map {|t| t.class } # => [REXML::Text, REXML::Text]
ts.map {|t| t.to_s }  # => ["text", "more"]


1478
1479
1480
# File 'lib/rexml/element.rb', line 1478

def texts
  find_all { |child| child.kind_of? Text }.freeze
end

#whitespaceObject

:call-seq:

whitespace

Returns true if whitespace is respected for this element, false otherwise.

See Element Context.

The evaluation is tested against the element’s expanded_name, and so is namespace-sensitive.



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/rexml/element.rb', line 490

def whitespace
  @whitespace = nil
  if @context
    if @context[:respect_whitespace]
      @whitespace = (@context[:respect_whitespace] == :all or
                     @context[:respect_whitespace].include? expanded_name)
    end
    @whitespace = false if (@context[:compress_whitespace] and
                            (@context[:compress_whitespace] == :all or
                             @context[:compress_whitespace].include? expanded_name)
                           )
  end
  @whitespace = true unless @whitespace == false
  @whitespace
end

#write(output = $stdout, indent = -1,, transitive = false, ie_hack = false) ⇒ Object

DEPRECATED

See REXML::Formatters

Writes out this element, and recursively, all children.

output

output an object which supports ‘<< string’; this is where the

document will be written.
indent

An integer. If -1, no indenting will be used; otherwise, the indentation will be this number of spaces, and children will be indented an additional amount. Defaults to -1

transitive

If transitive is true and indent is >= 0, then the output will be pretty-printed in such a way that the added whitespace does not affect the parse tree of the document

ie_hack

This hack inserts a space before the /> on empty tags to address a limitation of Internet Explorer. Defaults to false

out = ''
doc.write( out )     #-> doc is written to the string 'out'
doc.write( $stdout ) #-> doc written to the console


1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
# File 'lib/rexml/element.rb', line 1504

def write(output=$stdout, indent=-1, transitive=false, ie_hack=false)
  Kernel.warn("#{self.class.name}.write is deprecated.  See REXML::Formatters", uplevel: 1)
  formatter = if indent > -1
      if transitive
        require_relative "formatters/transitive"
        REXML::Formatters::Transitive.new( indent, ie_hack )
      else
        REXML::Formatters::Pretty.new( indent, ie_hack )
      end
    else
      REXML::Formatters::Default.new( ie_hack )
    end
  formatter.write( self, output )
end

#xpathObject

:call-seq:

xpath -> string_xpath

Returns the string xpath to the element relative to the most distant parent:

d = REXML::Document.new('<a><b><c/></b></a>')
a = d.root # => <a> ... </>
b = a[0]   # => <b> ... </>
c = b[0]   # => <c/>
d.xpath    # => ""
a.xpath    # => "/a"
b.xpath    # => "/a/b"
c.xpath    # => "/a/b/c"

If there is no parent, returns the expanded name of the element:

e = REXML::Element.new('foo')
e.xpath    # => "foo"


1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
# File 'lib/rexml/element.rb', line 1192

def xpath
  path_elements = []
  cur = self
  path_elements << __to_xpath_helper( self )
  while cur.parent
    cur = cur.parent
    path_elements << __to_xpath_helper( cur )
  end
  return path_elements.reverse.join( "/" )
end