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

Constructor

element

the Element of which this is an Attribute


968
969
970
# File 'lib/rexml/element.rb', line 968

def initialize element
  @element = element
end

Instance Method Details

#[](name) ⇒ Object

Fetches an attribute value. If you want to get the Attribute itself, use get_attribute()

name

an XPath attribute name. Namespaces are relevant here.

Returns

the String value of the matching attribute, or nil if no matching attribute was found. This is the unnormalized value (with entities expanded).

doc = Document.new "<a foo:att='1' bar:att='2' att='&lt;'/>"
doc.root.attributes['att']         #-> '<'
doc.root.attributes['bar:att']     #-> '2'

983
984
985
986
987
# File 'lib/rexml/element.rb', line 983

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

#[]=(name, value) ⇒ Object

Sets an attribute, overwriting any existing attribute value by the same name. Namespace is significant.

name

the name of the attribute

value

(optional) If supplied, the value of the attribute. If nil, any existing matching attribute is deleted.

Returns

Owning element

doc = Document.new "<a x:foo='1' foo='3'/>"
doc.root.attributes['y:foo'] = '2'
doc.root.attributes['foo'] = '4'
doc.root.attributes['x:foo'] = nil

1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
# File 'lib/rexml/element.rb', line 1085

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    # Check for conflicting namespaces

    raise ParseException.new(
      "Namespace conflict in adding attribute \"#{value.name}\": "+
      "Prefix \"#{old_attr.prefix}\" = "+
      "\"#{@element.namespace(old_attr.prefix)}\" and prefix "+
      "\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if
      value.prefix != "xmlns" and old_attr.prefix != "xmlns" and
      @element.namespace( old_attr.prefix ) ==
        @element.namespace( 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: <<

Adds an attribute, overriding any existing attribute by the same name. Namespaces are significant.

attribute

An Attribute


1204
1205
1206
# File 'lib/rexml/element.rb', line 1204

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

#delete(attribute) ⇒ Object

Removes an attribute

attribute

either a String, which is the name of the attribute to remove – namespaces are significant here – or the attribute to remove.

Returns

the owning element

doc = Document.new "<a y:foo='0' x:foo='1' foo='3' z:foo='4'/>"
doc.root.attributes.delete 'foo'   #-> <a y:foo='0' x:foo='1' z:foo='4'/>"
doc.root.attributes.delete 'x:foo' #-> <a y:foo='0' z:foo='4'/>"
attr = doc.root.attributes.get_attribute('y:foo')
doc.root.attributes.delete attr    #-> <a z:foo='4'/>"

1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
# File 'lib/rexml/element.rb', line 1172

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)
  attr = nil
  if old.kind_of? Hash # the supplied attribute is one of many
    attr = 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
    attr = old
    super(name)
  end
  @element
end

#delete_all(name) ⇒ Object

Deletes all attributes matching a name. Namespaces are significant.

name

A String; all attributes that match this path will be removed

Returns

an Array of the Attributes that were removed


1214
1215
1216
1217
1218
1219
1220
1221
# File 'lib/rexml/element.rb', line 1214

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

#eachObject

Iterates over each attribute of an Element, yielding the expanded name and value as a pair of Strings.

doc = Document.new '<a x="1" y="2"/>'
doc.root.attributes.each {|name, value| p name+" => "+value }

1025
1026
1027
1028
1029
# File 'lib/rexml/element.rb', line 1025

def each
  each_attribute do |attr|
    yield [attr.expanded_name, attr.value]
  end
end

#each_attributeObject

Iterates over the attributes of an Element. Yields actual Attribute nodes, not String values.

doc = Document.new '<a x="1" y="2"/>'
doc.root.attributes.each_attribute {|attr|
  p attr.expanded_name+" => "+attr.value
}

1010
1011
1012
1013
1014
1015
1016
1017
1018
# File 'lib/rexml/element.rb', line 1010

def each_attribute # :yields: attribute
  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

Fetches an attribute

name

the name by which to search for the attribute. Can be a prefix:name namespace name.

Returns

The first matching attribute, or nil if there was none. This

value is an Attribute node, not the String value of the attribute.

doc = Document.new '<a x:foo="1" foo="2" bar="3"/>'
doc.root.attributes.get_attribute("foo").value    #-> "2"
doc.root.attributes.get_attribute("x:foo").value  #-> "1"

1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
# File 'lib/rexml/element.rb', line 1040

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

The get_attribute_ns method retrieves a method by its namespace and name. Thus it is possible to reliably identify an attribute even if an XML processor has changed the prefix.

Method contributed by Henrik Martensson


1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
# File 'lib/rexml/element.rb', line 1228

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

Returns the number of attributes the owning Element contains.

doc = Document "<a x='1' y='2' foo:x='3'/>"
doc.root.attributes.length        #-> 3

996
997
998
999
1000
# File 'lib/rexml/element.rb', line 996

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

#namespacesObject


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

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

Returns an array of Strings containing all of the prefixes declared by this set of # attributes. The array does not include the default namespace declaration, if one exists.

doc = Document.new("<a xmlns='foo' xmlns:x='bar' xmlns:y='twee' "+
      "z='glorp' p:k='gru'/>")
prefixes = doc.root.attributes.prefixes    #-> ['x', 'y']

1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
# File 'lib/rexml/element.rb', line 1130

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


989
990
991
# File 'lib/rexml/element.rb', line 989

def to_a
  enum_for(:each_attribute).to_a
end