From c142785763274e62b836d9d6ac893aba548d4edc Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 21 Oct 2022 17:24:45 -0400 Subject: [PATCH] fix(jruby): Node#attribute correctly matches against localName Previously, it was matching against the full name. Also, make sure that we create new attributes with setAttributeNS (even if the URI is null) so that we can retrieve with `localName`. Note that we need additional logic to handle unknown namespaces. --- CHANGELOG.md | 1 + ext/java/nokogiri/XmlNode.java | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d723481f2..c6d7e39861 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Nokogiri follows [Semantic Versioning](https://semver.org/), please see the [REA * [CRuby] libgumbo (the HTML5 parser) treats reaching max-depth as EOF. This addresses a class of issues when the parser is interrupted in this way. [#3121] @stevecheckoway * [CRuby] Update node GC lifecycle to avoid a potential memory leak with fragments in libxml 2.13.0 caused by changes in `xmlAddChild`. [#3156] @flavorjones * [CRuby] libgumbo correctly prints nonstandard element names in error messages. [#3219] @stevecheckoway +* [JRuby] Fixed some bugs in how `Node#attributes` handles attributes with namespaces. [#2677, #2679] @flavorjones ### Changed diff --git a/ext/java/nokogiri/XmlNode.java b/ext/java/nokogiri/XmlNode.java index 4ecc957954..70440b5351 100644 --- a/ext/java/nokogiri/XmlNode.java +++ b/ext/java/nokogiri/XmlNode.java @@ -643,12 +643,22 @@ public class XmlNode extends RubyObject @JRubyMethod(name = {"attribute", "attr"}) public IRubyObject - attribute(ThreadContext context, IRubyObject name) + attribute(ThreadContext context, IRubyObject rbName) { - NamedNodeMap attrs = this.node.getAttributes(); - Node attr = attrs.getNamedItem(rubyStringToString(name)); - if (attr == null) { return context.nil; } - return getCachedNodeOrCreate(context.runtime, attr); + NamedNodeMap attributes = this.node.getAttributes(); + String name = rubyStringToString(rbName); + + for (int j = 0 ; j < attributes.getLength() ; j++) { + Node attribute = attributes.item(j); + String localName = attribute.getLocalName(); + if (localName == null) { + continue; + } + if (localName.equals(name)) { + return getCachedNodeOrCreate(context.runtime, attribute); + } + } + return context.nil; } @JRubyMethod @@ -1415,11 +1425,12 @@ public class XmlNode extends RubyObject } } - if (uri != null) { - element.setAttributeNS(uri, key, val); - } else { + if (colonIndex > 0 && uri == null) { element.setAttribute(key, val); + } else { + element.setAttributeNS(uri, key, val); } + clearXpathContext(node); }