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