This is an automated email from the ASF dual-hosted git repository. kwin pushed a commit to branch bugfix/convert-all-attributes in repository https://gitbox.apache.org/repos/asf/maven-doxia.git
commit 4c5564a45dc86a1c6c5fccfa50c377a0c1d1866d Author: Konrad Windszus <[email protected]> AuthorDate: Tue Feb 24 17:27:45 2026 +0100 Convert all globally available attributes to HTML5 compliant ones --- .../maven/doxia/sink/impl/AbstractXmlSink.java | 6 +- .../apache/maven/doxia/sink/impl/SinkUtils.java | 1 + .../maven/doxia/sink/impl/Xhtml5BaseSink.java | 207 ++++++++++++--------- .../maven/doxia/sink/impl/Xhtml5BaseSinkTest.java | 64 +++---- 4 files changed, 150 insertions(+), 128 deletions(-) diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractXmlSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractXmlSink.java index f82596ee..cc67ce52 100644 --- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractXmlSink.java +++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractXmlSink.java @@ -103,9 +103,9 @@ public abstract class AbstractXmlSink extends SinkAdapter implements XmlMarkup { * * @param t a non null tag. * @param att a set of attributes. May be null. - * @param isSimpleTag boolean to write as a simple tag. + * @param isEmptyElement boolean to write as tag for an <a href="https://www.w3.org/TR/xml/#d0e2480">empty element</a>. */ - protected void writeStartTag(Tag t, MutableAttributeSet att, boolean isSimpleTag) { + protected void writeStartTag(Tag t, MutableAttributeSet att, boolean isEmptyElement) { Objects.requireNonNull(t, "t cannot be null"); StringBuilder sb = new StringBuilder(); @@ -125,7 +125,7 @@ public abstract class AbstractXmlSink extends SinkAdapter implements XmlMarkup { sb.append(SinkUtils.getAttributeString(att)); - if (isSimpleTag) { + if (isEmptyElement) { sb.append(SPACE).append(SLASH); } diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkUtils.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkUtils.java index 408a5b5a..b6e54204 100644 --- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkUtils.java +++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkUtils.java @@ -217,6 +217,7 @@ public class SinkUtils { public static String asCssDeclaration(String property, String value) { return property + Markup.COLON + Markup.SPACE + value; } + /** * Filters the given AttributeSet. * Removes all attributes whose name (key) is not contained in the sorted array valids. diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java index bc514ccf..b0cae843 100644 --- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java +++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java @@ -267,7 +267,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void article(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.ARTICLE, atts); } @@ -279,7 +279,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void navigation(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.NAV, atts); } @@ -291,7 +291,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void sidebar(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.ASIDE, atts); } @@ -330,7 +330,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { protected void onSection(int depth, SinkEventAttributes attributes) { if (depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_6) { MutableAttributeSet att = new SinkEventAttributeSet(); - att.addAttributes(SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES)); + att.addAttributes(convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES)); writeStartTag(HtmlMarkup.SECTION, att); } @@ -361,7 +361,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { * @see #H6 */ protected void onSectionTitle(int depth, SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); if (depth == SECTION_LEVEL_1) { writeStartTag(HtmlMarkup.H1, atts); @@ -407,7 +407,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void header(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.HEADER, atts); } @@ -419,7 +419,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void content(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); if (contentStack.empty()) { writeStartTag(contentStack.push(HtmlMarkup.MAIN), atts); @@ -450,7 +450,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void footer(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.FOOTER, atts); } @@ -477,7 +477,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { paragraph_(); } - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); writeStartTag(HtmlMarkup.UL, atts); } @@ -497,7 +497,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void listItem(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); writeStartTag(HtmlMarkup.LI, atts); } @@ -546,7 +546,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { } olStyle += ";"; - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); if (atts == null) { atts = new SinkEventAttributeSet(1); @@ -576,7 +576,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void numberedListItem(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); writeStartTag(HtmlMarkup.LI, atts); } @@ -603,7 +603,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { paragraph_(); } - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); writeStartTag(HtmlMarkup.DL, atts); } @@ -623,7 +623,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void definedTerm(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); writeStartTag(HtmlMarkup.DT, atts); } @@ -643,7 +643,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void definition(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); writeStartTag(HtmlMarkup.DD, atts); } @@ -659,7 +659,8 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void figure(SinkEventAttributes attributes) { - writeStartTag(HtmlMarkup.FIGURE, attributes); + MutableAttributeSet filtered = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + writeStartTag(HtmlMarkup.FIGURE, filtered); } @Override @@ -669,7 +670,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void figureGraphics(String src, SinkEventAttributes attributes) { - MutableAttributeSet filtered = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_IMG_ATTRIBUTES); + MutableAttributeSet filtered = convertAndFilterAttributes(attributes, SinkUtils.SINK_IMG_ATTRIBUTES); if (filtered != null) { filtered.removeAttribute(SinkEventAttributes.SRC.toString()); } @@ -686,7 +687,8 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void figureCaption(SinkEventAttributes attributes) { - writeStartTag(HtmlMarkup.FIGCAPTION, attributes); + MutableAttributeSet filtered = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + writeStartTag(HtmlMarkup.FIGCAPTION, filtered); } @Override @@ -702,7 +704,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { public void paragraph(SinkEventAttributes attributes) { paragraphFlag = true; - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.P, atts); } @@ -721,7 +723,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void data(String value, SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); MutableAttributeSet att = new SinkEventAttributeSet(); if (value != null) { @@ -739,7 +741,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void time(String datetime, SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); MutableAttributeSet att = new SinkEventAttributeSet(); if (datetime != null) { @@ -761,7 +763,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void address(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.ADDRESS, atts); } @@ -781,7 +783,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void blockquote(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.BLOCKQUOTE, atts); } @@ -801,7 +803,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void division(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.DIV, atts); } @@ -833,10 +835,12 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { paragraph_(); } - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES); + final MutableAttributeSet atts; - if (atts == null) { + if (attributes == null) { atts = new SinkEventAttributeSet(); + } else { + atts = new SinkEventAttributeSet(attributes); } verbatimMode = VerbatimMode.ON; @@ -848,8 +852,9 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { } atts.removeAttribute(SinkEventAttributes.DECORATION); - - writeStartTag(HtmlMarkup.PRE, atts); + MutableAttributeSet filtered = convertAndFilterAttributes(attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES); + + writeStartTag(HtmlMarkup.PRE, filtered); if (verbatimMode == VerbatimMode.ON_WITH_CODE) { writeStartTag(HtmlMarkup.CODE); } @@ -876,7 +881,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void horizontalRule(SinkEventAttributes attributes) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_HR_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_HR_ATTRIBUTES); writeSimpleTag(HtmlMarkup.HR, atts); } @@ -896,7 +901,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { if (attributes == null) { this.tableAttributes = new SinkEventAttributeSet(0); } else { - this.tableAttributes = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_TABLE_ATTRIBUTES); + this.tableAttributes = convertAndFilterAttributes(attributes, SinkUtils.SINK_TABLE_ATTRIBUTES); } } @@ -991,7 +996,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { */ @Override public void tableRow(SinkEventAttributes attributes) { - MutableAttributeSet attrs = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_TR_ATTRIBUTES); + MutableAttributeSet attrs = convertAndFilterAttributes(attributes, SinkUtils.SINK_TR_ATTRIBUTES); if (attrs == null) { attrs = new SinkEventAttributeSet(); @@ -1046,7 +1051,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { * @see javax.swing.text.html.HTML.Tag#TH * @see javax.swing.text.html.HTML.Tag#TD */ - private void tableCell(boolean headerRow, MutableAttributeSet attributes) { + private void tableCell(boolean headerRow, SinkEventAttributes attributes) { Tag t = (headerRow ? HtmlMarkup.TH : HtmlMarkup.TD); if (!headerRow @@ -1078,7 +1083,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { if (attributes == null) { writeStartTag(t, null); } else { - writeStartTag(t, SinkUtils.filterAttributes(attributes, SinkUtils.SINK_TD_ATTRIBUTES)); + writeStartTag(t, convertAndFilterAttributes(attributes, SinkUtils.SINK_TD_ATTRIBUTES)); } } @@ -1141,7 +1146,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { this.tableCaptionXMLWriterStack.addLast(new PrettyPrintXMLWriter(sw)); // TODO: tableCaption should be written before tableRows (DOXIA-177) - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_SECTION_ATTRIBUTES); writeStartTag(HtmlMarkup.CAPTION, atts); } @@ -1173,7 +1178,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { return; } - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BASE_ATTRIBUTES); String id = name; @@ -1215,7 +1220,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { return; } - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_LINK_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_LINK_ATTRIBUTES); if (atts == null) { atts = new SinkEventAttributeSet(); @@ -1358,61 +1363,6 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { } } - /** - * Some attributes have generally supported values as defined in {@link SinkEventAttributes}. - * This method converts them to their HTML5 compliant equivalent, e.g. the "underline" value of the "decoration" attribute is converted to a style attribute with value "text-decoration-line: underline". - * - * Other attributes with values outsides of the generally supported ones are passed as is (and may not be supported by all HTML output formats). - * @param attributes - * @return a new set of attributes with HTML5 compliant values for the generally supported attribute values - */ - SinkEventAttributes convertToHtml5CompliantAttributes(SinkEventAttributes attributes) { - SinkEventAttributes compliantAttributes = new SinkEventAttributeSet(); - - for (Map.Entry<String, Object> attribute : attributes.entrySet()) { - if (attribute.getKey().equals(SinkEventAttributes.DECORATION)) { - switch (attribute.getValue().toString()) { - case "underline": - addStyle(compliantAttributes, "text-decoration-line", "underline"); - break; - case "overline": - addStyle(compliantAttributes, "text-decoration-line", "overline"); - break; - case "line-through": - addStyle(compliantAttributes, "text-decoration-line", "line-through"); - break; - case "source": - // potentially overwrites other semantics - compliantAttributes.addAttributes(SinkEventAttributeSet.Semantics.CODE); - break; - default: - LOGGER.warn( - "{}Skipping unsupported decoration attribute '{}'", - getLocationLogPrefix(), - attribute.getValue()); - } - } else if (attribute.getKey().equals(SinkEventAttributes.STYLE)) { - switch (attribute.getValue().toString()) { - case "bold": - addStyle(compliantAttributes, "font-weight", "bold"); - break; - case "italic": - addStyle(compliantAttributes, "font-style", "italic"); - break; - case "monospaced": - addStyle(compliantAttributes, "font-family", "monospace"); - break; - default: - // everything else is passed as-is, e.g. "color: red" or "text-decoration: underline" - compliantAttributes.addAttribute(SinkEventAttributes.STYLE, attribute.getValue()); - } - } else { - compliantAttributes.addAttribute(attribute.getKey(), attribute.getValue()); - } - } - return compliantAttributes; - } - /** * Adds a style to the given attributes. If the attributes already contain a style, the new style value is appended to it. * @@ -1515,7 +1465,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { if (headFlag || isVerbatim()) { getTextBuffer().append(EOL); } else { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BR_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BR_ATTRIBUTES); writeSimpleTag(HtmlMarkup.BR, atts); } @@ -1524,7 +1474,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { @Override public void lineBreakOpportunity(SinkEventAttributes attributes) { if (!headFlag && !isVerbatim()) { - MutableAttributeSet atts = SinkUtils.filterAttributes(attributes, SinkUtils.SINK_BR_ATTRIBUTES); + MutableAttributeSet atts = convertAndFilterAttributes(attributes, SinkUtils.SINK_BR_ATTRIBUTES); writeSimpleTag(HtmlMarkup.WBR, atts); } @@ -1778,6 +1728,77 @@ public class Xhtml5BaseSink extends AbstractXmlSink implements HtmlMarkup { return HtmlTools.encodeURL(text); } + /** + * First converts the given attributes to their HTML5 compliant equivalent for the generally supported attribute values, + * then filters the attributes to only include those whose keys are in the given list of valid attribute keys. + * @param attributes + * @param valids + * @return the converted and filtered attributes + * @see #convertToHtml5CompliantAttributes(SinkEventAttributes) + * @see SinkUtils#filterAttributes(SinkEventAttributes, String[]) + */ + protected SinkEventAttributes convertAndFilterAttributes(SinkEventAttributes attributes, String[] valids) { + return SinkUtils.filterAttributes(convertToHtml5CompliantAttributes(attributes), valids); + } + + /** + * Some attributes have generally supported values as defined in {@link SinkEventAttributes}. + * This method converts them to their HTML5 compliant equivalent, e.g. the "underline" value of the "decoration" attribute is converted to a style attribute with value "text-decoration-line: underline". + * + * Other attributes with values outsides of the generally supported ones are passed as is (and may not be supported by all HTML output formats). + * @param attributes + * @return a new set of attributes with HTML5 compliant values for the generally supported attribute values + */ + protected SinkEventAttributes convertToHtml5CompliantAttributes(SinkEventAttributes attributes) { + if (attributes == null) { + return null; + } + SinkEventAttributes compliantAttributes = new SinkEventAttributeSet(); + + for (Map.Entry<String, Object> attribute : attributes.entrySet()) { + if (attribute.getKey().equals(SinkEventAttributes.DECORATION)) { + switch (attribute.getValue().toString()) { + case "underline": + addStyle(compliantAttributes, "text-decoration-line", "underline"); + break; + case "overline": + addStyle(compliantAttributes, "text-decoration-line", "overline"); + break; + case "line-through": + addStyle(compliantAttributes, "text-decoration-line", "line-through"); + break; + case "source": + // potentially overwrites other semantics + compliantAttributes.addAttributes(SinkEventAttributeSet.Semantics.CODE); + break; + default: + LOGGER.warn( + "{}Skipping unsupported decoration attribute '{}'", + getLocationLogPrefix(), + attribute.getValue()); + } + } else if (attribute.getKey().equals(SinkEventAttributes.STYLE)) { + switch (attribute.getValue().toString()) { + case "bold": + addStyle(compliantAttributes, "font-weight", "bold"); + break; + case "italic": + addStyle(compliantAttributes, "font-style", "italic"); + break; + case "monospaced": + addStyle(compliantAttributes, "font-family", "monospace"); + break; + default: + // everything else is passed as-is, e.g. "color: red" or "text-decoration: underline" + compliantAttributes.addAttribute(SinkEventAttributes.STYLE, attribute.getValue()); + } + } else { + compliantAttributes.addAttribute(attribute.getKey(), attribute.getValue()); + } + } + return compliantAttributes; + } + protected void write(String text) { if (!this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null) { this.tableCaptionXMLWriterStack.getLast().writeMarkup(unifyEOLs(text)); diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java index d229c23d..7931b5ce 100644 --- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java +++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java @@ -179,7 +179,7 @@ class Xhtml5BaseSinkTest { sink.article_(); } - assertEquals("<article style=\"bold\"></article>", writer.toString()); + assertEquals("<article style=\"font-weight: bold\"></article>", writer.toString()); } /** @@ -200,7 +200,7 @@ class Xhtml5BaseSinkTest { sink.navigation(attributes); sink.navigation_(); } - assertEquals("<nav style=\"bold\"></nav>", writer.toString()); + assertEquals("<nav style=\"font-weight: bold\"></nav>", writer.toString()); } /** @@ -222,7 +222,7 @@ class Xhtml5BaseSinkTest { sink.sidebar_(); } - assertEquals("<aside style=\"bold\"></aside>", writer.toString()); + assertEquals("<aside style=\"font-weight: bold\"></aside>", writer.toString()); } /** @@ -239,7 +239,7 @@ class Xhtml5BaseSinkTest { sink.section_(level); } - assertEquals("<section style=\"bold\">" + LS + "<h1 style=\"bold\"></h1></section>", writer.toString()); + assertEquals("<section style=\"font-weight: bold\">" + LS + "<h1 style=\"font-weight: bold\"></h1></section>", writer.toString()); } /** @@ -355,7 +355,7 @@ class Xhtml5BaseSinkTest { sink.header_(); } - assertEquals("<header style=\"bold\"></header>", writer.toString()); + assertEquals("<header style=\"font-weight: bold\"></header>", writer.toString()); } /** @@ -382,7 +382,7 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<main style=\"bold\">" + EOL + "<div style=\"bold\" class=\"content\"></div></main>", + "<main style=\"font-weight: bold\">" + EOL + "<div style=\"font-weight: bold\" class=\"content\"></div></main>", writer.toString()); } @@ -405,7 +405,7 @@ class Xhtml5BaseSinkTest { sink.footer_(); } - assertEquals("<footer style=\"bold\"></footer>", writer.toString()); + assertEquals("<footer style=\"font-weight: bold\"></footer>", writer.toString()); } /** @@ -431,7 +431,7 @@ class Xhtml5BaseSinkTest { sink.list_(); } - assertEquals("<ul style=\"bold\">" + LS + "<li style=\"bold\"></li></ul>", writer.toString()); + assertEquals("<ul style=\"font-weight: bold\">" + LS + "<li style=\"font-weight: bold\"></li></ul>", writer.toString()); } /** @@ -460,7 +460,7 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<ol style=\"list-style-type: decimal; bold\">" + LS + "<li style=\"bold\"></li></ol>", + "<ol style=\"list-style-type: decimal; font-weight: bold\">" + LS + "<li style=\"font-weight: bold\"></li></ol>", writer.toString()); } @@ -492,7 +492,7 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<dl style=\"bold\">" + LS + "<dt style=\"bold\"></dt>" + LS + "<dd style=\"bold\"></dd></dl>", + "<dl style=\"font-weight: bold\">" + LS + "<dt style=\"font-weight: bold\"></dt>" + LS + "<dd style=\"font-weight: bold\"></dd></dl>", writer.toString()); } @@ -512,8 +512,8 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<figure style=\"bold\">" + "<img src=\"src.jpg\" style=\"bold\" />" - + "<figcaption style=\"bold\"></figcaption></figure>", + "<figure style=\"font-weight: bold\">" + "<img src=\"src.jpg\" style=\"font-weight: bold\" />" + + "<figcaption style=\"font-weight: bold\"></figcaption></figure>", writer.toString()); } @@ -528,7 +528,7 @@ class Xhtml5BaseSinkTest { sink.figureGraphics(src, attributes); } - assertEquals("<img src=\"source.png\" style=\"bold\" />", writer.toString()); + assertEquals("<img src=\"source.png\" style=\"font-weight: bold\" />", writer.toString()); } /** @@ -550,7 +550,7 @@ class Xhtml5BaseSinkTest { sink.paragraph_(); } - assertEquals("<p style=\"bold\"></p>", writer.toString()); + assertEquals("<p style=\"font-weight: bold\"></p>", writer.toString()); } /** @@ -565,7 +565,7 @@ class Xhtml5BaseSinkTest { sink.data_(); } - assertEquals("<data value=\"value\" style=\"bold\"></data>", writer.toString()); + assertEquals("<data value=\"value\" style=\"font-weight: bold\"></data>", writer.toString()); } /** @@ -580,7 +580,7 @@ class Xhtml5BaseSinkTest { sink.time_(); } - assertEquals("<time datetime=\"datetime\" style=\"bold\"></time>", writer.toString()); + assertEquals("<time datetime=\"datetime\" style=\"font-weight: bold\"></time>", writer.toString()); } /** @@ -602,7 +602,7 @@ class Xhtml5BaseSinkTest { sink.address_(); } - assertEquals("<address style=\"bold\"></address>", writer.toString()); + assertEquals("<address style=\"font-weight: bold\"></address>", writer.toString()); } /** @@ -624,7 +624,7 @@ class Xhtml5BaseSinkTest { sink.blockquote_(); } - assertEquals("<blockquote style=\"bold\"></blockquote>", writer.toString()); + assertEquals("<blockquote style=\"font-weight: bold\"></blockquote>", writer.toString()); } /** @@ -646,7 +646,7 @@ class Xhtml5BaseSinkTest { sink.division_(); } - assertEquals("<div style=\"bold\"></div>", writer.toString()); + assertEquals("<div style=\"font-weight: bold\"></div>", writer.toString()); } /** @@ -661,7 +661,7 @@ class Xhtml5BaseSinkTest { assertEquals("<pre><code></code></pre>", writer.toString()); - checkVerbatimAttributes(attributes, "<pre style=\"bold\"></pre>"); + checkVerbatimAttributes(attributes, "<pre style=\"font-weight: bold\"></pre>"); final SinkEventAttributes att = new SinkEventAttributeSet(SinkEventAttributes.ID, "id"); checkVerbatimAttributes(att, "<pre id=\"id\"></pre>"); @@ -710,7 +710,7 @@ class Xhtml5BaseSinkTest { sink.horizontalRule(attributes); } - assertEquals("<hr /><hr style=\"bold\" />", writer.toString()); + assertEquals("<hr /><hr style=\"font-weight: bold\" />", writer.toString()); } /** @@ -757,7 +757,7 @@ class Xhtml5BaseSinkTest { sink.table_(); } - String xmlExpected = "<table class=\"bodyTable\">" + EOL + "<tr style=\"bold\" class=\"a\"></tr>" + EOL + String xmlExpected = "<table class=\"bodyTable\">" + EOL + "<tr style=\"font-weight: bold\" class=\"a\"></tr>" + EOL + "<tr class=\"b\"></tr></table>"; assertEquals(xmlExpected, writer.toString()); @@ -807,13 +807,13 @@ class Xhtml5BaseSinkTest { StringBuilder expected = new StringBuilder("<table class=\"bodyTable\">"); expected.append(EOL).append("<tr class=\"a\"></tr>").append(EOL); - expected.append("<tr style=\"bold\" class=\"b\"></tr>").append(EOL); + expected.append("<tr style=\"font-weight: bold\" class=\"b\"></tr>").append(EOL); expected.append("<tr class=\"a hidden xyz abc\"></tr>").append(EOL); expected.append("<tr class=\"a abc hidden xyz\"></tr>").append(EOL); expected.append("<tr class=\"a\"></tr>").append(EOL); expected.append("<tr class=\"b not-hidden xyz\"></tr>").append(EOL); expected.append("<tr class=\"a xyz not-hidden\"></tr>").append(EOL); - expected.append("<tr style=\"bold\" class=\"b xyz abc hidden\"></tr>").append(EOL); + expected.append("<tr style=\"font-weight: bold\" class=\"b xyz abc hidden\"></tr>").append(EOL); expected.append("<tr class=\"b xyz hidden-not\"></tr>").append(EOL); expected.append("<tr class=\"a\"></tr></table>"); @@ -831,7 +831,7 @@ class Xhtml5BaseSinkTest { sink.tableCell_(); } - assertEquals("<td style=\"bold\"></td>", writer.toString()); + assertEquals("<td style=\"font-weight: bold\"></td>", writer.toString()); } /** @@ -844,7 +844,7 @@ class Xhtml5BaseSinkTest { sink.tableHeaderCell_(); } - assertEquals("<th style=\"bold\"></th>", writer.toString()); + assertEquals("<th style=\"font-weight: bold\"></th>", writer.toString()); } /** @@ -863,7 +863,7 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<table class=\"bodyTable\">" + "<caption style=\"bold\">caption</caption></table>", writer.toString()); + "<table class=\"bodyTable\">" + "<caption style=\"font-weight: bold\">caption</caption></table>", writer.toString()); } /** @@ -877,7 +877,7 @@ class Xhtml5BaseSinkTest { sink.anchor_(); } - assertEquals("<a id=\"anchor\" style=\"bold\"></a>", writer.toString()); + assertEquals("<a id=\"anchor\" style=\"font-weight: bold\"></a>", writer.toString()); } /** @@ -892,7 +892,7 @@ class Xhtml5BaseSinkTest { sink.link_(); } - assertEquals("<a style=\"bold\" href=\"link.html\"></a>", writer.toString()); + assertEquals("<a style=\"font-weight: bold\" href=\"link.html\"></a>", writer.toString()); } /** @@ -908,7 +908,7 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<a style=\"bold\" class=\"externalLink\" href=\"https://www.apache.org\"></a>", writer.toString()); + "<a style=\"font-weight: bold\" class=\"externalLink\" href=\"https://www.apache.org\"></a>", writer.toString()); } /** @@ -927,7 +927,7 @@ class Xhtml5BaseSinkTest { } assertEquals( - "<a style=\"bold\" class=\"externalLink cs1 cs2\" href=\"https://www.apache.org\"></a>", + "<a style=\"font-weight: bold\" class=\"externalLink cs1 cs2\" href=\"https://www.apache.org\"></a>", writer.toString()); } @@ -1034,7 +1034,7 @@ class Xhtml5BaseSinkTest { sink.nonBreakingSpace(); } - assertEquals("<br style=\"bold\" /><wbr style=\"bold\" /><!-- PB --> ", writer.toString()); + assertEquals("<br style=\"font-weight: bold\" /><wbr style=\"font-weight: bold\" /><!-- PB --> ", writer.toString()); } /**
