This is an automated email from the ASF dual-hosted git repository. kwin pushed a commit to branch bugfix/accept-anchor-with-name-even-in-xhtml5 in repository https://gitbox.apache.org/repos/asf/maven-doxia.git
commit 3487243ff584f440d049cfabeae74aac403f0bc6 Author: Konrad Windszus <[email protected]> AuthorDate: Tue Feb 10 20:27:20 2026 +0100 Support "name" attribute in "a" element still in XHTML5 This is also suggested by https://www.w3.org/TR/html5-diff/#obsolete-attributes: "The following attributes are allowed...: ... The name attribute on a." This closes #1020 --- .../maven/doxia/parser/Xhtml1BaseParser.java | 2 ++ .../maven/doxia/parser/Xhtml5BaseParser.java | 5 ++++ .../maven/doxia/parser/AbstractParserTest.java | 31 ++++++++++++++++++++++ .../maven/doxia/parser/Xhtml5BaseParserTest.java | 12 +++++++++ .../doxia/module/markdown/MarkdownParserTest.java | 29 +++++++------------- 5 files changed, 60 insertions(+), 19 deletions(-) diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml1BaseParser.java b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml1BaseParser.java index a915c812..860f96f4 100644 --- a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml1BaseParser.java +++ b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml1BaseParser.java @@ -118,6 +118,8 @@ public class Xhtml1BaseParser extends Xhtml5BaseParser { private static final Map<String, String> ELEMENT_MAPPING_TABLE = new HashMap<>(); static { + // although obsolete attribute "name" is still allowed, however strongly recommended to be replaced by "id" + // (https://www.w3.org/TR/html5-diff/#obsolete-attributes) ATTRIBUTE_MAPPING_TABLE.put( "a", Collections.singleton(new AttributeMapping("name", "id", AttributeMapping.MergeSemantics.IGNORE))); diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java index 31232f9f..dbfed392 100644 --- a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java +++ b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java @@ -826,6 +826,11 @@ public class Xhtml5BaseParser extends AbstractXmlParser implements HtmlMarkup { isLink = true; } else { String id = (String) attribs.getAttribute(Attribute.ID.toString()); + if (id == null) { + // although the "name" attribute is obsolete in HTML5, it is still allowed + // (https://www.w3.org/TR/html5-diff/#obsolete-attributes) + id = (String) attribs.getAttribute(Attribute.NAME.toString()); + } if (id != null) { sink.anchor(validAnchor(id), attribs); isAnchor = true; diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/parser/AbstractParserTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/parser/AbstractParserTest.java index d90ee119..26bfa9c5 100644 --- a/doxia-core/src/test/java/org/apache/maven/doxia/parser/AbstractParserTest.java +++ b/doxia-core/src/test/java/org/apache/maven/doxia/parser/AbstractParserTest.java @@ -249,6 +249,37 @@ public abstract class AbstractParserTest extends AbstractModuleTest { assertEventSuffix(it); } + /** + * Parse the file and return a {@link SinkEventTestingSink}. + * + * @param file the file to parse with {@link #parser} + * @return a sink to test parsing events + * @throws ParseException if the document parsing failed + * @throws IOException if an I/O error occurs while closing test reader + */ + protected SinkEventTestingSink parseFileToEventTestingSink(String file) throws ParseException, IOException { + SinkEventTestingSink sink; + try (Reader reader = getTestReader(file)) { + sink = new SinkEventTestingSink(); + createParser().parse(reader, sink); + } + return sink; + } + + /** + * Parse the text and return a {@link SinkEventTestingSink}. + * + * @param file the file to parse with {@link #parser} + * @return a sink to test parsing events + * @throws ParseException if the document parsing failed + */ + protected SinkEventTestingSink parseSourceToEventTestingSink(String text) throws ParseException { + SinkEventTestingSink sink; + sink = new SinkEventTestingSink(); + createParser().parse(text, sink); + return sink; + } + public static void assertSinkEquals(SinkEventElement element, String name, Object... args) { assertEquals(name, element.getName(), "Name of element doesn't match"); assertArrayEquals(args, element.getArgs(), "Arguments don't match"); diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java index 5ea893a6..1777e648 100644 --- a/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java +++ b/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java @@ -942,4 +942,16 @@ class Xhtml5BaseParserTest extends AbstractParserTest { protected String getVerbatimCodeSource() { return "<pre><code><>{}=#*</code></pre>"; } + + @Test + void anchorWithName() throws ParseException { + String text = "<a name=\"test\"></a>"; + + parser.parse(text, sink); + + Iterator<SinkEventElement> it = sink.getEventList().iterator(); + // first attribute is the id, second is all given attributes + assertSinkEquals(it.next(), "anchor", "test", new SinkEventAttributeSet("name", "test")); + assertSinkEquals(it, "anchor_"); + } } diff --git a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java index 5d644616..1fad1a69 100644 --- a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java +++ b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java @@ -32,7 +32,6 @@ import org.apache.maven.doxia.parser.ParseException; import org.apache.maven.doxia.sink.SinkEventAttributes; import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet; import org.apache.maven.doxia.sink.impl.SinkEventElement; -import org.apache.maven.doxia.sink.impl.SinkEventTestingSink; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -651,24 +650,6 @@ class MarkdownParserTest extends AbstractParserTest { assertFalse(it.hasNext()); } - /** - * Parse the file and return a {@link SinkEventTestingSink}. - * - * @param file the file to parse with {@link #parser} - * @return a sink to test parsing events - * @throws ParseException if the document parsing failed - * @throws IOException if an I/O error occurs while closing test reader - */ - protected SinkEventTestingSink parseFileToEventTestingSink(String file) throws ParseException, IOException { - SinkEventTestingSink sink; - try (Reader reader = getTestReader(file)) { - sink = new SinkEventTestingSink(); - parser.parse(reader, sink); - } - - return sink; - } - protected String parseFileToHtml(String file) throws ParseException, IOException { try (Reader reader = getTestReader(file)) { return parser.toXhtml(reader).toString(); @@ -897,4 +878,14 @@ class MarkdownParserTest extends AbstractParserTest { protected String getVerbatimCodeSource() { return "```" + EOL + "<>{}=#*" + EOL + "```"; } + + @Test + void anchorWithName() throws ParseException { + Iterator<SinkEventElement> eventIterator = parseSourceToEventTestingSink("<a name=\"my-anchor\">test</a>") + .getEventList() + .iterator(); + assertEventPrefix(eventIterator); + assertSinkStartsWith(eventIterator, "paragraph", "anchor", "text", "anchor_", "paragraph_"); + assertEventSuffix(eventIterator); + } }
