Skip to content

Commit aca5642

Browse files
committed
Fix Element#attribute when a namespace URI is bound to multiple prefixes
Element#attribute used namespaces.key(namespace), which returns only the first prefix bound to that URI, so an attribute using any other prefix for the same URI was not found. Try every prefix bound to the URI instead, keeping the unprefixed attribute preferred when the URI is the default namespace.
1 parent fa0427c commit aca5642

2 files changed

Lines changed: 28 additions & 11 deletions

File tree

lib/rexml/element.rb

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,20 +1269,22 @@ def [](name_or_index)
12691269
# document.root.attribute("x", "a") # => a:x='a:x'
12701270
#
12711271
def attribute( name, namespace=nil )
1272-
prefix = namespaces.key(namespace) if namespace
1273-
prefix = nil if prefix == 'xmlns'
1272+
prefixes = namespace ? namespaces.select {|_, uri| uri == namespace}.keys : []
12741273

1275-
ret_val =
1276-
attributes.get_attribute( prefix ? "#{prefix}:#{name}" : name )
1277-
1278-
return ret_val unless ret_val.nil?
1279-
return nil if prefix.nil?
1274+
# An unprefixed attribute is used for the default namespace.
1275+
if prefixes.empty? or prefixes.include?( 'xmlns' )
1276+
ret_val = attributes.get_attribute( name )
1277+
return ret_val unless ret_val.nil?
1278+
end
12801279

1281-
# now check that prefix'es namespace is not the same as the
1282-
# default namespace
1283-
return nil unless ( namespaces[ prefix ] == namespaces[ 'xmlns' ] )
1280+
# The same namespace URI may be bound to multiple prefixes.
1281+
prefixes.each do |prefix|
1282+
next if prefix == 'xmlns'
1283+
ret_val = attributes.get_attribute( "#{prefix}:#{name}" )
1284+
return ret_val unless ret_val.nil?
1285+
end
12841286

1285-
attributes.get_attribute( name )
1287+
nil
12861288
end
12871289

12881290
# :call-seq:

test/test_element.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,20 @@ def test_array_reference_symbol
1111
doc = REXML::Document.new("<language name='Ruby'/>")
1212
assert_equal("Ruby", doc.root[:name])
1313
end
14+
15+
def test_attribute_duplicated_namespace_url
16+
doc = REXML::Document.new("<root xmlns='url1' xmlns:ns1='url1' " +
17+
"xmlns:ns2='url2' xmlns:ns3='url2' " +
18+
"a='' ns1:a='' ns1:b='' ns2:c='' ns3:d=''/>")
19+
root = doc.root
20+
attributes = [
21+
root.attribute("a", "url1"),
22+
root.attribute("b", "url1"),
23+
root.attribute("c", "url2"),
24+
root.attribute("d", "url2"),
25+
]
26+
assert_equal(["a", "ns1:b", "ns2:c", "ns3:d"],
27+
attributes.collect {|attribute| attribute&.expanded_name})
28+
end
1429
end
1530
end

0 commit comments

Comments
 (0)