Class: REXML::Attributes

Inherits:
Hash
  • Object
show all
Defined in:
lib/rexml/element.rb

Overview

A class that defines the set of Attributes of an Element and provides operations for accessing elements in that set.

Instance Method Summary collapse

Constructor Details

#initialize(element) ⇒ Attributes

:call-seq:

new(element)

Creates and returns a new REXML::Attributes object. The element given by argument element is stored, but its own attributes are not modified:

ele = REXML::Element.new('foo')
attrs = REXML::Attributes.new(ele)
attrs.object_id == ele.attributes.object_id # => false

Other instance methods in class REXML::Attributes may refer to:

  • element.document.

  • element.prefix.

  • element.expanded_name.



2156
2157
2158
# File 'lib/rexml/element.rb', line 2156

def initialize element
  @element = element
end

Instance Method Details

#[](name) ⇒ Object

:call-seq:

[name] -> attribute_value or nil

Returns the value for the attribute given by name, if it exists; otherwise nil. The value returned is the unnormalized attribute value, with entities expanded:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
ele.attributes['att']     # => "<"
ele.attributes['bar:att'] # => "2"
ele.attributes['nosuch']  # => nil

Related: get_attribute (returns an Attribute object).



2181
2182
2183
2184
2185
# File 'lib/rexml/element.rb', line 2181

def [](name)
  attr = get_attribute(name)
  return attr.value unless attr.nil?
  return nil
end

#[]=(name, value) ⇒ Object

:call-seq:

[name] = value -> value

When value is non-nil, assigns that to the attribute for the given name, overwriting the previous value if it exists:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes
attrs['foo:att'] = '2' # => "2"
attrs['baz:att'] = '3' # => "3"

When value is nil, deletes the attribute if it exists:

attrs['baz:att'] = nil
attrs.include?('baz:att') # => false


2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
# File 'lib/rexml/element.rb', line 2365

def []=( name, value )
  if value.nil?             # Delete the named attribute
    attr = get_attribute(name)
    delete attr
    return
  end

  unless value.kind_of? Attribute
    if @element.document and @element.document.doctype
      value = Text::normalize( value, @element.document.doctype )
    else
      value = Text::normalize( value, nil )
    end
    value = Attribute.new(name, value)
  end
  value.element = @element
  old_attr = fetch(value.name, nil)
  if old_attr.nil?
    store(value.name, value)
  elsif old_attr.kind_of? Hash
    old_attr[value.prefix] = value
  elsif old_attr.prefix != value.prefix
    store value.name, {old_attr.prefix => old_attr,
                       value.prefix    => value}
  else
    store value.name, value
  end
  return @element
end

#add(attribute) ⇒ Object Also known as: <<

:call-seq:

add(attribute) -> attribute

Adds attribute attribute, replacing the previous attribute of the same name if it exists; returns attribute:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes
attrs # => {"att"=>{"foo"=>foo:att='1', "bar"=>bar:att='2', ""=>att='&lt;'}}
attrs.add(REXML::Attribute.new('foo:att', '2')) # => foo:att='2'
attrs.add(REXML::Attribute.new('baz', '3')) # => baz='3'
attrs.include?('baz') # => true


2522
2523
2524
# File 'lib/rexml/element.rb', line 2522

def add( attribute )
  self[attribute.name] = attribute
end

#delete(attribute) ⇒ Object

:call-seq:

delete(name) -> element
delete(attribute) -> element

Removes a specified attribute if it exists; returns the attributes’ element.

When string argument name is given, removes the attribute of that name if it exists:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes
attrs.delete('foo:att') # => <ele bar:att='2' att='&lt;'/>
attrs.delete('foo:att') # => <ele bar:att='2' att='&lt;'/>

When attribute argument attribute is given, removes that attribute if it exists:

attr = REXML::Attribute.new('bar:att', '2')
attrs.delete(attr) # => <ele att='&lt;'/> # => <ele att='&lt;'/>
attrs.delete(attr) # => <ele att='&lt;'/> # => <ele/>


2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
# File 'lib/rexml/element.rb', line 2475

def delete( attribute )
  name = nil
  prefix = nil
  if attribute.kind_of? Attribute
    name = attribute.name
    prefix = attribute.prefix
  else
    attribute =~ Namespace::NAMESPLIT
    prefix, name = $1, $2
    prefix = '' unless prefix
  end
  old = fetch(name, nil)
  if old.kind_of? Hash # the supplied attribute is one of many
    old.delete(prefix)
    if old.size == 1
      repl = nil
      old.each_value{|v| repl = v}
      store name, repl
    end
  elsif old.nil?
    return @element
  else # the supplied attribute is a top-level one
    super(name)
  end
  @element
end

#delete_all(name) ⇒ Object

:call-seq:

delete_all(name) -> array_of_removed_attributes

Removes all attributes matching the given name; returns an array of the removed attributes:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes
attrs.delete_all('att') # => [att='&lt;']


2544
2545
2546
2547
2548
2549
2550
2551
# File 'lib/rexml/element.rb', line 2544

def delete_all( name )
  rv = []
  each_attribute { |attribute|
    rv << attribute if attribute.expanded_name == name
  }
  rv.each{ |attr| attr.remove }
  return rv
end

#eachObject

:call-seq:

each {|expanded_name, value| ... }

Calls the given block with each expanded-name/value pair:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele']   # => <a foo:att='1' bar:att='2' att='&lt;'/>
ele.attributes.each do |expanded_name, value|
  p [expanded_name, value]
end

Output:

["foo:att", "1"]
["bar:att", "2"]
["att", "<"]


2283
2284
2285
2286
2287
2288
# File 'lib/rexml/element.rb', line 2283

def each
  return to_enum(__method__) unless block_given?
  each_attribute do |attr|
    yield [attr.expanded_name, attr.value]
  end
end

#each_attributeObject

:call-seq:

each_attribute {|attr| ... }

Calls the given block with each REXML::Attribute object:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele']   # => <a foo:att='1' bar:att='2' att='&lt;'/>
ele.attributes.each_attribute do |attr|
  p [attr.class, attr]
end

Output:

[REXML::Attribute, foo:att='1']
[REXML::Attribute, bar:att='2']
[REXML::Attribute, att='&lt;']


2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
# File 'lib/rexml/element.rb', line 2250

def each_attribute # :yields: attribute
  return to_enum(__method__) unless block_given?
  each_value do |val|
    if val.kind_of? Attribute
      yield val
    else
      val.each_value { |atr| yield atr }
    end
  end
end

#get_attribute(name) ⇒ Object

:call-seq:

get_attribute(name) -> attribute_object or nil

Returns the REXML::Attribute object for the given name:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes
attrs.get_attribute('foo:att')       # => foo:att='1'
attrs.get_attribute('foo:att').class # => REXML::Attribute
attrs.get_attribute('bar:att')       # => bar:att='2'
attrs.get_attribute('att')           # => att='&lt;'
attrs.get_attribute('nosuch')        # => nil


2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
# File 'lib/rexml/element.rb', line 2309

def get_attribute( name )
  attr = fetch( name, nil )
  if attr.nil?
    return nil if name.nil?
    # Look for prefix
    name =~ Namespace::NAMESPLIT
    prefix, n = $1, $2
    if prefix
      attr = fetch( n, nil )
      # check prefix
      if attr == nil
      elsif attr.kind_of? Attribute
        return attr if prefix == attr.prefix
      else
        attr = attr[ prefix ]
        return attr
      end
    end
    element_document = @element.document
    if element_document and element_document.doctype
      expn = @element.expanded_name
      expn = element_document.doctype.name if expn.size == 0
      attr_val = element_document.doctype.attribute_of(expn, name)
      return Attribute.new( name, attr_val ) if attr_val
    end
    return nil
  end
  if attr.kind_of? Hash
    attr = attr[ @element.prefix ]
  end
  return attr
end

#get_attribute_ns(namespace, name) ⇒ Object

:call-seq:

get_attribute_ns(namespace, name)

Returns the REXML::Attribute object among the attributes that matches the given namespace and name:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele'] # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes
attrs.get_attribute_ns('http://foo', 'att')    # => foo:att='1'
attrs.get_attribute_ns('http://foo', 'nosuch') # => nil


2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
# File 'lib/rexml/element.rb', line 2570

def get_attribute_ns(namespace, name)
  result = nil
  each_attribute() { |attribute|
    if name == attribute.name &&
      namespace == attribute.namespace() &&
      ( !namespace.empty? || !attribute.fully_expanded_name.index(':') )
      # foo will match xmlns:foo, but only if foo isn't also an attribute
      result = attribute if !result or !namespace.empty? or
                            !attribute.fully_expanded_name.index(':')
    end
  }
  result
end

#lengthObject Also known as: size

:call-seq:

length

Returns the count of attributes:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele']   # => <a foo:att='1' bar:att='2' att='&lt;'/>
ele.attributes.length # => 3


2221
2222
2223
2224
2225
# File 'lib/rexml/element.rb', line 2221

def length
  c = 0
  each_attribute { c+=1 }
  c
end

#namespacesObject

:call-seq:

namespaces

Returns a hash of name/value pairs for the namespaces:

xml_string = '<a xmlns="foo" xmlns:x="bar" xmlns:y="twee" z="glorp"/>'
d = REXML::Document.new(xml_string)
d.root.attributes.namespaces # => {"xmlns"=>"foo", "x"=>"bar", "y"=>"twee"}


2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
# File 'lib/rexml/element.rb', line 2431

def namespaces
  namespaces = {}
  each_attribute do |attribute|
    namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns'
  end
  if @element.document and @element.document.doctype
    expn = @element.expanded_name
    expn = @element.document.doctype.name if expn.size == 0
    @element.document.doctype.attributes_of(expn).each {
      |attribute|
      namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns'
    }
  end
  namespaces
end

#prefixesObject

:call-seq:

prefixes -> array_of_prefix_strings

Returns an array of prefix strings in the attributes. The array does not include the default namespace declaration, if one exists.

xml_string = '<a xmlns="foo" xmlns:x="bar" xmlns:y="twee" z="glorp"/>'
d = REXML::Document.new(xml_string)
d.root.attributes.prefixes # => ["x", "y"]


2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
# File 'lib/rexml/element.rb', line 2406

def prefixes
  ns = []
  each_attribute do |attribute|
    ns << attribute.name if attribute.prefix == 'xmlns'
  end
  if @element.document and @element.document.doctype
    expn = @element.expanded_name
    expn = @element.document.doctype.name if expn.size == 0
    @element.document.doctype.attributes_of(expn).each {
      |attribute|
      ns << attribute.name if attribute.prefix == 'xmlns'
    }
  end
  ns
end

#to_aObject

:call-seq:

to_a -> array_of_attribute_objects

Returns an array of REXML::Attribute objects representing the attributes:

xml_string = <<-EOT
  <root xmlns:foo="http://foo" xmlns:bar="http://bar">
     <ele foo:att='1' bar:att='2' att='&lt;'/>
  </root>
EOT
d = REXML::Document.new(xml_string)
ele = d.root.elements['//ele']   # => <a foo:att='1' bar:att='2' att='&lt;'/>
attrs = ele.attributes.to_a      # => [foo:att='1', bar:att='2', att='&lt;']
attrs.first.class                # => REXML::Attribute


2203
2204
2205
# File 'lib/rexml/element.rb', line 2203

def to_a
  enum_for(:each_attribute).to_a
end