diff --git a/CHANGES b/CHANGES index 1bb4842593..eda0d2bc46 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,10 @@ jsoup changelog element, e.g. ancestor-or-self::*. + * Bugfix: boolean attribute names should be case-insensitive, but were not when the parser was configured to preserve + case. + + *** Release 1.14.3 [2021-Sep-30] * Improvement: added native XPath support in Element#selectXpath(String) diff --git a/src/main/java/org/jsoup/nodes/Attribute.java b/src/main/java/org/jsoup/nodes/Attribute.java index a1b2ae21ec..5cdecc339c 100644 --- a/src/main/java/org/jsoup/nodes/Attribute.java +++ b/src/main/java/org/jsoup/nodes/Attribute.java @@ -2,6 +2,7 @@ import org.jsoup.SerializationException; import org.jsoup.helper.Validate; +import org.jsoup.internal.Normalizer; import org.jsoup.internal.StringUtil; import org.jsoup.nodes.Document.OutputSettings.Syntax; @@ -211,7 +212,7 @@ protected static boolean shouldCollapseAttribute(final String key, @Nullable fin * Checks if this attribute name is defined as a boolean attribute in HTML5 */ public static boolean isBooleanAttribute(final String key) { - return Arrays.binarySearch(booleanAttributes, key) >= 0; + return Arrays.binarySearch(booleanAttributes, Normalizer.lowerCase(key)) >= 0; } @Override diff --git a/src/test/java/org/jsoup/nodes/AttributeTest.java b/src/test/java/org/jsoup/nodes/AttributeTest.java index 629ed8bf64..454b3bb041 100644 --- a/src/test/java/org/jsoup/nodes/AttributeTest.java +++ b/src/test/java/org/jsoup/nodes/AttributeTest.java @@ -1,6 +1,8 @@ package org.jsoup.nodes; import org.jsoup.Jsoup; +import org.jsoup.parser.ParseSettings; +import org.jsoup.parser.Parser; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -72,4 +74,19 @@ public void html() { oldVal = attr.setValue("foo"); assertEquals("", oldVal); // string, not null } + + @Test void booleanAttributesAreNotCaseSensitive() { + // https://github.com/jhy/jsoup/issues/1656 + assertTrue(Attribute.isBooleanAttribute("required")); + assertTrue(Attribute.isBooleanAttribute("REQUIRED")); + assertTrue(Attribute.isBooleanAttribute("rEQUIREd")); + assertFalse(Attribute.isBooleanAttribute("random string")); + + String html = "One"; + Document doc = Jsoup.parse(html); + assertEquals("One", doc.selectFirst("a").outerHtml()); + + Document doc2 = Jsoup.parse(html, Parser.htmlParser().settings(ParseSettings.preserveCase)); + assertEquals("One", doc2.selectFirst("a").outerHtml()); + } }