8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
authorclanger
Sun, 31 Jul 2016 23:14:27 +0200
changeset 39909 00e4298ae168
parent 39908 c00ecee0e212
child 39910 af46336cbca4
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace Reviewed-by: joehw, dfuchs
jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XslElement.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java	Sun Jul 31 23:14:27 2016 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -9,7 +9,7 @@
  * (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
+ *     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,
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: LiteralElement.java,v 1.2.4.1 2005/09/13 12:38:33 pvedula Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.compiler;
 
@@ -58,8 +55,6 @@
     // names are not known at compile time.
     private boolean _allAttributesUnique = false;
 
-    private final static String XMLNS_STRING = "xmlns";
-
     /**
      * Returns the QName for this literal element
      */
@@ -140,8 +135,8 @@
         // Treat default namespace as "" and not null
         if (prefix == null)
             prefix = Constants.EMPTYSTRING;
-        else if (prefix.equals(XMLNS_STRING))
-            return(XMLNS_STRING);
+        else if (prefix.equals(XMLNS_PREFIX))
+            return(XMLNS_PREFIX);
 
         // Check if we must translate the prefix
         final String alternative = stable.lookupPrefixAlias(prefix);
@@ -264,7 +259,7 @@
                 // Ignore special attributes (e.g. xmlns:prefix and xmlns)
                 final String prefix = qname.getPrefix();
                 if (prefix != null && prefix.equals(XMLNS_PREFIX) ||
-                    prefix == null && qname.getLocalPart().equals("xmlns") ||
+                    prefix == null && qname.getLocalPart().equals(XMLNS_PREFIX) ||
                     uri != null && uri.equals(XSLT_URI))
                 {
                     continue;
@@ -337,9 +332,9 @@
         il.append(methodGen.startElement());
 
         // The value of an attribute may depend on a (sibling) variable
-        int j=0;
+        int j = 0;
         while (j < elementCount())  {
-            final SyntaxTreeNode item = (SyntaxTreeNode) elementAt(j);
+            final SyntaxTreeNode item = elementAt(j);
             if (item instanceof Variable) {
                 item.translate(classGen, methodGen);
             }
@@ -348,35 +343,12 @@
 
         // Compile code to emit namespace attributes
         if (_accessedPrefixes != null) {
-            boolean declaresDefaultNS = false;
-
             for (Map.Entry<String, String> entry : _accessedPrefixes.entrySet()) {
                 final String prefix = entry.getKey();
                 final String uri = entry.getValue();
-
-                if (uri != Constants.EMPTYSTRING ||
-                        prefix != Constants.EMPTYSTRING)
-                {
-                    if (prefix == Constants.EMPTYSTRING) {
-                        declaresDefaultNS = true;
-                    }
-                    il.append(methodGen.loadHandler());
-                    il.append(new PUSH(cpg,prefix));
-                    il.append(new PUSH(cpg,uri));
-                    il.append(methodGen.namespace());
-                }
-            }
-
-            /*
-             * If our XslElement parent redeclares the default NS, and this
-             * element doesn't, it must be redeclared one more time.
-             */
-            if (!declaresDefaultNS && (_parent instanceof XslElement)
-                    && ((XslElement) _parent).declaresDefaultNS())
-            {
                 il.append(methodGen.loadHandler());
-                il.append(new PUSH(cpg, Constants.EMPTYSTRING));
-                il.append(new PUSH(cpg, Constants.EMPTYSTRING));
+                il.append(new PUSH(cpg, prefix));
+                il.append(new PUSH(cpg, uri));
                 il.append(methodGen.namespace());
             }
         }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java	Sun Jul 31 23:14:27 2016 +0200
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: Parser.java,v 1.2.4.1 2005/09/13 12:14:32 pvedula Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.compiler;
 
@@ -72,20 +69,20 @@
  */
 public class Parser implements Constants, ContentHandler {
 
-    private static final String XSL = "xsl";            // standard prefix
+    private static final String XSL = "xsl";           // standard prefix
     private static final String TRANSLET = "translet"; // extension prefix
 
     private Locator _locator = null;
 
-    private XSLTC _xsltc;             // Reference to the compiler object.
-    private XPathParser _xpathParser; // Reference to the XPath parser.
-    private ArrayList<ErrorMsg> _errors;           // Contains all compilation errors
-    private ArrayList<ErrorMsg> _warnings;         // Contains all compilation errors
+    private XSLTC _xsltc;                  // Reference to the compiler object.
+    private XPathParser _xpathParser;      // Reference to the XPath parser.
+    private ArrayList<ErrorMsg> _errors;   // Contains all compilation errors
+    private ArrayList<ErrorMsg> _warnings; // Contains all compilation warnings
 
     private Map<String, String>   _instructionClasses; // Maps instructions to classes
     private Map<String, String[]> _instructionAttrs;  // reqd and opt attrs
-    private Map<String, QName>   _qNames;
-    private Map<String, Map>     _namespaces;
+    private Map<String, QName>    _qNames;
+    private Map<String, Map<String, QName>> _namespaces;
     private QName       _useAttributeSets;
     private QName       _excludeResultPrefixes;
     private QName       _extensionElementPrefixes;
@@ -143,7 +140,6 @@
     public void setOutput(Output output) {
         if (_output != null) {
             if (_output.getImportPrecedence() <= output.getImportPrecedence()) {
-                String cdata = _output.getCdata();
                 output.mergeOutput(_output);
                 _output.disable();
                 _output = output;
@@ -177,12 +173,13 @@
         Object existing = _variableScope.get(var.getName().getStringRep());
         if (existing != null) {
             if (existing instanceof Stack) {
-                Stack stack = (Stack)existing;
+                @SuppressWarnings("unchecked")
+                Stack<VariableBase> stack = (Stack<VariableBase>)existing;
                 stack.push(var);
             }
             else if (existing instanceof VariableBase) {
-                Stack stack = new Stack();
-                stack.push(existing);
+                Stack<VariableBase> stack = new Stack<>();
+                stack.push((VariableBase)existing);
                 stack.push(var);
                 _variableScope.put(var.getName().getStringRep(), stack);
             }
@@ -195,7 +192,8 @@
     public void removeVariable(QName name) {
         Object existing = _variableScope.get(name.getStringRep());
         if (existing instanceof Stack) {
-            Stack stack = (Stack)existing;
+            @SuppressWarnings("unchecked")
+            Stack<VariableBase> stack = (Stack<VariableBase>)existing;
             if (!stack.isEmpty()) stack.pop();
             if (!stack.isEmpty()) return;
         }
@@ -205,13 +203,14 @@
     public VariableBase lookupVariable(QName name) {
         Object existing = _variableScope.get(name.getStringRep());
         if (existing instanceof VariableBase) {
-            return((VariableBase)existing);
+            return (VariableBase)existing;
         }
         else if (existing instanceof Stack) {
-            Stack stack = (Stack)existing;
-            return((VariableBase)stack.peek());
+            @SuppressWarnings("unchecked")
+            Stack<VariableBase> stack = (Stack<VariableBase>)existing;
+            return stack.peek();
         }
-        return(null);
+        return null;
     }
 
     public void setXSLTC(XSLTC xsltc) {
@@ -401,10 +400,9 @@
         try {
             if (stylesheet != null) {
                 stylesheet.parseContents(this);
-                final int precedence = stylesheet.getImportPrecedence();
                 final Iterator<SyntaxTreeNode> elements = stylesheet.elements();
                 while (elements.hasNext()) {
-                    Object child = elements.next();
+                    SyntaxTreeNode child = elements.next();
                     if (child instanceof Text) {
                         final int l = getLineNumber();
                         ErrorMsg err =
@@ -731,8 +729,6 @@
            new String[] {"stylesheet-prefix", "result-prefix"});
     }
 
-
-
     /**
      * Initialize the _instructionClasses map, which maps XSL element
      * names to Java classes in this package.
@@ -806,6 +802,7 @@
     /**
      * Add primops and base functions to the symbol table.
      */
+    @SuppressWarnings("unused")
     private void initSymbolTable() {
         MethodType I_V  = new MethodType(Type.Int, Type.Void);
         MethodType I_R  = new MethodType(Type.Int, Type.Real);
@@ -998,12 +995,12 @@
         String local, Attributes attributes)
     {
         SyntaxTreeNode node = null;
-        QName  qname = getQName(uri, prefix, local);
+        QName qname = getQName(uri, prefix, local);
         String className = _instructionClasses.get(qname.getStringRep());
 
         if (className != null) {
             try {
-                final Class clazz = ObjectFactory.findProviderClass(className, true);
+                final Class<?> clazz = ObjectFactory.findProviderClass(className, true);
                 node = (SyntaxTreeNode)clazz.newInstance();
                 node.setQName(qname);
                 node.setParser(this);
@@ -1050,7 +1047,7 @@
                 else {
                     Stylesheet sheet = _xsltc.getStylesheet();
                     if ((sheet != null) && (sheet.isExtension(uri))) {
-                        if (sheet != (SyntaxTreeNode)_parentStack.peek()) {
+                        if (sheet != _parentStack.peek()) {
                             node = new UnsupportedElement(uri, prefix, local, true);
                             UnsupportedElement elem = (UnsupportedElement)node;
                             ErrorMsg msg =
@@ -1183,7 +1180,6 @@
                     node.setParser(this);
                     node.setParent(parent);
                     node.setLineNumber(line);
-// System.out.println("e = " + text + " " + node);
                     return node;
                 }
             }
@@ -1279,7 +1275,7 @@
 
     /************************ SAX2 ContentHandler INTERFACE *****************/
 
-    private Stack _parentStack = null;
+    private Stack<SyntaxTreeNode> _parentStack = null;
     private Map<String, String> _prefixMapping = null;
 
     /**
@@ -1289,7 +1285,7 @@
         _root = null;
         _target = null;
         _prefixMapping = null;
-        _parentStack = new Stack();
+        _parentStack = new Stack<>();
     }
 
     /**
@@ -1345,7 +1341,7 @@
             _root = element;
         }
         else {
-            SyntaxTreeNode parent = (SyntaxTreeNode)_parentStack.peek();
+            SyntaxTreeNode parent = _parentStack.peek();
             parent.addElement(element);
             element.setParent(parent);
         }
@@ -1376,7 +1372,7 @@
      */
     public void characters(char[] ch, int start, int length) {
         String string = new String(ch, start, length);
-        SyntaxTreeNode parent = (SyntaxTreeNode)_parentStack.peek();
+        SyntaxTreeNode parent = _parentStack.peek();
 
         if (string.length() == 0) return;
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java	Sun Jul 31 23:14:27 2016 +0200
@@ -73,7 +73,7 @@
     protected QName _qname;                    // The element QName
     private int _line;                         // Source file line number
     protected AttributesImpl _attributes = null;   // Attributes of this element
-    private   Map<String, String> _prefixMapping = null; // Namespace declarations
+    private Map<String, String> _prefixMapping = null; // Namespace declarations
 
     // Sentinel - used to denote unrecognised syntaxt tree nodes.
     protected static final SyntaxTreeNode Dummy = new AbsolutePathPattern(null);
@@ -828,7 +828,7 @@
      * @param pos The child node's position.
      * @return The child node.
      */
-    protected final Object elementAt(int pos) {
+    protected final SyntaxTreeNode elementAt(int pos) {
         return _contents.get(pos);
     }
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java	Sun Jul 31 23:14:27 2016 +0200
@@ -154,11 +154,11 @@
     *  Extension function class loader variables
     */
 
-    /* Class loader reference that will be used to external extension functions loading */
+    /* Class loader reference that will be used for external extension functions loading */
     private ClassLoader _extensionClassLoader;
 
     /**
-    *  HashSet with the loaded classes
+    *  HashMap with the loaded classes
     */
     private final Map<String, Class> _externalExtensionFunctions;
 
@@ -295,7 +295,7 @@
     }
 
     /*
-     * Function loads an external external extension functions.
+     * Function loads an external extension function.
      * The filtering of function types (external,internal) takes place in FunctionCall class
      *
      */
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XslElement.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XslElement.java	Sun Jul 31 23:14:27 2016 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -17,16 +17,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: XslElement.java,v 1.2.4.1 2005/09/12 11:39:55 pvedula Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.compiler;
 
 import com.sun.org.apache.bcel.internal.generic.ALOAD;
 import com.sun.org.apache.bcel.internal.generic.ASTORE;
 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
-import com.sun.org.apache.bcel.internal.generic.ICONST;
 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
 import com.sun.org.apache.bcel.internal.generic.InstructionList;
 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
@@ -61,14 +57,6 @@
         displayContents(indent + IndentIncrement);
     }
 
-    /**
-     * This method is now deprecated. The new implemation of this class
-     * never declares the default NS.
-     */
-    public boolean declaresDefaultNS() {
-        return false;
-    }
-
     public void parseContents(Parser parser) {
         final SymbolTable stable = parser.getSymbolTable();
 
@@ -211,7 +199,6 @@
      * on the handler (vii) evaluates the contents (viii) calls endElement().
      */
     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
-        LocalVariableGen local = null;
         final ConstantPoolGen cpg = classGen.getConstantPool();
         final InstructionList il = methodGen.getInstructionList();
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java	Sun Jul 31 23:14:27 2016 +0200
@@ -634,7 +634,7 @@
         }
 
         // Inefficient, but array is small
-        for (int i =0; i < features.length; i++) {
+        for (int i = 0; i < features.length; i++) {
             if (name.equals(features[i])) {
                 return true;
             }
@@ -923,7 +923,7 @@
             String transletClassName = getTransletBaseName(source);
 
             if (_packageName != null)
-               transletClassName = _packageName + "." + transletClassName;
+                transletClassName = _packageName + "." + transletClassName;
 
             if (_jarFileName != null)
                 bytecodes = getBytecodesFromJar(source, transletClassName);
--- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java	Fri Jul 29 09:32:44 2016 -0700
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java	Sun Jul 31 23:14:27 2016 +0200
@@ -62,7 +62,7 @@
 
 /*
  * @summary Transformer Tests
- * @bug 6272879 6305029 6505031 8150704
+ * @bug 6272879 6305029 6505031 8150704 8162598
  */
 public class TransformerTest {
     private Transformer createTransformer() throws TransformerException {
@@ -111,6 +111,41 @@
         }
     }
 
+    /**
+     * Utility method for testBug8162598().
+     * Provides a convenient way to check/assert the expected namespaces
+     * of a Node and its siblings.
+     *
+     * @param test
+     * The node to check
+     * @param nstest
+     * Expected namespace of the node
+     * @param nsb
+     * Expected namespace of the first sibling
+     * @param nsc
+     * Expected namespace of the first sibling of the first sibling
+     */
+    private void checkNodeNS8162598(Node test, String nstest, String nsb, String nsc) {
+        String testNodeName = test.getNodeName();
+        if (nstest == null) {
+            Assert.assertNull(test.getNamespaceURI(), "unexpected namespace for " + testNodeName);
+        } else {
+            Assert.assertEquals(test.getNamespaceURI(), nstest, "unexpected namespace for " + testNodeName);
+        }
+        Node b = test.getChildNodes().item(0);
+        if (nsb == null) {
+            Assert.assertNull(b.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b");
+        } else {
+            Assert.assertEquals(b.getNamespaceURI(), nsb, "unexpected namespace for " + testNodeName + "->b");
+        }
+        Node c = b.getChildNodes().item(0);
+        if (nsc == null) {
+            Assert.assertNull(c.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b->c");
+        } else {
+            Assert.assertEquals(c.getNamespaceURI(), nsc, "unexpected namespace for " + testNodeName + "->b->c");
+        }
+    }
+
     private class XMLReaderFor6305029 implements XMLReader {
         private static final String NAMESPACES = "http://xml.org/sax/features/namespaces";
         private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes";
@@ -249,22 +284,19 @@
                 "  </test>" + LINE_SEPARATOR +
                 "</XMLUtils>";
 
-        Document document;
-        Node node;
-
         System.out.println("Stylesheet:");
-        System.out.println("==================================");
+        System.out.println("=============================");
         System.out.println(xsl);
         System.out.println();
 
-        System.out.println("Source file before transformation:");
-        System.out.println("==================================");
+        System.out.println("Source before transformation:");
+        System.out.println("=============================");
         System.out.println(sourceXml);
         System.out.println();
 
-        System.out.println("Source file after transformation:");
-        System.out.println("=================================");
-        document = transformInputStreamToDocument(createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())),
+        System.out.println("Result after transformation:");
+        System.out.println("============================");
+        Document document = transformInputStreamToDocument(createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())),
             new ByteArrayInputStream(sourceXml.getBytes()));
         OutputFormat format = new OutputFormat();
         format.setIndenting(true);
@@ -274,9 +306,8 @@
         System.out.println("Node content for element valeur2:");
         System.out.println("=================================");
         NodeList nodes = document.getElementsByTagName("valeur2");
-        nodes = document.getElementsByTagName("valeur2");
         for (int i = 0; i < nodes.getLength(); i++) {
-            node = nodes.item(i);
+            Node node = nodes.item(i);
             System.out.println("  Node value: " + node.getFirstChild().getNodeValue());
             System.out.println("  Node attribute: " + node.getAttributes().item(0).getNodeValue());
 
@@ -341,4 +372,62 @@
         Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference");
         System.out.println("Passed.");
     }
+
+    /*
+     * @bug 8162598
+     * @summary Test XSLTC handling of namespaces, especially empty namespace definitions to reset the
+     *          default namespace
+     */
+    @Test
+    public final void testBug8162598() throws IOException, TransformerException {
+        final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+        final String xsl =
+            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + LINE_SEPARATOR +
+            "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" + LINE_SEPARATOR +
+            "    <xsl:template match=\"/\">" + LINE_SEPARATOR +
+            "        <root xmlns=\"ns1\">" + LINE_SEPARATOR +
+            "            <xsl:call-template name=\"transform\"/>" + LINE_SEPARATOR +
+            "        </root>" + LINE_SEPARATOR +
+            "    </xsl:template>" + LINE_SEPARATOR +
+            "    <xsl:template name=\"transform\">" + LINE_SEPARATOR +
+            "        <test1 xmlns=\"ns2\"><b xmlns=\"ns2\"><c xmlns=\"\"></c></b></test1>" + LINE_SEPARATOR +
+            "        <test2 xmlns=\"ns1\"><b xmlns=\"ns2\"><c xmlns=\"\"></c></b></test2>" + LINE_SEPARATOR +
+            "        <test3><b><c xmlns=\"\"></c></b></test3>" + LINE_SEPARATOR +
+            "        <test4 xmlns=\"\"><b><c xmlns=\"\"></c></b></test4>" + LINE_SEPARATOR +
+            "        <test5 xmlns=\"ns1\"><b><c xmlns=\"\"></c></b></test5>" + LINE_SEPARATOR +
+            "        <test6 xmlns=\"\"/>" + LINE_SEPARATOR +
+            "    </xsl:template>" + LINE_SEPARATOR +
+            "</xsl:stylesheet>";
+
+
+        final String sourceXml =
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?><aaa></aaa>" + LINE_SEPARATOR;
+
+        System.out.println("Stylesheet:");
+        System.out.println("=============================");
+        System.out.println(xsl);
+        System.out.println();
+
+        System.out.println("Source before transformation:");
+        System.out.println("=============================");
+        System.out.println(sourceXml);
+        System.out.println();
+
+        System.out.println("Result after transformation:");
+        System.out.println("============================");
+        Document document = transformInputStreamToDocument(
+            createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())),
+                                             new ByteArrayInputStream(sourceXml.getBytes()));
+        OutputFormat format = new OutputFormat();
+        format.setIndenting(true);
+        new XMLSerializer(System.out, format).serialize(document);
+        System.out.println();
+        checkNodeNS8162598(document.getElementsByTagName("test1").item(0), "ns2", "ns2", null);
+        checkNodeNS8162598(document.getElementsByTagName("test2").item(0), "ns1", "ns2", null);
+        checkNodeNS8162598(document.getElementsByTagName("test3").item(0), null, null, null);
+        checkNodeNS8162598(document.getElementsByTagName("test4").item(0), null, null, null);
+        checkNodeNS8162598(document.getElementsByTagName("test5").item(0), "ns1", "ns1", null);
+        Assert.assertNull(document.getElementsByTagName("test6").item(0).getNamespaceURI(), "unexpected namespace for test6");
+    }
 }