dita-ot / dita-ot

DITA Open Toolkit — the open-source publishing engine for content authored in the Darwin Information Typing Architecture.
https://www.dita-ot.org
Apache License 2.0
401 stars 196 forks source link

foreign xlink:href attributes are processed, resulting into NullPointer exception #4480

Open DrRataplan opened 3 months ago

DrRataplan commented 3 months ago

Hey! I am setting up a Dita OT plugin that (among other things) includes some elements in a foreign element that I specialized and I place in a map. This <foreign /> contains some element that has an xlink:href attribute on it.

Expected Behavior

I would expect Dita OT to not process the contents of <foreign /> elements. Just copy over the contents.

Actual Behavior

I am getting a NullPointer exception if I have an xlink:href attribute on an element in a foreign element

Possible Solution

Ignore the contents of foreign elements in the preprocess step. Or ignore anything that is not on a topicref/@href. Or ignore @href in other namespaces than the null one.

Steps to Reproduce

  1. Take the map at https://gist.github.com/DrRataplan/ded9a31559cceb5188f74c53e980c59a
  2. Run it through Dita OT. Try to output XHTML for instance, but this seems to break in an early step.
  3. Observe some errors because of no specialization.
  4. Observe error.

Copy of the error message

See https://gist.github.com/DrRataplan/b768cde94dfc5fc22831d9474c918ca6 The important part is this:

Caused by: java.lang.NullPointerException: Cannot invoke "java.net.URI.toString()" because the return value of "org.dita.dost.writer.DitaWriterFilter.replaceHREF(String, org.xml.sax.Attributes)" is null
    at org.dita.dost.writer.DitaWriterFilter.processAttributes(DitaWriterFilter.java:163)
    at org.dita.dost.writer.DitaWriterFilter.startElement(DitaWriterFilter.java:133)
    at java.xml/org.xml.sax.helpers.XMLFilterImpl.startElement(Unknown Source)

Environment

DrRataplan commented 3 months ago

Error is here: https://github.com/dita-ot/dita-ot/blob/develop/src/main/java/org/dita/dost/writer/DitaWriterFilter.java#L158C1-L159C1

Only the local name is compared, regardless of namespaces. If we test for a URI (https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/org/xml/sax/Attributes.html#getURI(int)) it will only match Q{}href instead of *:href: href without any namespace instead of everything with the localname set to href.

DrRataplan commented 3 months ago

I am up for making a PR to fix it, but I am a bit stuck on how to write a test. I cannot find any direct tests for the DitaWriterFilter class or a good place to start from. I do have a fix ready. I think if we chane to this in the DitaWriterFilter.java file, we're golden:

modified   src/main/java/org/dita/dost/writer/DitaWriterFilter.java
@@ -147,8 +147,14 @@ public final class DitaWriterFilter extends AbstractXMLFilter {
     for (int i = 0; i < attsLen; i++) {
       final String attName = atts.getLocalName(i);
       final String origValue = atts.getValue(i);
+     final String uri = atts.getURI(i);
+
       String attValue = null;
-      if (origValue.equals(ATTR_VALUE_DITA_USE_CONREF_TARGET)) {
+
+      // Ignore anything in a namespace: those are not used in DITA and must be some external element, like xlink:href
+      if (!uri.isEmpty()) {
+         // It is in a namespace. Retain original value.
+      } else if (origValue.equals(ATTR_VALUE_DITA_USE_CONREF_TARGET)) {
         // retain original value
       } else if (ATTRIBUTE_NAME_CONREF.equals(attName)) {
         if (res == null) {

Can you help me out on this?