diff --git a/lib/rexml/element.rb b/lib/rexml/element.rb index a002db07..394d7415 100644 --- a/lib/rexml/element.rb +++ b/lib/rexml/element.rb @@ -1269,20 +1269,17 @@ def [](name_or_index) # document.root.attribute("x", "a") # => a:x='a:x' # 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 attributes.get_attribute( name ) if namespace.nil? + ret_val = attributes.get_attribute_ns( namespace, 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 ) + # Kept for compatibility: an unprefixed attribute also matches when the + # requested URI is the default namespace or is not declared on this + # element, even though such an attribute is not in that namespace. + if namespace == namespaces[ 'xmlns' ] or !namespaces.has_value?( namespace ) + attributes.get_attribute( name ) + end end # :call-seq: diff --git a/test/test_element.rb b/test/test_element.rb index 20216895..02dae3be 100644 --- a/test/test_element.rb +++ b/test/test_element.rb @@ -11,5 +11,33 @@ def test_array_reference_symbol doc = REXML::Document.new("") assert_equal("Ruby", doc.root[:name]) end + + def test_attribute_duplicated_namespace_url + doc = REXML::Document.new("") + root = doc.root + attributes = [ + root.attribute("a", "url1"), + root.attribute("b", "url1"), + root.attribute("c", "url2"), + root.attribute("d", "url2"), + ] + assert_equal(["ns1:a", "ns1:b", "ns2:c", "ns3:d"], + attributes.collect {|attribute| attribute&.expanded_name}) + end + + def test_attribute_prefixed_match_independent_of_declaration_order + sources = [ + "", + "", + "", + "", + ] + expanded_names = sources.collect do |source| + REXML::Document.new(source).root.attribute("a", "url1").expanded_name + end + assert_equal(["ns1:a"] * 4, expanded_names) + end end end