Repository: dita-ot/dita-ot
Issue: <xsl:message> (in plugin XSLT files) no longer shows element structure

## Expected Behavior
When I add the following XSLT template via a DITA-OT plugin:

```
<xsl:template match="*" priority="1000">
  <xsl:message>BEGIN--<xsl:copy-of select="."/>--END</xsl:message>
  <xsl:next-match/>
</xsl:template>
```

I expect to see XML copies of the elements matched by that template.

## Actual Behavior
In 3.5.4 and earlier releases, I see the XML structure:

```
   [mapref] BEGIN--<keywords xmlns:dita-ot="http://dita-ot.sourceforge.net/ns/201007/dita-ot" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" class="- topic/keywords " xtrc="keywords:1;7:17" xtrf="file:/home/chrispy/BUG/map.ditamap">
   [mapref]         <keyword class="- topic/keyword " xtrc="keyword:1;8:18" xtrf="file:/home/chrispy/BUG/map.ditamap">ProductA</keyword>
   [mapref]       </keywords>--END
   [mapref] BEGIN--<keyword xmlns:dita-ot="http://dita-ot.sourceforge.net/ns/201007/dita-ot" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" class="- topic/keyword " xtrc="keyword:1;8:18" xtrf="file:/home/chrispy/BUG/map.ditamap">ProductA</keyword>--END
```

Starting with 3.6, I see only text node contents:

```
   [mapref] BEGIN--
   [mapref]         ProductA
   [mapref]       --END
   [mapref] BEGIN--ProductA--END
   [mapref] BEGIN----END
```

## Steps to Reproduce
1. Unarchive the attached testcase.
2. Run the `do.sh` script (bash script, for linux environment)
3. In `do.out`, examine the `mapref` messages from 3.5.4 and 3.6.

[BUG.zip](https://github.com/dita-ot/dita-ot/files/5757487/BUG.zip)

## Environment
* DITA-OT version: 3.6
* Operating system and version: Windows 10, running Ubuntu 18.04 LTS via WSL
* Ran via: `dita` command line
*  Transformation type: `dita`


Changed files:
src/test/java/org/dita/dost/util/XMLUtilsTest.java, src/main/java/org/dita/dost/util/XMLUtils.java

diff --git a/src/main/java/org/dita/dost/util/XMLUtils.java b/src/main/java/org/dita/dost/util/XMLUtils.java
index 8cf929206..58e6f800e 100644
--- a/src/main/java/org/dita/dost/util/XMLUtils.java
+++ b/src/main/java/org/dita/dost/util/XMLUtils.java
@@ -11,7 +11,9 @@ import com.google.common.annotations.VisibleForTesting;
 import net.sf.saxon.expr.instruct.TerminationException;
 import net.sf.saxon.lib.*;
 import net.sf.saxon.s9api.*;
+import net.sf.saxon.s9api.streams.Predicates;
 import net.sf.saxon.s9api.streams.Step;
+import net.sf.saxon.s9api.streams.XdmStream;
 import org.apache.xml.resolver.tools.CatalogResolver;
 import org.dita.dost.exception.DITAOTException;
 import org.dita.dost.log.DITAOTLogger;
@@ -31,6 +33,7 @@ import javax.xml.transform.stream.StreamSource;
 import java.io.*;
 import java.net.URI;
 import java.util.*;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX;
@@ -154,7 +157,13 @@ public final class XMLUtils {
                             .findAny()
                             .map(XdmItem::getStringValue)
                             .orElse("INFO");
-                final String msg = content.getStringValue();
+                final String msg = content
+                        .select(descendant(
+                                hasLocalName("level").or(hasLocalName("error-code"))
+                                        .and(hasType(ItemType.PROCESSING_INSTRUCTION_NODE))
+                                .negate()))
+                        .map(n -> n.toString())
+                        .collect(Collectors.joining());
                 switch (level) {
                     case "FATAL":
                         final TerminationException err = new TerminationException(msg);
diff --git a/src/test/java/org/dita/dost/util/XMLUtilsTest.java b/src/test/java/org/dita/dost/util/XMLUtilsTest.java
index 1f1a5ec9d..a9d1687b3 100644
--- a/src/test/java/org/dita/dost/util/XMLUtilsTest.java
+++ b/src/test/java/org/dita/dost/util/XMLUtilsTest.java
@@ -8,8 +8,14 @@
 package org.dita.dost.util;
 
 import net.sf.saxon.Configuration;
+import net.sf.saxon.expr.instruct.TerminationException;
 import net.sf.saxon.lib.CollationURIResolver;
 import net.sf.saxon.om.StructuredQName;
+import net.sf.saxon.s9api.MessageListener2;
+import net.sf.saxon.s9api.SaxonApiException;
+import net.sf.saxon.s9api.SaxonApiUncheckedException;
+import net.sf.saxon.s9api.XdmNode;
+import net.sf.saxon.sapling.Saplings;
 import net.sf.saxon.trans.SymbolicName;
 import org.dita.dost.TestUtils;
 import org.dita.dost.TestUtils.CachingLogger;
@@ -27,18 +33,11 @@ import org.xml.sax.helpers.AttributesImpl;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.StringReader;
-import java.util.Arrays;
 import java.util.Deque;
 import java.util.LinkedList;
+import java.util.List;
 
 import static javax.xml.XMLConstants.NULL_NS_URI;
 import static javax.xml.XMLConstants.XML_NS_URI;
@@ -267,6 +266,105 @@ public class XMLUtilsTest {
         assertTrue(XMLUtils.nonDitaContext(classes));
     }
 
+    @Test
+    public void toMessageListener() throws SaxonApiException {
+        final CachingLogger logger = new CachingLogger();
+        final MessageListener2 listener = XMLUtils.toMessageListener(logger);
+
+        final XdmNode msg = Saplings.doc().withChild(
+                    Saplings.text("message "),
+                    Saplings.elem("debug")
+                )
+                .toXdmNode(new XMLUtils().getProcessor());
+
+        listener.message(msg, null, false, null);
+
+        final List<Message> act = logger.getMessages();
+        assertEquals(1, act.size());
+        assertEquals(new Message(Message.Level.INFO, "message <debug/>", null), act.get(0));
+    }
+
+    @Test
+    public void toMessageListener_withLevelAndErrorCode() throws SaxonApiException {
+        final CachingLogger logger = new CachingLogger();
+        final MessageListener2 listener = XMLUtils.toMessageListener(logger);
+
+        final XdmNode msg = Saplings.doc().withChild(
+                    Saplings.pi("error-code", "DOTX037W"),
+                    Saplings.pi("level", "WARN"),
+                    Saplings.text("message "),
+                    Saplings.elem("debug")
+                )
+                .toXdmNode(new XMLUtils().getProcessor());
+
+        listener.message(msg, null, false, null);
+
+        final List<Message> act = logger.getMessages();
+        assertEquals(1, act.size());
+        assertEquals(new Message(Message.Level.WARN, "message <debug/>", null), act.get(0));
+    }
+
+    @Test
+    public void toMessageListener_withErrorCode() throws SaxonApiException {
+        final CachingLogger logger = new CachingLogger();
+        final MessageListener2 listener = XMLUtils.toMessageListener(logger);
+
+        final XdmNode msg = Saplings.doc().withChild(
+                    Saplings.pi("error-code", "DOTX037W"),
+                    Saplings.text("message "),
+                    Saplings.elem("debug")
+                )
+                .toXdmNode(new XMLUtils().getProcessor());
+
+        listener.message(msg, null, false, null);
+
+        final List<Message> act = logger.getMessages();
+        assertEquals(1, act.size());
+        assertEquals(new Message(Message.Level.INFO, "message <debug/>", null), act.get(0));
+    }
+
+    @Test
+    public void toMessageListener_withFatalErrorCode() throws SaxonApiException {
+        final CachingLogger logger = new CachingLogger();
+        final MessageListener2 listener = XMLUtils.toMessageListener(logger);
+
+        final XdmNode msg = Saplings.doc().withChild(
+                    Saplings.pi("error-code", "DOTX037W"),
+                    Saplings.pi("level", "WARN"),
+                    Saplings.text("message "),
+                    Saplings.elem("debug")
+                )
+                .toXdmNode(new XMLUtils().getProcessor());
+
+        try {
+            listener.message(msg, null, true, null);
+            fail();
+        } catch (SaxonApiUncheckedException e) {
+            final TerminationException cause = (TerminationException) e.getCause();
+            assertEquals("DOTX037W", cause.getErrorCodeLocalPart());
+            assertEquals("message <debug/>", cause.getMessage());
+        }
+    }
+
+    @Test
+    public void toMessageListener_withLevel() throws SaxonApiException {
+        final CachingLogger logger = new CachingLogger();
+        final MessageListener2 listener = XMLUtils.toMessageListener(logger);
+
+        final XdmNode msg = Saplings.doc().withChild(
+                    Saplings.pi("level", "ERROR"),
+                    Saplings.text("message "),
+                    Saplings.elem("debug")
+                )
+                .toXdmNode(new XMLUtils().getProcessor());
+
+        listener.message(msg, null, false, null);
+
+        final List<Message> act = logger.getMessages();
+        assertEquals(1, act.size());
+        assertEquals(new Message(Message.Level.ERROR, "message <debug/>", null), act.get(0));
+    }
+
 //    @Test
 //    public void transform() throws Exception {
 //        copyFile(new File(srcDir, "test.dita"), new File(tempDir, "test.dita"));