1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package transform;
  25 
  26 import static jaxp.library.JAXPTestUtilities.getSystemProperty;
  27 
  28 import java.io.BufferedReader;
  29 import java.io.ByteArrayInputStream;
  30 import java.io.ByteArrayOutputStream;
  31 import java.io.File;
  32 import java.io.FileNotFoundException;
  33 import java.io.FileReader;
  34 import java.io.IOException;
  35 import java.io.StringReader;
  36 import java.io.StringWriter;
  37 
  38 import javax.xml.parsers.DocumentBuilderFactory;
  39 import javax.xml.parsers.ParserConfigurationException;
  40 import javax.xml.parsers.SAXParserFactory;
  41 import javax.xml.transform.Transformer;
  42 import javax.xml.transform.TransformerException;
  43 import javax.xml.transform.TransformerFactory;
  44 import javax.xml.transform.dom.DOMResult;
  45 import javax.xml.transform.dom.DOMSource;
  46 import javax.xml.transform.sax.SAXSource;
  47 import javax.xml.transform.stream.StreamResult;
  48 import javax.xml.transform.stream.StreamSource;
  49 
  50 import org.testng.Assert;
  51 import org.testng.AssertJUnit;
  52 import org.testng.annotations.Listeners;
  53 import org.testng.annotations.Test;
  54 import org.w3c.dom.Document;
  55 import org.w3c.dom.Element;
  56 import org.w3c.dom.Node;
  57 import org.w3c.dom.NodeList;
  58 import org.xml.sax.ContentHandler;
  59 import org.xml.sax.DTDHandler;
  60 import org.xml.sax.EntityResolver;
  61 import org.xml.sax.ErrorHandler;
  62 import org.xml.sax.InputSource;
  63 import org.xml.sax.SAXException;
  64 import org.xml.sax.SAXNotRecognizedException;
  65 import org.xml.sax.SAXNotSupportedException;
  66 import org.xml.sax.XMLReader;
  67 import org.xml.sax.helpers.AttributesImpl;
  68 
  69 import com.sun.org.apache.xml.internal.serialize.OutputFormat;
  70 import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
  71 
  72 /*
  73  * @test
  74  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  75  * @run testng/othervm -DrunSecMngr=true transform.TransformerTest
  76  * @run testng/othervm transform.TransformerTest
  77  * @summary Transformer Tests
  78  * @bug 6272879 6305029 6505031 8150704 8162598 8169112 8169631 8169772
  79  */
  80 @Listeners({jaxp.library.FilePolicy.class})
  81 public class TransformerTest {
  82 
  83     // some global constants
  84     private static final String LINE_SEPARATOR =
  85         getSystemProperty("line.separator");
  86 
  87     private static final String NAMESPACES =
  88         "http://xml.org/sax/features/namespaces";
  89 
  90     private static final String NAMESPACE_PREFIXES =
  91         "http://xml.org/sax/features/namespace-prefixes";
  92 
  93     private static abstract class TestTemplate {
  94         protected void printSnippet(String title, String snippet) {
  95             StringBuilder div = new StringBuilder();
  96             for (int i = 0; i < title.length(); i++)
  97                 div.append("=");
  98             System.out.println(title + "\n" + div + "\n" + snippet + "\n");
  99         }
 100     }
 101 
 102     /**
 103      * Reads the contents of the given file into a string.
 104      * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one.
 105      *
 106      * @param f
 107      * The file to read
 108      * @return The content of the file as a string, with line terminators as \"n"
 109      * for all platforms
 110      * @throws IOException
 111      * If there was an error reading
 112      */
 113     private String getFileContentAsString(File f) throws IOException {
 114         try (BufferedReader reader = new BufferedReader(new FileReader(f))) {
 115             String line;
 116             StringBuilder sb = new StringBuilder();
 117             while ((line = reader.readLine()) != null) {
 118                 sb.append(line).append("\n");
 119             }
 120             return sb.toString();
 121         }
 122     }
 123 
 124     private class XMLReaderFor6305029 implements XMLReader {
 125         private boolean namespaces = true;
 126         private boolean namespacePrefixes = false;
 127         private EntityResolver resolver;
 128         private DTDHandler dtdHandler;
 129         private ContentHandler contentHandler;
 130         private ErrorHandler errorHandler;
 131 
 132         public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
 133             if (name.equals(NAMESPACES)) {
 134                 return namespaces;
 135             } else if (name.equals(NAMESPACE_PREFIXES)) {
 136                 return namespacePrefixes;
 137             } else {
 138                 throw new SAXNotRecognizedException();
 139             }
 140         }
 141 
 142         public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
 143             if (name.equals(NAMESPACES)) {
 144                 namespaces = value;
 145             } else if (name.equals(NAMESPACE_PREFIXES)) {
 146                 namespacePrefixes = value;
 147             } else {
 148                 throw new SAXNotRecognizedException();
 149             }
 150         }
 151 
 152         public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
 153             return null;
 154         }
 155 
 156         public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
 157         }
 158 
 159         public void setEntityResolver(final EntityResolver theResolver) {
 160             this.resolver = theResolver;
 161         }
 162 
 163         public EntityResolver getEntityResolver() {
 164             return resolver;
 165         }
 166 
 167         public void setDTDHandler(final DTDHandler theHandler) {
 168             dtdHandler = theHandler;
 169         }
 170 
 171         public DTDHandler getDTDHandler() {
 172             return dtdHandler;
 173         }
 174 
 175         public void setContentHandler(final ContentHandler handler) {
 176             contentHandler = handler;
 177         }
 178 
 179         public ContentHandler getContentHandler() {
 180             return contentHandler;
 181         }
 182 
 183         public void setErrorHandler(final ErrorHandler handler) {
 184             errorHandler = handler;
 185         }
 186 
 187         public ErrorHandler getErrorHandler() {
 188             return errorHandler;
 189         }
 190 
 191         public void parse(final InputSource input) throws IOException, SAXException {
 192             parse();
 193         }
 194 
 195         public void parse(final String systemId) throws IOException, SAXException {
 196             parse();
 197         }
 198 
 199         private void parse() throws SAXException {
 200             contentHandler.startDocument();
 201             contentHandler.startPrefixMapping("prefix", "namespaceUri");
 202 
 203             AttributesImpl atts = new AttributesImpl();
 204             if (namespacePrefixes) {
 205                 atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri");
 206             }
 207 
 208             contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts);
 209             contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "");
 210             contentHandler.endPrefixMapping("prefix");
 211             contentHandler.endDocument();
 212         }
 213     }
 214 
 215     /*
 216      * @bug 6272879
 217      * @summary Test for JDK-6272879
 218      */
 219     @Test
 220     public final void testBug6272879() throws IOException, TransformerException {
 221         final String xsl =
 222                 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + LINE_SEPARATOR +
 223                 "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" + LINE_SEPARATOR +
 224                 "<xsl:output method=\"xml\" indent=\"no\" encoding=\"ISO-8859-1\"/>" + LINE_SEPARATOR +
 225                 "<xsl:template match=\"/\">" + LINE_SEPARATOR +
 226                 "<xsl:element name=\"TransformateurXML\">" + LINE_SEPARATOR +
 227                 "  <xsl:for-each select=\"XMLUtils/test\">" + LINE_SEPARATOR +
 228                 "  <xsl:element name=\"test2\">" + LINE_SEPARATOR +
 229                 "    <xsl:element name=\"valeur2\">" + LINE_SEPARATOR +
 230                 "      <xsl:attribute name=\"attribut2\">" + LINE_SEPARATOR +
 231                 "        <xsl:value-of select=\"valeur/@attribut\"/>" + LINE_SEPARATOR +
 232                 "      </xsl:attribute>" + LINE_SEPARATOR +
 233                 "      <xsl:value-of select=\"valeur\"/>" + LINE_SEPARATOR +
 234                 "    </xsl:element>" + LINE_SEPARATOR +
 235                 "  </xsl:element>" + LINE_SEPARATOR +
 236                 "  </xsl:for-each>" + LINE_SEPARATOR +
 237                 "</xsl:element>" + LINE_SEPARATOR +
 238                 "</xsl:template>" + LINE_SEPARATOR +
 239                 "</xsl:stylesheet>";
 240 
 241         final String sourceXml =
 242                 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + LINE_SEPARATOR +
 243                 // "<!DOCTYPE XMLUtils [" + LINE_SEPARATOR +
 244                 // "<!ELEMENT XMLUtils (test*)>" + LINE_SEPARATOR +
 245                 // "<!ELEMENT test (valeur*)>" + LINE_SEPARATOR +
 246                 // "<!ELEMENT valeur (#PCDATA)>" + LINE_SEPARATOR +
 247                 // "<!ATTLIST valeur attribut CDATA #REQUIRED>]>" +
 248                 // LINE_SEPARATOR +
 249                 "<XMLUtils>" + LINE_SEPARATOR +
 250                 "  <test>" + LINE_SEPARATOR +
 251                 "    <valeur attribut=\"Attribut 1\">Valeur 1</valeur>" + LINE_SEPARATOR +
 252                 "  </test>" + LINE_SEPARATOR +
 253                 "  <test>" + LINE_SEPARATOR +
 254                 "    <valeur attribut=\"Attribut 2\">Valeur 2</valeur>" + LINE_SEPARATOR +
 255                 "  </test>" + LINE_SEPARATOR +
 256                 "</XMLUtils>";
 257 
 258         System.out.println("Stylesheet:");
 259         System.out.println("=============================");
 260         System.out.println(xsl);
 261         System.out.println();
 262 
 263         System.out.println("Source before transformation:");
 264         System.out.println("=============================");
 265         System.out.println(sourceXml);
 266         System.out.println();
 267 
 268         // transform to DOM result
 269         TransformerFactory tf = TransformerFactory.newInstance();
 270         Transformer t = tf.newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
 271         DOMResult result = new DOMResult();
 272         t.transform(new StreamSource(new ByteArrayInputStream(sourceXml.getBytes())), result);
 273         Document document = (Document)result.getNode();
 274 
 275         System.out.println("Result after transformation:");
 276         System.out.println("============================");
 277         OutputFormat format = new OutputFormat();
 278         format.setIndenting(true);
 279         new XMLSerializer(System.out, format).serialize(document);
 280         System.out.println();
 281 
 282         System.out.println("Node content for element valeur2:");
 283         System.out.println("=================================");
 284         NodeList nodes = document.getElementsByTagName("valeur2");
 285         for (int i = 0; i < nodes.getLength(); i++) {
 286             Node node = nodes.item(i);
 287             System.out.println("  Node value: " + node.getFirstChild().getNodeValue());
 288             System.out.println("  Node attribute: " + node.getAttributes().item(0).getNodeValue());
 289 
 290             AssertJUnit.assertEquals("Node value mismatch", "Valeur " + (i + 1), node.getFirstChild().getNodeValue());
 291             AssertJUnit.assertEquals("Node attribute mismatch", "Attribut " + (i + 1), node.getAttributes().item(0).getNodeValue());
 292         }
 293     }
 294 
 295     /*
 296      * @bug 6305029
 297      * @summary Test for JDK-6305029
 298      */
 299     @Test
 300     public final void testBug6305029() throws TransformerException {
 301         final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<prefix:localName xmlns:prefix=\"namespaceUri\"/>";
 302 
 303         // test SAXSource
 304         SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource());
 305         StringWriter resultWriter = new StringWriter();
 306         TransformerFactory tf = TransformerFactory.newInstance();
 307         tf.newTransformer().transform(saxSource, new StreamResult(resultWriter));
 308         AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString());
 309 
 310         // test StreamSource
 311         StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT));
 312         resultWriter = new StringWriter();
 313         tf.newTransformer().transform(streamSource, new StreamResult(resultWriter));
 314         AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString());
 315     }
 316 
 317     /*
 318      * @bug 6505031
 319      * @summary Test transformer parses keys and their values coming from different xml documents.
 320      */
 321     @Test
 322     public final void testBug6505031() throws TransformerException {
 323         TransformerFactory tf = TransformerFactory.newInstance();
 324         Transformer t = tf.newTransformer(new StreamSource(getClass().getResource("transform.xsl").toString()));
 325         t.setParameter("config", getClass().getResource("config.xml").toString());
 326         t.setParameter("mapsFile", getClass().getResource("maps.xml").toString());
 327         StringWriter sw = new StringWriter();
 328         t.transform(new StreamSource(getClass().getResource("template.xml").toString()), new StreamResult(sw));
 329         String s = sw.toString();
 330         Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value"));
 331     }
 332 
 333     private static class Test8169631 extends TestTemplate {
 334         private final static String xsl =
 335             "<?xml version=\"1.0\"?>" + LINE_SEPARATOR +
 336             "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" + LINE_SEPARATOR +
 337             "  <xsl:template match=\"/\">" + LINE_SEPARATOR +
 338             "    <xsl:variable name=\"Counter\" select=\"count(//row)\"/>" + LINE_SEPARATOR +
 339             "    <xsl:variable name=\"AttribCounter\" select=\"count(//@attrib)\"/>" + LINE_SEPARATOR +
 340             "    <Counter><xsl:value-of select=\"$Counter\"/></Counter>" + LINE_SEPARATOR +
 341             "    <AttribCounter><xsl:value-of select=\"$AttribCounter\"/></AttribCounter>" + LINE_SEPARATOR +
 342             "  </xsl:template>" + LINE_SEPARATOR +
 343             "</xsl:stylesheet>" + LINE_SEPARATOR;
 344 
 345         private final static String sourceXml =
 346             "<?xml version=\"1.0\"?>" + LINE_SEPARATOR +
 347             "<envelope xmlns=\"http://www.sap.com/myns\" xmlns:sap=\"http://www.sap.com/myns\">" + LINE_SEPARATOR +
 348             "  <sap:row sap:attrib=\"a\">1</sap:row>" + LINE_SEPARATOR +
 349             "  <row attrib=\"b\">2</row>" + LINE_SEPARATOR +
 350             "  <row sap:attrib=\"c\">3</row>" + LINE_SEPARATOR +
 351             "</envelope>" + LINE_SEPARATOR;
 352 
 353         /**
 354          * Utility method to print out transformation result and check values.
 355          *
 356          * @param type
 357          * Text describing type of transformation
 358          * @param result
 359          * Resulting output of transformation
 360          * @param elementCount
 361          * Counter of elements to check
 362          * @param attribCount
 363          * Counter of attributes to check
 364          */
 365         private void verifyResult(String type, String result, int elementCount,
 366                                   int attribCount)
 367         {
 368             printSnippet("Result of transformation from " + type + ":",
 369                          result);
 370             Assert.assertEquals(
 371                 result.contains("<Counter>" + elementCount + "</Counter>"),
 372                 true, "Result of transformation from " + type +
 373                 " should have count of " + elementCount + " elements.");
 374             Assert.assertEquals(
 375                 result.contains("<AttribCounter>" + attribCount +
 376                 "</AttribCounter>"), true, "Result of transformation from " +
 377                 type + " should have count of "+ attribCount + " attributes.");
 378         }
 379 
 380         public void run() throws IOException, TransformerException,
 381             SAXException, ParserConfigurationException
 382         {
 383             printSnippet("Source:", sourceXml);
 384 
 385             printSnippet("Stylesheet:", xsl);
 386 
 387             // create default transformer (namespace aware)
 388             TransformerFactory tf1 = TransformerFactory.newInstance();
 389             ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes());
 390             Transformer t1 = tf1.newTransformer(new StreamSource(bais));
 391 
 392             // test transformation from stream source with namespace support
 393             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 394             bais = new ByteArrayInputStream(sourceXml.getBytes());
 395             t1.transform(new StreamSource(bais), new StreamResult(baos));
 396             verifyResult("StreamSource with namespace support", baos.toString(), 0, 1);
 397 
 398             // test transformation from DOM source with namespace support
 399             bais.reset();
 400             baos.reset();
 401             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 402             dbf.setNamespaceAware(true);
 403             Document doc = dbf.newDocumentBuilder().parse(new InputSource(bais));
 404             t1.transform(new DOMSource(doc), new StreamResult(baos));
 405             verifyResult("DOMSource with namespace support", baos.toString(), 0, 1);
 406 
 407             // test transformation from DOM source without namespace support
 408             bais.reset();
 409             baos.reset();
 410             dbf.setNamespaceAware(false);
 411             doc = dbf.newDocumentBuilder().parse(new InputSource(bais));
 412             t1.transform(new DOMSource(doc), new StreamResult(baos));
 413             verifyResult("DOMSource without namespace support", baos.toString(), 3, 3);
 414 
 415             // test transformation from SAX source with namespace support
 416             bais.reset();
 417             baos.reset();
 418             SAXParserFactory spf = SAXParserFactory.newInstance();
 419             spf.setNamespaceAware(true);
 420             XMLReader xmlr = spf.newSAXParser().getXMLReader();
 421             SAXSource saxS = new SAXSource(xmlr, new InputSource(bais));
 422             t1.transform(saxS, new StreamResult(baos));
 423             verifyResult("SAXSource with namespace support", baos.toString(), 0, 1);
 424 
 425             // test transformation from SAX source without namespace support
 426             bais.reset();
 427             baos.reset();
 428             spf.setNamespaceAware(false);
 429             xmlr = spf.newSAXParser().getXMLReader();
 430             saxS = new SAXSource(xmlr, new InputSource(bais));
 431             t1.transform(saxS, new StreamResult(baos));
 432             verifyResult("SAXSource without namespace support", baos.toString(), 3, 3);
 433         }
 434     }
 435 
 436     /*
 437      * @bug 8169631
 438      * @summary Test combinations of namespace awareness settings on
 439      *          XSL transformations
 440      */
 441     @Test
 442     public final void testBug8169631() throws IOException, SAXException,
 443         TransformerException, ParserConfigurationException
 444     {
 445         new Test8169631().run();
 446     }
 447 
 448     /*
 449      * @bug 8150704
 450      * @summary Test that XSL transformation with lots of temporary result
 451      *          trees will not run out of DTM IDs.
 452      */
 453     @Test
 454     public final void testBug8150704() throws TransformerException, IOException {
 455         System.out.println("Testing transformation of Bug8150704-1.xml...");
 456         TransformerFactory tf = TransformerFactory.newInstance();
 457         Transformer t = tf.newTransformer(new StreamSource(getClass().getResource("Bug8150704-1.xsl").toString()));
 458         StringWriter sw = new StringWriter();
 459         t.transform(new StreamSource(getClass().getResource("Bug8150704-1.xml").toString()), new StreamResult(sw));
 460         String resultstring = sw.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n");
 461         String reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-1.ref").getPath()));
 462         Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-1.xml does not match reference");
 463         System.out.println("Passed.");
 464 
 465         System.out.println("Testing transformation of Bug8150704-2.xml...");
 466         t = tf.newTransformer(new StreamSource(getClass().getResource("Bug8150704-2.xsl").toString()));
 467         sw = new StringWriter();
 468         t.transform(new StreamSource(getClass().getResource("Bug8150704-2.xml").toString()), new StreamResult(sw));
 469         resultstring = sw.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n");
 470         reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-2.ref").getPath()));
 471         Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference");
 472         System.out.println("Passed.");
 473     }
 474 
 475     private static class Test8162598 extends TestTemplate {
 476         private static final String xsl =
 477             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + LINE_SEPARATOR +
 478             "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" + LINE_SEPARATOR +
 479             "    <xsl:template match=\"/\">" + LINE_SEPARATOR +
 480             "        <root xmlns=\"ns1\">" + LINE_SEPARATOR +
 481             "            <xsl:call-template name=\"transform\"/>" + LINE_SEPARATOR +
 482             "        </root>" + LINE_SEPARATOR +
 483             "    </xsl:template>" + LINE_SEPARATOR +
 484             "    <xsl:template name=\"transform\">" + LINE_SEPARATOR +
 485             "        <test1 xmlns=\"ns2\"><b xmlns=\"ns2\"><c xmlns=\"\"></c></b></test1>" + LINE_SEPARATOR +
 486             "        <test2 xmlns=\"ns1\"><b xmlns=\"ns2\"><c xmlns=\"\"></c></b></test2>" + LINE_SEPARATOR +
 487             "        <test3><b><c xmlns=\"\"></c></b></test3>" + LINE_SEPARATOR +
 488             "        <test4 xmlns=\"\"><b><c xmlns=\"\"></c></b></test4>" + LINE_SEPARATOR +
 489             "        <test5 xmlns=\"ns1\"><b><c xmlns=\"\"></c></b></test5>" + LINE_SEPARATOR +
 490             "        <test6 xmlns=\"\"/>" + LINE_SEPARATOR +
 491             "    </xsl:template>" + LINE_SEPARATOR +
 492             "</xsl:stylesheet>";
 493 
 494         private static final String sourceXml =
 495             "<?xml version=\"1.0\" encoding=\"UTF-8\"?><aaa></aaa>" + LINE_SEPARATOR;
 496         /**
 497          * Utility method for testBug8162598().
 498          * Provides a convenient way to check/assert the expected namespaces
 499          * of a Node and its siblings.
 500          *
 501          * @param test
 502          * The node to check
 503          * @param nstest
 504          * Expected namespace of the node
 505          * @param nsb
 506          * Expected namespace of the first sibling
 507          * @param nsc
 508          * Expected namespace of the first sibling of the first sibling
 509          */
 510 
 511         private void checkNodeNS(Node test, String nstest, String nsb, String nsc) {
 512             String testNodeName = test.getNodeName();
 513             if (nstest == null) {
 514                 Assert.assertNull(test.getNamespaceURI(), "unexpected namespace for " + testNodeName);
 515             } else {
 516                 Assert.assertEquals(test.getNamespaceURI(), nstest, "unexpected namespace for " + testNodeName);
 517             }
 518             Node b = test.getChildNodes().item(0);
 519             if (nsb == null) {
 520                 Assert.assertNull(b.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b");
 521             } else {
 522                 Assert.assertEquals(b.getNamespaceURI(), nsb, "unexpected namespace for " + testNodeName + "->b");
 523             }
 524             Node c = b.getChildNodes().item(0);
 525             if (nsc == null) {
 526                 Assert.assertNull(c.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b->c");
 527             } else {
 528                 Assert.assertEquals(c.getNamespaceURI(), nsc, "unexpected namespace for " + testNodeName + "->b->c");
 529             }
 530         }
 531 
 532         public void run()  throws IOException, TransformerException {
 533             printSnippet("Source:", sourceXml);
 534 
 535             printSnippet("Stylesheet:", xsl);
 536 
 537             // transform to DOM result
 538             TransformerFactory tf = TransformerFactory.newInstance();
 539             ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes());
 540             Transformer t = tf.newTransformer(new StreamSource(bais));
 541             DOMResult result = new DOMResult();
 542             bais = new ByteArrayInputStream(sourceXml.getBytes());
 543             t.transform(new StreamSource(bais), result);
 544             Document document = (Document)result.getNode();
 545 
 546             System.out.println("Result after transformation:");
 547             System.out.println("============================");
 548             OutputFormat format = new OutputFormat();
 549             format.setIndenting(true);
 550             new XMLSerializer(System.out, format).serialize(document);
 551             System.out.println();
 552 
 553             checkNodeNS(document.getElementsByTagName("test1").item(0), "ns2", "ns2", null);
 554             checkNodeNS(document.getElementsByTagName("test2").item(0), "ns1", "ns2", null);
 555             checkNodeNS(document.getElementsByTagName("test3").item(0), null, null, null);
 556             checkNodeNS(document.getElementsByTagName("test4").item(0), null, null, null);
 557             checkNodeNS(document.getElementsByTagName("test5").item(0), "ns1", "ns1", null);
 558             Assert.assertNull(document.getElementsByTagName("test6").item(0).getNamespaceURI(),
 559                 "unexpected namespace for test6");
 560         }
 561     }
 562 
 563     /*
 564      * @bug 8162598
 565      * @summary Test XSLTC handling of namespaces, especially empty namespace
 566      *          definitions to reset the default namespace
 567      */
 568     @Test
 569     public final void testBug8162598() throws IOException,
 570         TransformerException
 571     {
 572         new Test8162598().run();
 573     }
 574 
 575     /**
 576      * @bug 8169112
 577      * @summary Test compilation of large xsl file with outlining.
 578      *
 579      * This test merely compiles a large xsl file and tests if its bytecode
 580      * passes verification by invoking the transform() method for
 581      * dummy content. The test succeeds if no Exception is thrown
 582      */
 583     @Test
 584     public final void testBug8169112() throws FileNotFoundException,
 585         TransformerException
 586     {
 587         TransformerFactory tf = TransformerFactory.newInstance();
 588         String xslFile = getClass().getResource("Bug8169112.xsl").toString();
 589         Transformer t = tf.newTransformer(new StreamSource(xslFile));
 590         String xmlIn = "<?xml version=\"1.0\"?><DOCROOT/>";
 591         ByteArrayInputStream bis = new ByteArrayInputStream(xmlIn.getBytes());
 592         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 593         t.transform(new StreamSource(bis), new StreamResult(bos));
 594     }
 595 
 596     /**
 597      * @bug 8169772
 598      * @summary Test transformation of DOM with null valued text node
 599      *
 600      * This test would throw a NullPointerException during transform when the
 601      * fix was not present.
 602      */
 603     @Test
 604     public final void testBug8169772() throws ParserConfigurationException,
 605         SAXException, IOException, TransformerException
 606     {
 607         // create a small DOM
 608         Document doc = DocumentBuilderFactory.newInstance().
 609             newDocumentBuilder().parse(
 610                 new ByteArrayInputStream(
 611                     "<?xml version=\"1.0\"?><DOCROOT/>".getBytes()
 612                 )
 613             );
 614 
 615         // insert a bad element
 616         Element e = doc.createElement("ERROR");
 617         e.appendChild(doc.createTextNode(null));
 618         doc.getDocumentElement().appendChild(e);
 619 
 620         // transform
 621         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 622         TransformerFactory.newInstance().newTransformer().transform(
 623             new DOMSource(doc.getDocumentElement()), new StreamResult(bos)
 624         );
 625         System.out.println("Transformation result (DOM with null text node):");
 626         System.out.println("================================================");
 627         System.out.println(bos);
 628     }
 629 }