changeset 56186:12885822f0c5

8228854: Default ErrorListener reports warnings and errors to the console Reviewed-by: lancea
author joehw
date Thu, 05 Sep 2019 17:26:38 +0000
parents 5f5ca2e02f6e
children 06f3d5092832
files src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java src/java.xml/share/classes/javax/xml/transform/ErrorListener.java src/java.xml/share/classes/javax/xml/transform/package-info.java src/java.xml/share/classes/jdk/xml/internal/TransformErrorListener.java test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java
diffstat 16 files changed, 528 insertions(+), 300 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -54,7 +54,7 @@
  * @author Morten Jorgensen
  * @author G. Todd Miller
  * @author John Howard, JohnH@schemasoft.com
- * @LastModified: Oct 2017
+ * @LastModified: Aug 2019
  */
 public abstract class AbstractTranslet implements Translet {
 
@@ -558,8 +558,8 @@
         throws TransletException
     {
         try {
-            final TransletOutputHandlerFactory factory
-                = TransletOutputHandlerFactory.newInstance(_overrideDefaultParser);
+            final TransletOutputHandlerFactory factory = TransletOutputHandlerFactory
+                    .newInstance(_overrideDefaultParser, _msgHandler.getErrorListener());
 
             String dirStr = new File(filename).getParent();
             if ((null != dirStr) && (dirStr.length() > 0)) {
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,6 +1,5 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -21,11 +20,18 @@
 
 package com.sun.org.apache.xalan.internal.xsltc.runtime;
 
+import javax.xml.transform.ErrorListener;
+
 /**
  * @author Morten Jorgensen
+ * @LastModified: Aug 2019
  */
 public class MessageHandler {
     public void displayMessage(String msg) {
         System.err.println(msg);
     }
+
+    public ErrorListener getErrorListener() {
+        return null;
+    }
 }
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -41,6 +41,7 @@
 import com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler;
 import com.sun.org.apache.xml.internal.serializer.ToXMLStream;
 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
+import javax.xml.transform.ErrorListener;
 import org.w3c.dom.Node;
 
 import org.xml.sax.ContentHandler;
@@ -48,7 +49,7 @@
 
 /**
  * @author Santiago Pericas-Geertsen
- * @LastModified: Oct 2017
+ * @LastModified: Aug 2019
  */
 public class TransletOutputHandlerFactory {
 
@@ -71,16 +72,17 @@
     private LexicalHandler _lexHandler              = null;
 
     private boolean _overrideDefaultParser;
+    private ErrorListener _errListener;
 
-    static public TransletOutputHandlerFactory newInstance() {
-        return new TransletOutputHandlerFactory(true);
-    }
-    static public TransletOutputHandlerFactory newInstance(boolean overrideDefaultParser) {
-        return new TransletOutputHandlerFactory(overrideDefaultParser);
+    static public TransletOutputHandlerFactory newInstance(boolean overrideDefaultParser,
+            ErrorListener errListener) {
+        return new TransletOutputHandlerFactory(overrideDefaultParser, errListener);
     }
 
-    public TransletOutputHandlerFactory(boolean overrideDefaultParser) {
+    public TransletOutputHandlerFactory(boolean overrideDefaultParser,
+            ErrorListener errListener) {
         _overrideDefaultParser = overrideDefaultParser;
+        _errListener = errListener;
     }
     public void setOutputType(int outputType) {
         _outputType = outputType;
@@ -156,24 +158,24 @@
 
                 if (_method == null)
                 {
-                    result = new ToUnknownStream();
+                    result = new ToUnknownStream(_errListener);
                 }
                 else if (_method.equalsIgnoreCase("xml"))
                 {
 
-                    result = new ToXMLStream();
+                    result = new ToXMLStream(_errListener);
 
                 }
                 else if (_method.equalsIgnoreCase("html"))
                 {
 
-                    result = new ToHTMLStream();
+                    result = new ToHTMLStream(_errListener);
 
                 }
                 else if (_method.equalsIgnoreCase("text"))
                 {
 
-                    result = new ToTextStream();
+                    result = new ToTextStream(_errListener);
 
                 }
 
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java	Thu Sep 05 17:26:38 2019 +0000
@@ -74,6 +74,7 @@
 import jdk.xml.internal.JdkXmlFeatures;
 import jdk.xml.internal.JdkXmlUtils;
 import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.TransformErrorListener;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLFilter;
@@ -84,10 +85,10 @@
  * @author G. Todd Miller
  * @author Morten Jorgensen
  * @author Santiago Pericas-Geertsen
- * @LastModified: July 2019
+ * @LastModified: Aug 2019
  */
 public class TransformerFactoryImpl
-    extends SAXTransformerFactory implements SourceLoader, ErrorListener
+    extends SAXTransformerFactory implements SourceLoader
 {
     // Public constants for attributes supported by the XSLTC TransformerFactory.
     public final static String TRANSLET_NAME = "translet-name";
@@ -102,10 +103,15 @@
     public final static String INDENT_NUMBER = "indent-number";
 
     /**
+     * Default error listener
+     */
+    private final ErrorListener _defaultListener = new TransformErrorListener();
+
+    /**
      * This error listener is used only for this factory and is not passed to
      * the Templates or Transformer objects that we create.
      */
-    private ErrorListener _errorListener = this;
+    private ErrorListener _errorListener = _defaultListener;
 
     // flag indicating whether there's an user's ErrorListener
     private boolean _hasUserErrListener;
@@ -1223,90 +1229,6 @@
     }
 
     /**
-     * Receive notification of a recoverable error.
-     * The transformer must continue to provide normal parsing events after
-     * invoking this method. It should still be possible for the application
-     * to process the document through to the end.
-     *
-     * @param e The warning information encapsulated in a transformer
-     * exception.
-     * @throws TransformerException if the application chooses to discontinue
-     * the transformation (always does in our case).
-     */
-    @Override
-    public void error(TransformerException e)
-        throws TransformerException
-    {
-        Throwable wrapped = e.getException();
-        if (wrapped != null) {
-            System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
-                                            e.getMessageAndLocation(),
-                                            wrapped.getMessage()));
-        } else {
-            System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
-                                            e.getMessageAndLocation()));
-        }
-        throw e;
-    }
-
-    /**
-     * Receive notification of a non-recoverable error.
-     * The application must assume that the transformation cannot continue
-     * after the Transformer has invoked this method, and should continue
-     * (if at all) only to collect addition error messages. In fact,
-     * Transformers are free to stop reporting events once this method has
-     * been invoked.
-     *
-     * @param e warning information encapsulated in a transformer
-     * exception.
-     * @throws TransformerException if the application chooses to discontinue
-     * the transformation (always does in our case).
-     */
-    @Override
-    public void fatalError(TransformerException e)
-        throws TransformerException
-    {
-        Throwable wrapped = e.getException();
-        if (wrapped != null) {
-            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
-                                            e.getMessageAndLocation(),
-                                            wrapped.getMessage()));
-        } else {
-            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
-                                            e.getMessageAndLocation()));
-        }
-        throw e;
-    }
-
-    /**
-     * Receive notification of a warning.
-     * Transformers can use this method to report conditions that are not
-     * errors or fatal errors. The default behaviour is to take no action.
-     * After invoking this method, the Transformer must continue with the
-     * transformation. It should still be possible for the application to
-     * process the document through to the end.
-     *
-     * @param e The warning information encapsulated in a transformer
-     * exception.
-     * @throws TransformerException if the application chooses to discontinue
-     * the transformation (never does in our case).
-     */
-    @Override
-    public void warning(TransformerException e)
-        throws TransformerException
-    {
-        Throwable wrapped = e.getException();
-        if (wrapped != null) {
-            System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
-                                            e.getMessageAndLocation(),
-                                            wrapped.getMessage()));
-        } else {
-            System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
-                                            e.getMessageAndLocation()));
-        }
-    }
-
-    /**
      * This method implements XSLTC's SourceLoader interface. It is used to
      * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes.
      *
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java	Thu Sep 05 17:26:38 2019 +0000
@@ -83,6 +83,7 @@
 import javax.xml.transform.stream.StreamSource;
 import jdk.xml.internal.JdkXmlFeatures;
 import jdk.xml.internal.JdkXmlUtils;
+import jdk.xml.internal.TransformErrorListener;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -93,10 +94,10 @@
  * @author Morten Jorgensen
  * @author G. Todd Miller
  * @author Santiago Pericas-Geertsen
- * @LastModified: Feb 2019
+ * @LastModified: Aug 2019
  */
 public final class TransformerImpl extends Transformer
-    implements DOMCache, ErrorListener
+    implements DOMCache
 {
 
     private final static String LEXICAL_HANDLER_PROPERTY =
@@ -129,9 +130,14 @@
     private String _sourceSystemId = null;
 
     /**
+     * Default error listener
+     */
+    private final ErrorListener _defaultListener = new TransformErrorListener();
+
+    /**
      * An error listener for runtime errors.
      */
-    private ErrorListener _errorListener = this;
+    private ErrorListener _errorListener = _defaultListener;
 
     /**
      * A reference to a URI resolver for calls to document().
@@ -250,6 +256,10 @@
                 }
             }
         }
+
+        public ErrorListener getErrorListener() {
+            return _errorListener;
+        }
     }
 
     protected TransformerImpl(Properties outputProperties, int indentNumber,
@@ -264,6 +274,9 @@
         int indentNumber, TransformerFactoryImpl tfactory)
     {
         _translet = (AbstractTranslet) translet;
+        if (_translet != null) {
+            _translet.setMessageHandler(new MessageHandler(_errorListener));
+        }
         _properties = createOutputProperties(outputProperties);
         _propertiesClone = (Properties) _properties.clone();
         _indentNumber = indentNumber;
@@ -400,7 +413,8 @@
         // Get encoding using getProperty() to use defaults
         _encoding = _properties.getProperty(OutputKeys.ENCODING);
 
-        _tohFactory = TransletOutputHandlerFactory.newInstance(_overrideDefaultParser);
+        _tohFactory = TransletOutputHandlerFactory
+                .newInstance(_overrideDefaultParser, _errorListener);
         _tohFactory.setEncoding(_encoding);
         if (_method != null) {
             _tohFactory.setOutputMethod(_method);
@@ -829,8 +843,8 @@
         _errorListener = listener;
 
         // Register a message handler to report xsl:messages
-    if (_translet != null)
-        _translet.setMessageHandler(new MessageHandler(_errorListener));
+        if (_translet != null)
+            _translet.setMessageHandler(new MessageHandler(_errorListener));
     }
 
     /**
@@ -1353,90 +1367,6 @@
     }
 
     /**
-     * Receive notification of a recoverable error.
-     * The transformer must continue to provide normal parsing events after
-     * invoking this method. It should still be possible for the application
-     * to process the document through to the end.
-     *
-     * @param e The warning information encapsulated in a transformer
-     * exception.
-     * @throws TransformerException if the application chooses to discontinue
-     * the transformation (always does in our case).
-     */
-    @Override
-    public void error(TransformerException e)
-        throws TransformerException
-    {
-        Throwable wrapped = e.getException();
-        if (wrapped != null) {
-            System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
-                                            e.getMessageAndLocation(),
-                                            wrapped.getMessage()));
-        } else {
-            System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
-                                            e.getMessageAndLocation()));
-        }
-        throw e;
-    }
-
-    /**
-     * Receive notification of a non-recoverable error.
-     * The application must assume that the transformation cannot continue
-     * after the Transformer has invoked this method, and should continue
-     * (if at all) only to collect addition error messages. In fact,
-     * Transformers are free to stop reporting events once this method has
-     * been invoked.
-     *
-     * @param e The warning information encapsulated in a transformer
-     * exception.
-     * @throws TransformerException if the application chooses to discontinue
-     * the transformation (always does in our case).
-     */
-    @Override
-    public void fatalError(TransformerException e)
-        throws TransformerException
-    {
-        Throwable wrapped = e.getException();
-        if (wrapped != null) {
-            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
-                                            e.getMessageAndLocation(),
-                                            wrapped.getMessage()));
-        } else {
-            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
-                                            e.getMessageAndLocation()));
-        }
-        throw e;
-    }
-
-    /**
-     * Receive notification of a warning.
-     * Transformers can use this method to report conditions that are not
-     * errors or fatal errors. The default behaviour is to take no action.
-     * After invoking this method, the Transformer must continue with the
-     * transformation. It should still be possible for the application to
-     * process the document through to the end.
-     *
-     * @param e The warning information encapsulated in a transformer
-     * exception.
-     * @throws TransformerException if the application chooses to discontinue
-     * the transformation (never does in our case).
-     */
-    @Override
-    public void warning(TransformerException e)
-        throws TransformerException
-    {
-        Throwable wrapped = e.getException();
-        if (wrapped != null) {
-            System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
-                                            e.getMessageAndLocation(),
-                                            wrapped.getMessage()));
-        } else {
-            System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
-                                            e.getMessageAndLocation()));
-        }
-    }
-
-    /**
      * This method resets  the Transformer to its original configuration
      * Transformer code is reset to the same state it was when it was
      * created
@@ -1448,7 +1378,7 @@
         _method = null;
         _encoding = null;
         _sourceSystemId = null;
-        _errorListener = this;
+        _errorListener = _defaultListener;
         _uriResolver = null;
         _dom = null;
         _parameters = null;
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -25,7 +25,7 @@
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Set;
-import java.util.ArrayList;
+import javax.xml.transform.ErrorListener;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.SourceLocator;
 import javax.xml.transform.Transformer;
@@ -42,10 +42,12 @@
  * It contains a number of common fields and methods.
  *
  * @xsl.usage internal
+ * @LastModified: Aug 2019
  */
 public abstract class SerializerBase
     implements SerializationHandler, SerializerConstants
 {
+    protected ErrorListener m_errListener;
 
     /**
      * To fire off the end element trace event
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java	Thu Sep 05 17:26:38 2019 +0000
@@ -30,6 +30,7 @@
 
 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
+import javax.xml.transform.ErrorListener;
 
 /**
  * This serializer takes a series of SAX or
@@ -40,7 +41,7 @@
  * because it is used from another package.
  *
  * @xsl.usage internal
- * @LastModified: July 2019
+ * @LastModified: Aug 2019
  */
 public final class ToHTMLStream extends ToStream
 {
@@ -638,12 +639,15 @@
      */
     public ToHTMLStream()
     {
+        this(null);
+    }
 
-        super();
+    public ToHTMLStream(ErrorListener l)
+    {
+        super(l);
         m_charInfo = m_htmlcharInfo;
         // initialize namespaces
         m_prefixMap = new NamespaceMappings();
-
     }
 
     /** The name of the current element. */
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java	Thu Sep 05 17:26:38 2019 +0000
@@ -51,7 +51,7 @@
  * serializers (xml, html, text ...) that write output to a stream.
  *
  * @xsl.usage internal
- * @LastModified: July 2019
+ * @LastModified: Aug 2019
  */
 abstract public class ToStream extends SerializerBase {
 
@@ -198,7 +198,13 @@
     /**
      * Default constructor
      */
-    public ToStream() { }
+    public ToStream() {
+        this(null);
+    }
+
+    public ToStream(ErrorListener l) {
+        m_errListener = l;
+    }
 
     /**
      * This helper method to writes out "]]>" when closing a CDATA section.
@@ -422,45 +428,30 @@
                        // from what it was
 
                        EncodingInfo encodingInfo = Encodings.getEncodingInfo(newEncoding);
-                       if (newEncoding != null && encodingInfo.name == null) {
-                        // We tried to get an EncodingInfo for Object for the given
-                        // encoding, but it came back with an internall null name
-                        // so the encoding is not supported by the JDK, issue a message.
-                        final String msg = Utils.messages.createMessage(
-                                MsgKey.ER_ENCODING_NOT_SUPPORTED,new Object[]{ newEncoding });
-
-                        final String msg2 =
-                            "Warning: encoding \"" + newEncoding + "\" not supported, using "
-                                   + Encodings.DEFAULT_MIME_ENCODING;
-                        try {
-                                // Prepare to issue the warning message
-                                final Transformer tran = super.getTransformer();
-                                if (tran != null) {
-                                    final ErrorListener errHandler = tran
-                                            .getErrorListener();
-                                    // Issue the warning message
-                                    if (null != errHandler
-                                            && m_sourceLocator != null) {
-                                        errHandler
-                                                .warning(new TransformerException(
-                                                        msg, m_sourceLocator));
-                                        errHandler
-                                                .warning(new TransformerException(
-                                                        msg2, m_sourceLocator));
-                                    } else {
-                                        System.out.println(msg);
-                                        System.out.println(msg2);
-                                    }
-                                } else {
-                                    System.out.println(msg);
-                                    System.out.println(msg2);
+                       if (encodingInfo.name == null) {
+                            // We tried to get an EncodingInfo for Object for the given
+                            // encoding, but it came back with an internall null name
+                            // so the encoding is not supported by the JDK, issue a message.
+                            final String msg = Utils.messages.createMessage(
+                                    MsgKey.ER_ENCODING_NOT_SUPPORTED,new Object[]{ newEncoding });
+
+                            final String msg2 =
+                                "Warning: encoding \"" + newEncoding + "\" not supported, using "
+                                       + Encodings.DEFAULT_MIME_ENCODING;
+                            try {
+                                // refer to JDK-8229005, should throw Exception instead of warning and
+                                // then falling back to the default encoding. Keep it for now.
+                                if (m_errListener != null) {
+                                    m_errListener.warning(new TransformerException(msg, m_sourceLocator));
+                                    m_errListener.warning(new TransformerException(msg2, m_sourceLocator));
                                 }
                             } catch (Exception e) {
                             }
 
                             // We said we are using UTF-8, so use it
                             newEncoding = Encodings.DEFAULT_MIME_ENCODING;
-                            val = Encodings.DEFAULT_MIME_ENCODING; // to store the modified value into the properties a little later
+                            // to store the modified value into the properties a little later
+                            val = Encodings.DEFAULT_MIME_ENCODING;
                             encodingInfo = Encodings.getEncodingInfo(newEncoding);
                         }
                        // The encoding was good, or was forced to UTF-8 above
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,6 +24,7 @@
 
 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
+import javax.xml.transform.ErrorListener;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
@@ -33,7 +34,7 @@
  * This class converts SAX or SAX-like calls to a
  * serialized document for xsl:output method of "text".
  * @xsl.usage internal
- * @LastModified: Sept 2018
+ * @LastModified: Aug 2019
  */
 public final class ToTextStream extends ToStream
 {
@@ -44,7 +45,12 @@
    */
   public ToTextStream()
   {
-    super();
+    this(null);
+  }
+
+  public ToTextStream(ErrorListener l)
+  {
+    super(l);
   }
 
 
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -26,6 +26,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
+import javax.xml.transform.ErrorListener;
 import javax.xml.transform.SourceLocator;
 import javax.xml.transform.Transformer;
 import org.w3c.dom.Node;
@@ -48,7 +49,7 @@
  *
  * This class is not a public API, it is public because it is used within Xalan.
  * @xsl.usage internal
- * @LastModified: Oct 2017
+ * @LastModified: Aug 2019
  */
 public final class ToUnknownStream extends SerializerBase
 {
@@ -116,7 +117,11 @@
      * That may change later to an HTML Stream object.
      */
     public ToUnknownStream() {
-        m_handler = new ToXMLStream();
+        this(null);
+    }
+
+    public ToUnknownStream(ErrorListener l) {
+        m_handler = new ToXMLStream(l);
     }
 
     /**
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java	Thu Sep 05 17:26:38 2019 +0000
@@ -40,7 +40,7 @@
  * be viewed as internal or package private, this is not an API.
  *
  * @xsl.usage internal
- * @LastModified: July 2019
+ * @LastModified: Aug 2019
  */
 public final class ToXMLStream extends ToStream
 {
@@ -64,12 +64,20 @@
      */
     public ToXMLStream()
     {
+        this(null);
+    }
+
+    /**
+     * Default constructor.
+     */
+    public ToXMLStream(ErrorListener l)
+    {
+        super(l);
         m_charInfo = m_xmlcharInfo;
 
         initCDATA();
         // initialize namespaces
         m_prefixMap = new NamespaceMappings();
-
     }
 
     /**
--- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,6 +1,5 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -68,6 +67,7 @@
  * @version $Id:
  *
  * @xsl.usage internal
+ * @LastModified: Aug 2019
  */
 final public class LSSerializerImpl implements DOMConfiguration, LSSerializer {
 
@@ -220,7 +220,7 @@
 
         // Get a serializer that seriailizes according to the properties,
         // which in this case is to xml
-        fXMLSerializer = new ToXMLStream();
+        fXMLSerializer = new ToXMLStream(null);
         fXMLSerializer.setOutputFormat(configProps);
 
         // Initialize Serializer
--- a/src/java.xml/share/classes/javax/xml/transform/ErrorListener.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/javax/xml/transform/ErrorListener.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,29 +26,39 @@
 package javax.xml.transform;
 
 /**
- * <p>To provide customized error handling, implement this interface and
- * use the <code>setErrorListener</code> method to register an instance of the
- * implementation with the {@link javax.xml.transform.Transformer}.  The
- * <code>Transformer</code> then reports all errors and warnings through this
- * interface.</p>
+ * The listener interface used by a {@link TransformerFactory} or {@link Transformer}
+ * to notify callers of error messages that occur during a transformation process.
+ * An ErrorListener receives three levels of messages: warnings, errors and fatal
+ * errors as classified by their severity. Each of them is handled as described
+ * in their respective method.
  *
- * <p>If an application does <em>not</em> register its own custom
- * <code>ErrorListener</code>, the default <code>ErrorListener</code>
- * is used which reports all warnings and errors to <code>System.err</code>
- * and does not throw any <code>Exception</code>s.
- * Applications are <em>strongly</em> encouraged to register and use
- * <code>ErrorListener</code>s that insure proper behavior for warnings and
- * errors.</p>
+ * <p>
+ * An ErrorListener instance can be registered to a {@link TransformerFactory}
+ * or {@link Transformer} through
+ * the {@link TransformerFactory#setErrorListener(ErrorListener)}
+ * or {@link Transformer#setErrorListener(ErrorListener)}
+ * method to receive errors and warnings reported by the TransformerFactory
+ * or Transformer.
  *
- * <p>For transformation errors, a <code>Transformer</code> must use this
- * interface instead of throwing an <code>Exception</code>: it is up to the
- * application to decide whether to throw an <code>Exception</code> for
- * different types of errors and warnings.  Note however that the
- * <code>Transformer</code> is not required to continue with the transformation
- * after a call to {@link #fatalError(TransformerException exception)}.</p>
+ * <p>
+ * When a listener is registered, the {@link TransformerFactory} or {@link Transformer}
+ * must use this interface to pass on all warnings and errors to the listener
+ * and let the application decide how to handle them.
+ * Note that the {@code TransformerFactory} or {@code Transformer} is not
+ * required to continue with the transformation after a call to
+ * {@link #fatalError(TransformerException exception)}.
  *
- * <p><code>Transformer</code>s may use this mechanism to report XML parsing
- * errors as well as transformation errors.</p>
+ * <p>
+ * If an application does not provide a listener, the {@link TransformerFactory}
+ * or {@link Transformer} shall create one on its own. The default {@code ErrorListener}
+ * may take no action for warnings and recoverable errors, and allow the
+ * transformation to continue.
+ * However, the {@code TransformerFactory} or {@code Transformer} may still throw
+ * {@code TransformerException} when it decides it can not continue processing.
+ *
+ * @apiNote It is recommended that applications register and use their own
+ * {@code ErrorListener} to override the default behavior in order to ensure
+ * proper handling of warnings and errors.
  *
  * @since 1.4
  */
--- a/src/java.xml/share/classes/javax/xml/transform/package-info.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/src/java.xml/share/classes/javax/xml/transform/package-info.java	Thu Sep 05 17:26:38 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -183,11 +183,6 @@
  * to report errors that occur during the transformation. The <code>ErrorListener</code>
  * on both objects will always be valid and non-<code>null</code>, whether set by
  * the application or a default implementation provided by the processor.
- * The default implementation provided by the processor will report all warnings
- * and errors to <code>System.err</code> and does not throw any <code>Exception</code>s.
- * Applications are <em>strongly</em> encouraged to register and use
- * <code>ErrorListener</code>s that insure proper behavior for warnings and
- * errors.
  *
  *
  * <h2>Resolution of URIs within a transformation</h2>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.xml/share/classes/jdk/xml/internal/TransformErrorListener.java	Thu Sep 05 17:26:38 2019 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.xml.internal;
+
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.TransformerException;
+
+/**
+ * Implements an ErrorListener for use by the JDK as the default ErrorListener.
+ * For compatibility, this implementation retains the behavior as was implemented
+ * by TransformerFactoryImpl and TransformerImpl where both the error and
+ * fatalError methods re-throw the exception.
+ */
+public class TransformErrorListener implements ErrorListener {
+    /**
+     * Receives notification of a warning.
+     *
+     * @param e The warning information encapsulated in a TransformerException.
+     * @throws TransformerException not thrown in this implementation
+     */
+    @Override
+    public void warning(TransformerException e)
+        throws TransformerException
+    {
+        // no op
+    }
+
+    /**
+     * Receives notification of an error.
+     * The transformer may continue the process if the error is recoverable.
+     * It may decide not to if it can not continue after the error.
+     *
+     * @param e The error information encapsulated in a TransformerException.
+     * @throws TransformerException re-throws the exception.
+     */
+    @Override
+    public void error(TransformerException e)
+        throws TransformerException
+    {
+        throw e;
+    }
+
+    /**
+     * Receives notification of a fatal error.
+     *
+     * @param e The error information encapsulated in a TransformerException.
+     * @throws TransformerException re-throws the exception.
+     */
+    @Override
+    public void fatalError(TransformerException e)
+        throws TransformerException
+    {
+        throw e;
+    }
+}
--- a/test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java	Thu Sep 05 19:24:53 2019 +0200
+++ b/test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java	Thu Sep 05 17:26:38 2019 +0000
@@ -27,92 +27,361 @@
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.PrintStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.xml.transform.ErrorListener;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import org.xml.sax.InputSource;
 
 /*
  * @test
- * @bug 8157830
+ * @bug 8157830 8228854
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  * @run testng/othervm transform.ErrorListenerTest
  * @summary Verifies that ErrorListeners are handled properly
  */
 public class ErrorListenerTest {
+    static final int SYSTEM_ERR = 1;
+    static final int SYSTEM_OUT = 2;
+    static final String ERR_STDERR = "Msg sent to stderr";
+    static final String ERR_STDOUT = "Msg sent to stdout";
 
     static final private String INVALID_STYLESHEET = "xxx";
     static final private String SYSTEM_ID = "http://openjdk_java_net/xsl/dummy.xsl";
 
-    PrintStream original;
+    final private String INCLUDE_NOT_EXIST = "<?xml version=\"1.1\" encoding=\"UTF-8\"?>" +
+        "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" +
+        "    <xsl:import href=\"NOSUCHFILE.xsl\"/>" +
+        "</xsl:stylesheet>";
+
+    final private String VAR_UNDEFINED = "<?xml version=\"1.1\" encoding=\"ISO-8859-1\"?>" +
+        "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
+        "    <xsl:template match=\"/\"> " +
+        "        <test1><xsl:apply-templates select=\"$ids\"/></test1>" +
+        "        <test2><xsl:apply-templates select=\"$dummy//ids/id\"/></test2>" +
+        "    </xsl:template>" +
+        "</xsl:stylesheet>";
+    final private String XSL_DOC_FUNCTION = "<?xml version=\"1.1\" encoding=\"ISO-8859-1\"?>" +
+        "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
+        "    <xsl:output method=\"xml\" indent=\"yes\"/>" +
+        "    <xsl:variable name=\"ids\" select=\"//ids//id\"/>" +
+        "    <xsl:variable name=\"dummy\" select=\"document('NOSUCHFILE.xml')\"/>" +
+        "    <xsl:template match=\"/\"> " +
+        "        <test1><xsl:apply-templates select=\"$ids\"/></test1>" +
+        "        <test2><xsl:apply-templates select=\"$dummy//ids/id\"/></test2>" +
+        "    </xsl:template>" +
+        "    <xsl:template match=\"id\">" +
+        "        <xsl:variable name=\"entity\" select=\"id(@value)\"/> " +
+        "        <must-be-one><xsl:value-of select=\"count($entity)\"/></must-be-one>" +
+        "    </xsl:template>" +
+        "</xsl:stylesheet>";
+    final private String XML_DOC_FUNCTION = "<?xml version=\"1.1\" encoding=\"ISO-8859-1\" standalone=\"no\"?>" +
+        "<organization2>" +
+        "    <company id=\"xca\" count=\"2\">" +
+        "        <department id=\"xda\"/>" +
+        "    </company>" +
+        "    <company id=\"xcb\" count=\"0\"/>" +
+        "    <company id=\"xcc\" count=\"5\"/>" +
+        "    <ids>" +
+        "        <id value=\"xca\"/>" +
+        "        <id value=\"xcb\"/>" +
+        "    </ids>" +
+        "</organization2>";
+
+    PrintStream originalErr, originalOut;
+    List<String> testMsgs = new ArrayList<>();
 
     @BeforeClass
     public void setUpClass() throws Exception {
         // save the PrintStream
-        original = System.err;
+        originalErr = System.err;
+        originalOut = System.out;
     }
 
     @AfterClass
     protected void tearDown() throws Exception {
         // set back to the original
-        System.setErr(original);
+        System.setErr(originalErr);
+        System.setOut(originalOut);
+        // print out test messages
+        testMsgs.stream().forEach((msg) -> {
+            System.out.println(msg);
+        });
+    }
+
+    /*
+       DataProvider: for ErrorListenner tests
+       Data: xsl, xml, setListener(true/false), output channel(stderr/stdout),
+             expected console output, expected listener output
+     */
+    @DataProvider(name = "testCreatingTransformer")
+    public Object[][] getTransformer() {
+        return new Object[][]{
+            /*
+             * Verifies that the default implementation does not print out
+             * warnings and errors to stderr.
+             */
+            {INCLUDE_NOT_EXIST, false, ""},
+            {VAR_UNDEFINED, false, ""},
+            /*
+             * Verifies that the registered listener is used.
+             */
+            {INCLUDE_NOT_EXIST, true, "NOSUCHFILE.xsl"},
+            {VAR_UNDEFINED, true, "'ids' is undefined"},
+            /*
+             * The original test for JDK8157830
+             * Verifies that when an ErrorListener is registered, parser errors
+             * are passed onto the listener without other output.
+            */
+            {INVALID_STYLESHEET, true, "Content is not allowed in prolog"},
+        };
+    }
+    /*
+       DataProvider: for ErrorListenner tests
+       Data: xsl, xml, setListener(true/false), output channel(stderr/stdout),
+             expected console output, expected listener output
+     */
+    @DataProvider(name = "testTransform")
+    public Object[][] getTransform() {
+        return new Object[][]{
+            /*
+             * Verifies that the default implementation does not print out
+             * warnings and errors to stderr.
+             */
+            {XSL_DOC_FUNCTION, XML_DOC_FUNCTION, false, ""},
+            /*
+             * Verifies that the default implementation does not print out
+             * warnings and errors to stderr.
+             */
+            {XSL_DOC_FUNCTION, XML_DOC_FUNCTION, true, "NOSUCHFILE.xml"}
+        };
+    }
+
+    /*
+       DataProvider: for ErrorListenner tests
+       Data: xsl, xml, setListener(true/false), expected listener output
+     */
+    @DataProvider(name = "testEncoding")
+    public Object[][] getData() {
+        return new Object[][]{
+            {"<foo><bar></bar></foo>", false, ""},
+            {"<foo><bar></bar></foo>", true, "'dummy' is not supported"}
+        };
     }
 
     /**
-     * Verifies that when an ErrorListener is registered, parser errors are passed
-     * onto the listener without other output.
+     * Verifies that ErrorListeners are properly set and propagated, or the
+     * default ErrorListener does not send messages to stderr/stdout.
      *
+     * @param xsl the stylesheet
+     * @param setListener a flag indicating whether a listener should be set
+     * @param msgL the expected listener output
+     * @throws Exception if the test fails
+     */
+    @Test(dataProvider = "testCreatingTransformer")
+    public void testTransformer(String xsl, boolean setListener, String msgL)
+            throws Exception {
+        ErrListener listener = setListener ? new ErrListener("test") : null;
+        String msgConsole = getTransformerErr("testTransformer", xsl, listener);
+        evalResult(listener, msgConsole, setListener, msgL);
+    }
+
+    /**
+     * Verifies that ErrorListeners are properly set and propagated, or the
+     * default ErrorListener does not send messages to stderr/stdout.
+     *
+     * @param xsl the stylesheet
+     * @param xml the XML
+     * @param setListener a flag indicating whether a listener should be set
+     * @param msgL the expected listener output
+     * @throws Exception if the test fails
+     */
+    //@Test(dataProvider = "testTransform")
+    public void testTransform(String xsl, String xml, boolean setListener, String msgL)
+            throws Exception {
+        ErrListener listener = setListener ? new ErrListener("test") : null;
+        Transformer t = getTransformer("testDocFunc", xsl, listener);
+        String msgConsole = transform("testDocFunc", xml, t);
+        evalResult(listener, msgConsole, setListener, msgL);
+    }
+
+    /**
+     * Verifies that the default implementation does not print out warnings and
+     * errors to the console when an invalid encoding is set.
+     *
+     * @throws Exception if the test fails
+     */
+    //@Test(dataProvider = "testEncoding")
+    public void testEncoding(String xml, boolean setListener, String msgL)
+            throws Exception {
+        ErrListener listener = setListener ? new ErrListener("test") : null;
+        Transformer t = TransformerFactory.newInstance().newTransformer();
+        if (setListener) {
+            t.setErrorListener(listener);
+        }
+        t.setOutputProperty(OutputKeys.ENCODING, "dummy");
+        String msgConsole = transform("testEncoding", "<foo><bar></bar></foo>", t);
+        evalResult(listener, msgConsole, setListener, msgL);
+    }
+
+    private void evalResult(ErrListener l, String m, boolean setListener, String msgL)
+            throws Exception{
+        Assert.assertTrue(!m.contains(ERR_STDERR), "no output to stderr");
+        Assert.assertTrue(!m.contains(ERR_STDOUT), "no output to stdout");
+        if (setListener) {
+            testMsgs.add("l.errMsg=" + l.errMsg);
+            testMsgs.add("evalResult.msgL=" + msgL);
+            Assert.assertTrue(l.errMsg.contains(msgL),
+                    "The registered listener shall be used.");
+        }
+    }
+
+    /**
+     * Obtains a Transformer.
+     *
+     * @param test the name of the test
+     * @param xsl the stylesheet
+     * @param setListener a flag indicating whether to set a listener
+     * @return the Transformer, null if error occurs
      * @throws Exception
      */
-    @Test
-    public void test() throws Exception {
-        InputStream is = new ByteArrayInputStream(INVALID_STYLESHEET.getBytes());
+    private Transformer getTransformer(String test, String xsl, ErrorListener listener)
+            throws Exception {
+        Transformer f = null;
+        InputSource source = new InputSource(new ByteArrayInputStream(xsl.getBytes()));
+        TransformerFactory factory = TransformerFactory.newInstance();
+        if (listener != null) {
+            factory.setErrorListener(listener);
+        }
+
+        try {
+            f = factory.newTransformer(new SAXSource(source));
+            if (listener != null) {
+                f.setErrorListener(listener);
+            }
+        } catch (TransformerConfigurationException e) {
+            testMsgs.add(test + "::catch: " + e.getMessage());
+        }
+
+        return f;
+    }
+
+    /**
+     * Attempts to capture messages sent to stderr/stdout during the creation
+     * of a Transformer.
+     *
+     * @param test the name of the test
+     * @param xsl the stylesheet
+     * @param setListener a flag indicating whether to set a listener
+     * @return message sent to stderr/stdout, null if none
+     * @throws Exception
+     */
+    private String getTransformerErr(String test, String xsl, ErrorListener listener)
+            throws Exception {
+        InputStream is = new ByteArrayInputStream(xsl.getBytes());
         InputSource source = new InputSource(is);
-        source.setSystemId(SYSTEM_ID);
 
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        PrintStream ps = new PrintStream(baos);
-        System.setErr(ps);
+        ByteArrayOutputStream baos1 = setOutput(SYSTEM_ERR);
+        ByteArrayOutputStream baos2 = setOutput(SYSTEM_OUT);
 
         TransformerFactory factory = TransformerFactory.newInstance();
-        factory.setErrorListener(new ErrListener());
+        if (listener != null) {
+            factory.setErrorListener(listener);
+        }
 
         try {
             factory.newTransformer(new SAXSource(source));
         } catch (TransformerConfigurationException e) {
-            // nothing
+            testMsgs.add(test + "::catch: " + e.getMessage());
         }
+        reset();
+        String msg = !"".equals(baos1.toString()) ? ERR_STDERR : "";
+        msg = !"".equals(baos2.toString()) ? msg + ERR_STDOUT : msg;
+        return msg;
+    }
 
-        // all errors are handled by the ErrorListener, no other output
-        Assert.assertEquals(baos.toString(), "");
+    /**
+     * Transforms an XML file. Attempts to capture stderr/stdout as the Transformer
+     * may direct messages to stdout.
+     *
+     * @param test the name of the test
+     * @param xml the XML file
+     * @param t the Transformer
+     * @param type the flag indicating which output channel to capture
+     * @return message sent to stdout, null if none
+     * @throws Exception
+     */
+    private String transform(String test, String xml, Transformer t)
+            throws Exception {
+        StreamSource source = new StreamSource(new StringReader(xml));
+        StreamResult result = new StreamResult(new StringWriter());
+        ByteArrayOutputStream baos1 = setOutput(SYSTEM_ERR);
+        ByteArrayOutputStream baos2 = setOutput(SYSTEM_OUT);
+        try {
+            t.transform(source, result);
+        } catch (Exception e) {
+            testMsgs.add(test + "::catch: " + e.getMessage());
+        }
+        reset();
+        String msg = !"".equals(baos1.toString()) ? ERR_STDERR : "";
+        msg = !"".equals(baos2.toString()) ? msg + ERR_STDOUT : msg;
+        return msg;
+    }
 
+    private ByteArrayOutputStream setOutput(int type) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        if (type == SYSTEM_ERR) {
+            System.setErr(ps);
+        } else {
+            System.setOut(ps);
+        }
+        return baos;
+    }
+
+    private void reset() {
+        System.setErr(originalErr);
+        System.setOut(originalOut);
     }
 
     class ErrListener implements ErrorListener {
-
-        @Override
-        public void error(TransformerException exception)
-                throws TransformerException {
-            System.out.println("Correctly handled error: " + exception.getMessage());
+        String testName;
+        String errMsg = "";
+        ErrListener(String test) {
+            testName = test;
         }
 
         @Override
-        public void fatalError(TransformerException exception)
+        public void error(TransformerException e)
                 throws TransformerException {
-            System.out.println("Correctly handled fatal: " + exception.getMessage());
+            errMsg = errMsg + "#error: " + e.getMessage();
         }
 
         @Override
-        public void warning(TransformerException exception)
+        public void fatalError(TransformerException e)
                 throws TransformerException {
-            System.out.println("Correctly handled warning: " + exception.getMessage());
+            errMsg = errMsg + "#fatalError: " + e.getMessage();
+        }
+
+        @Override
+        public void warning(TransformerException e)
+                throws TransformerException {
+            errMsg = errMsg + "#warning: " + e.getMessage();
         }
     }
 }