This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-doxia.git
The following commit(s) were added to refs/heads/master by this push:
new cf68f3dd [DOXIA-723] Expose document location in Sink (#194)
cf68f3dd is described below
commit cf68f3ddf8bdfafab64703dae4632cfed98e28e4
Author: Konrad Windszus <[email protected]>
AuthorDate: Thu Jan 25 14:23:51 2024 +0100
[DOXIA-723] Expose document location in Sink (#194)
---
.../maven/doxia/parser/AbstractXmlParser.java | 27 ++++++++++++-
.../java/org/apache/maven/doxia/parser/Parser.java | 4 +-
.../maven/doxia/sink/impl/AbstractLocator.java | 38 +++++++++++++++++
.../apache/maven/doxia/sink/impl/AbstractSink.java | 46 +++++++++++++++++++++
.../sink/impl/UniqueAnchorNamesValidator.java | 3 +-
.../maven/doxia/sink/impl/Xhtml5BaseSink.java | 13 +++---
.../apache/maven/doxia/module/apt/AptParser.java | 23 ++++++++++-
.../org/apache/maven/doxia/module/apt/AptSink.java | 7 +++-
.../doxia/module/markdown/MarkdownParser.java | 5 ++-
.../maven/doxia/module/markdown/MarkdownSink.java | 10 +++--
.../org/apache/maven/doxia/sink/EmptyLocator.java | 39 ++++++++++++++++++
.../java/org/apache/maven/doxia/sink/Locator.java | 47 ++++++++++++++++++++++
.../java/org/apache/maven/doxia/sink/Sink.java | 16 ++++++++
13 files changed, 260 insertions(+), 18 deletions(-)
diff --git
a/doxia-core/src/main/java/org/apache/maven/doxia/parser/AbstractXmlParser.java
b/doxia-core/src/main/java/org/apache/maven/doxia/parser/AbstractXmlParser.java
index aa60cb52..92440b30 100644
---
a/doxia-core/src/main/java/org/apache/maven/doxia/parser/AbstractXmlParser.java
+++
b/doxia-core/src/main/java/org/apache/maven/doxia/parser/AbstractXmlParser.java
@@ -39,6 +39,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.maven.doxia.macro.MacroExecutionException;
import org.apache.maven.doxia.markup.XmlMarkup;
import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.impl.AbstractLocator;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.apache.maven.doxia.util.HtmlTools;
import org.apache.maven.doxia.util.XmlValidator;
@@ -135,7 +136,7 @@ public abstract class AbstractXmlParser extends
AbstractParser implements XmlMar
// Note: do it after input is set, otherwise values are reset
initXmlParser(parser);
- parseXml(parser, getWrappedSink(sink));
+ parseXml(parser, getWrappedSink(sink), reference);
} catch (XmlPullParserException ex) {
throw new ParseException("Error parsing the model", ex,
ex.getLineNumber(), ex.getColumnNumber());
} catch (MacroExecutionException ex) {
@@ -185,15 +186,37 @@ public abstract class AbstractXmlParser extends
AbstractParser implements XmlMar
return atts;
}
+ private static final class XmlPullParserLocator extends AbstractLocator {
+
+ private final XmlPullParser parser;
+
+ XmlPullParserLocator(XmlPullParser parser, String reference) {
+ super(reference);
+ this.parser = parser;
+ }
+
+ @Override
+ public int getLineNumber() {
+ return parser.getLineNumber();
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return parser.getColumnNumber() != -1 ? parser.getColumnNumber() +
1 : -1;
+ }
+ }
/**
* Parse the model from the XmlPullParser into the given sink.
*
* @param parser A parser, not null.
* @param sink the sink to receive the events.
+ * @param reference the reference (usually the file path of the parsed
document)
* @throws org.codehaus.plexus.util.xml.pull.XmlPullParserException if
there's a problem parsing the model
* @throws org.apache.maven.doxia.macro.MacroExecutionException if there's
a problem executing a macro
*/
- private void parseXml(XmlPullParser parser, Sink sink) throws
XmlPullParserException, MacroExecutionException {
+ private void parseXml(XmlPullParser parser, Sink sink, String reference)
+ throws XmlPullParserException, MacroExecutionException {
+ sink.setDocumentLocator(new XmlPullParserLocator(parser, reference));
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Parser.java
b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Parser.java
index aecc63d9..4b271867 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Parser.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Parser.java
@@ -45,11 +45,13 @@ public interface Parser {
/**
* Parses the given source model and emits Doxia events into the given
sink.
+ * Shortcut for {@link #parse(Reader, Sink, String)} with last argument
being {@code null}.
*
* @param source not null reader that provides the source document.
* You could use <code>newReader</code> methods from {@link
org.codehaus.plexus.util.ReaderFactory}.
* @param sink A sink that consumes the Doxia events.
* @throws org.apache.maven.doxia.parser.ParseException if the model could
not be parsed.
+ *
*/
void parse(Reader source, Sink sink) throws ParseException;
@@ -59,7 +61,7 @@ public interface Parser {
* @param source not null reader that provides the source document.
* You could use <code>newReader</code> methods from {@link
org.codehaus.plexus.util.ReaderFactory}.
* @param sink A sink that consumes the Doxia events.
- * @param reference the reference
+ * @param reference a string identifying the source (for file based
documents the source file path)
* @throws org.apache.maven.doxia.parser.ParseException if the model could
not be parsed.
*/
void parse(Reader source, Sink sink, String reference) throws
ParseException;
diff --git
a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractLocator.java
b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractLocator.java
new file mode 100644
index 00000000..99f1884c
--- /dev/null
+++
b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractLocator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.doxia.sink.impl;
+
+import org.apache.maven.doxia.sink.Locator;
+
+/**
+ * @since 2.0.0
+ */
+public abstract class AbstractLocator implements Locator {
+
+ private String reference;
+
+ protected AbstractLocator(String reference) {
+ this.reference = reference;
+ }
+
+ @Override
+ public String getReference() {
+ return reference;
+ }
+}
diff --git
a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractSink.java
b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractSink.java
index 0839ad88..4adadfc8 100644
---
a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractSink.java
+++
b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/AbstractSink.java
@@ -19,6 +19,8 @@
package org.apache.maven.doxia.sink.impl;
import org.apache.maven.doxia.markup.Markup;
+import org.apache.maven.doxia.sink.EmptyLocator;
+import org.apache.maven.doxia.sink.Locator;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
@@ -33,6 +35,8 @@ import org.apache.maven.doxia.sink.SinkEventAttributes;
*/
public abstract class AbstractSink implements Sink, Markup {
+ private Locator locator;
+
// -- start default implementation for legacy doxia 1.0 methods which have
overridden variants in Doxia 1.1 or 2.0,
// all sink implementation derived from this must only override the Doxia
> 1.0 variants
@Override
@@ -420,4 +424,46 @@ public abstract class AbstractSink implements Sink, Markup
{
protected void init() {
// nop
}
+
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ @Override
+ public Locator getDocumentLocator() {
+ if (locator == null) {
+ return EmptyLocator.INSTANCE;
+ }
+ return locator;
+ }
+
+ protected String getLocationLogPrefix() {
+ return formatLocation(getDocumentLocator());
+ }
+
+ /**
+ * Creates a string with line/column information. Inspired by
+ * {@code o.a.m.model.building.ModelProblemUtils.formatLocation(...)}.
+ *
+ * @param locator The locator must not be {@code null}.
+ * @return The formatted location or an empty string if unknown, never
{@code null}.
+ */
+ public static String formatLocation(Locator locator) {
+ StringBuilder buffer = new StringBuilder();
+
+ if (locator.getReference() != null) {
+ buffer.append(locator.getReference());
+ }
+ if (locator.getLineNumber() > 0) {
+ buffer.append(", line ").append(locator.getLineNumber());
+ }
+ if (locator.getColumnNumber() > 0) {
+ buffer.append(", column ").append(locator.getLineNumber());
+ }
+ if (buffer.length() > 0) {
+ buffer.append(": ");
+ }
+ return buffer.toString();
+ }
}
diff --git
a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/UniqueAnchorNamesValidator.java
b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/UniqueAnchorNamesValidator.java
index b44ab474..eaf8f4a0 100644
---
a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/UniqueAnchorNamesValidator.java
+++
b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/UniqueAnchorNamesValidator.java
@@ -46,7 +46,8 @@ public class UniqueAnchorNamesValidator extends SinkWrapper {
private void enforceUniqueAnchor(String name) {
if (!usedAnchorNames.add(name)) {
- throw new IllegalStateException("Anchor name \"" + name + "\" used
more than once");
+ throw new IllegalStateException(
+ getLocationLogPrefix() + "Anchor name \"" + name + "\"
used more than once");
}
}
}
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 03693d3a..cdb7d7b8 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
@@ -927,7 +927,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink
implements HtmlMarkup {
}
if (this.tableContentWriterStack.isEmpty()) {
- LOGGER.warn("No table content");
+ LOGGER.warn("{}No table content", getLocationLogPrefix());
return;
}
@@ -1182,7 +1182,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink
implements HtmlMarkup {
if (!DoxiaUtils.isValidId(id)) {
id = DoxiaUtils.encodeId(name);
- LOGGER.debug("Modified invalid anchor name '{}' to '{}'", name,
id);
+ LOGGER.debug("{}Modified invalid anchor name '{}' to '{}'",
getLocationLogPrefix(), name, id);
}
MutableAttributeSet att = new SinkEventAttributeSet();
@@ -1448,7 +1448,8 @@ public class Xhtml5BaseSink extends AbstractXmlSink
implements HtmlMarkup {
}
if (!originalComment.equals(comment)) {
- LOGGER.warn("Modified invalid comment '{}' to '{}'",
originalComment, comment);
+ LOGGER.warn(
+ "{}Modified invalid comment '{}' to '{}'",
getLocationLogPrefix(), originalComment, comment);
}
final StringBuilder buffer = new StringBuilder(comment.length() +
7);
@@ -1505,7 +1506,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink
implements HtmlMarkup {
@Override
public void unknown(String name, Object[] requiredParams,
SinkEventAttributes attributes) {
if (requiredParams == null || !(requiredParams[0] instanceof Integer))
{
- LOGGER.warn("No type information for unknown event '{}',
ignoring!", name);
+ LOGGER.warn("{}No type information for unknown event '{}',
ignoring!", getLocationLogPrefix(), name);
return;
}
@@ -1527,7 +1528,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink
implements HtmlMarkup {
Tag tag = HtmlTools.getHtmlTag(name);
if (tag == null) {
- LOGGER.warn("No HTML tag found for unknown event '{}', ignoring!",
name);
+ LOGGER.warn("[]No HTML tag found for unknown event '{}',
ignoring!", getLocationLogPrefix(), name);
} else {
if (tagType == TAG_TYPE_SIMPLE) {
writeSimpleTag(tag, escapeAttributeValues(attributes));
@@ -1536,7 +1537,7 @@ public class Xhtml5BaseSink extends AbstractXmlSink
implements HtmlMarkup {
} else if (tagType == TAG_TYPE_END) {
writeEndTag(tag);
} else {
- LOGGER.warn("No type information for unknown event '{}',
ignoring!", name);
+ LOGGER.warn("{}No type information for unknown event '{}',
ignoring!", getLocationLogPrefix(), name);
}
}
}
diff --git
a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
index 1df6a41c..52e8ec5a 100644
---
a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
+++
b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
@@ -38,6 +38,7 @@ import org.apache.maven.doxia.parser.AbstractTextParser;
import org.apache.maven.doxia.parser.ParseException;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
+import org.apache.maven.doxia.sink.impl.AbstractLocator;
import org.apache.maven.doxia.sink.impl.SinkAdapter;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.apache.maven.doxia.util.DoxiaUtils;
@@ -180,7 +181,26 @@ public class AptParser extends AbstractTextParser
implements AptMarkup {
/** {@inheritDoc} */
@Override
public void parse(Reader source, Sink sink) throws ParseException {
- parse(source, sink, "");
+ parse(source, sink, null);
+ }
+
+ private static final class AptSourceLocator extends AbstractLocator {
+ private final AptSource aptSource;
+
+ AptSourceLocator(AptSource aptSource, String reference) {
+ super(reference);
+ this.aptSource = aptSource;
+ }
+
+ @Override
+ public int getLineNumber() {
+ return aptSource.getLineNumber() > -1 ? aptSource.getLineNumber()
+ 1 : -1;
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return -1;
+ }
}
/** {@inheritDoc} */
@@ -200,6 +220,7 @@ public class AptParser extends AbstractTextParser
implements AptMarkup {
this.source = new AptReaderSource(new StringReader(sourceContent),
reference);
this.sink = getWrappedSink(sink);
+ sink.setDocumentLocator(new AptSourceLocator(this.source,
reference));
blockFileName = null;
diff --git
a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
index 6a1854cb..fefaf18d 100644
---
a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
+++
b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
@@ -265,7 +265,10 @@ public class AptSink extends AbstractTextSink implements
AptMarkup {
@Override
public void sectionTitle(int level, SinkEventAttributes attributes) {
if (level > 5) {
- LOGGER.warn("Replacing unsupported section title level {} in APT
with level 5", level);
+ LOGGER.warn(
+ "{}Replacing unsupported section title level {} in APT
with level 5",
+ getLocationLogPrefix(),
+ level);
level = 5;
}
if (level == 1) {
@@ -846,7 +849,7 @@ public class AptSink extends AbstractTextSink implements
AptMarkup {
* @see
org.apache.maven.doxia.sink.Sink#unknown(String,Object[],SinkEventAttributes)
*/
public void unknown(String name, Object[] requiredParams,
SinkEventAttributes attributes) {
- LOGGER.warn("Unknown Sink event '{}', ignoring!", name);
+ LOGGER.warn("{}Unknown Sink event '{}', ignoring!",
getLocationLogPrefix(), name);
}
/**
diff --git
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
index 9c229ccf..8534b1a1 100644
---
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
+++
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
@@ -171,8 +171,11 @@ public class MarkdownParser extends AbstractTextParser
implements TextMarkup {
// Markdown to HTML (using flexmark-java library)
String html = toHtml(source);
+ // TODO: add locator for the markdown source (not the intermediate
HTML format)
+ // this requires writing a custom renderer not leveraging the
XHTML parser
+
// then HTML to Sink API
- parser.parse(html, getWrappedSink(sink));
+ parser.parse(html, getWrappedSink(sink), "Intermediate HTML from "
+ reference);
} catch (IOException e) {
throw new ParseException("Failed reading Markdown source
document", e);
}
diff --git
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
index 71d45090..976b4100 100644
---
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
+++
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
@@ -303,7 +303,8 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
// markdown only supports decimal numbering
if (numbering != NUMBERING_DECIMAL) {
LOGGER.warn(
- "Markdown only supports numbered item with decimal style
({}) but requested was style {}, falling back to decimal style",
+ "{}Markdown only supports numbered item with decimal style
({}) but requested was style {}, falling back to decimal style",
+ getLocationLogPrefix(),
NUMBERING_DECIMAL,
numbering);
}
@@ -379,7 +380,8 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void definitionList(SinkEventAttributes attributes) {
- LOGGER.warn("Definition list not natively supported in Markdown,
rendering HTML instead");
+ LOGGER.warn(
+ "{}Definition list not natively supported in Markdown,
rendering HTML instead", getLocationLogPrefix());
writeUnescaped("<dl>" + EOL);
}
@@ -757,7 +759,7 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
ElementContext currentContext = elementContextStack.element();
if (currentContext == ElementContext.TABLE_CAPTION) {
// table caption cannot even be emitted via XHTML in markdown as
there is no suitable location
- LOGGER.warn("Ignoring unsupported table caption in Markdown");
+ LOGGER.warn("{}Ignoring unsupported table caption in Markdown",
getLocationLogPrefix());
} else {
String unifiedText = currentContext.escape(unifyEOLs(text));
writeUnescaped(unifiedText);
@@ -785,7 +787,7 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
*/
@Override
public void unknown(String name, Object[] requiredParams,
SinkEventAttributes attributes) {
- LOGGER.warn("Unknown Sink event '" + name + "', ignoring!");
+ LOGGER.warn("{}Unknown Sink event '" + name + "', ignoring!",
getLocationLogPrefix());
}
/**
diff --git
a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/EmptyLocator.java
b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/EmptyLocator.java
new file mode 100644
index 00000000..e3633e5d
--- /dev/null
+++ b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/EmptyLocator.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.doxia.sink;
+
+public final class EmptyLocator implements Locator {
+
+ public static final Locator INSTANCE = new EmptyLocator();
+
+ @Override
+ public int getLineNumber() {
+ return -1;
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return -1;
+ }
+
+ @Override
+ public String getReference() {
+ return null;
+ }
+}
diff --git
a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Locator.java
b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Locator.java
new file mode 100644
index 00000000..4202a6cc
--- /dev/null
+++ b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Locator.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.doxia.sink;
+
+/**
+ * Interface for associating a {@link Sink} event with a document location.
+ * @since 2.0.0
+ */
+public interface Locator {
+ /**
+ * Returns the underlying source reference (for file based documents a
relative file path, otherwise an arbitrary string or {@code null}).
+ * @return the source for the sink event (may be {@code null})
+ */
+ String getReference();
+
+ /**
+ * Returns the line number for the sink event (starting from 1).
+ * If it is not known returns {@code -1}.
+ *
+ * @return the line number for the sink event
+ */
+ int getLineNumber();
+
+ /**
+ * Returns the column number for the sink event (starting from 1).
+ * If it is not known returns {@code -1}.
+ *
+ * @return the column number for the sink event
+ */
+ int getColumnNumber();
+}
diff --git a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
index 2739eec4..ec4d2833 100644
--- a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
+++ b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
@@ -1749,4 +1749,20 @@ public interface Sink extends AutoCloseable {
* Closing a previously-closed Sink has no effect.
*/
void close();
+
+ /**
+ * Sets the locator which exposes location information for a particular
Sink event.
+ * @param locator the locator (never {@code null}).
+ * @since 2.0.0
+ */
+ default void setDocumentLocator(Locator locator) {}
+
+ /**
+ * Returns the locator which exposes location information for a particular
Sink event.
+ * @return the locator (never {@code null}).
+ * @since 2.0.0
+ */
+ default Locator getDocumentLocator() {
+ return EmptyLocator.INSTANCE;
+ }
}