From 78e617941d30cf0b340cbda460502e458449abd3 Mon Sep 17 00:00:00 2001 From: NAITOH Jun Date: Mon, 31 Aug 2026 10:49:18 +0900 Subject: [PATCH] Follow up GH-357 in the documentation of Element#attribute GH-360 documented REXML::Element#attribute as matching a namespace loosely, and said an unprefixed attribute is taken to be in the default namespace. GH-357 made the method ask REXML::Attributes#get_attribute_ns first, so that is now only true when nothing matches strictly: attribute("a", "ns0") -> p:a='PA', not a='A' The two examples in the note still hold, because neither document has a prefixed attribute of the same local name for the strict match to find. It is the rule stated around them that no longer holds: an unprefixed attribute is taken to be in the default namespace only when nothing matches strictly. Describe the method the way it now works -- strict first, then the compatibility fallback -- and add the example above, which is the only place the change is visible. Say of get_attribute_ns that it matches strictly and only strictly, rather than pointing at it as the way to match strictly, now that Element#attribute starts there too. --- lib/rexml/element.rb | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/rexml/element.rb b/lib/rexml/element.rb index af005754..677069cf 100644 --- a/lib/rexml/element.rb +++ b/lib/rexml/element.rb @@ -1268,9 +1268,11 @@ def [](name_or_index) # document.root.attribute("x") # => x='x' # document.root.attribute("x", "a") # => a:x='a:x' # - # This method matches +namespace+ loosely. An unprefixed attribute is - # taken to be in the default namespace, and a +namespace+ that no prefix - # is bound to falls back to the unprefixed attribute: + # This method matches +namespace+ as the XML Namespaces specification says + # first, then falls back to a looser match kept for compatibility: an + # unprefixed attribute is taken to be in the default namespace, and a + # +namespace+ that no prefix is bound to falls back to the unprefixed + # attribute: # # xml_string = "" # document = REXML::Document.new(xml_string) @@ -1278,11 +1280,16 @@ def [](name_or_index) # document.root.attribute("a", "nosuch") # => a='a' # # The XML Namespaces specification says that an unprefixed attribute has - # no namespace, so neither of those should match. - # REXML::Attributes#get_attribute_ns follows the XML Namespaces - # specification and returns +nil+ for both; use it when you need the - # namespace to be matched strictly. The looser behavior here is kept for - # compatibility. + # no namespace, so neither of those should match; the fallback answers + # them. The fallback only answers when nothing matches strictly, so an + # attribute that does is returned instead of the unprefixed one: + # + # xml_string = "" + # document = REXML::Document.new(xml_string) + # document.root.attribute("a", "ns0") # => p:a='PA' + # + # REXML::Attributes#get_attribute_ns matches strictly and only strictly, + # returning +nil+ where the fallback would answer. # def attribute( name, namespace=nil ) return attributes.get_attribute( name ) if namespace.nil?