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 com.sun.org.apache.xml.internal.serialize.OutputFormat; 27 import com.sun.org.apache.xml.internal.serialize.XMLSerializer; 28 29 import java.io.BufferedReader; 30 import java.io.ByteArrayInputStream; 31 import java.io.File; 32 import java.io.FileReader; 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.io.StringReader; 36 import java.io.StringWriter; 37 38 import javax.xml.transform.Transformer; 39 import javax.xml.transform.TransformerException; 40 import javax.xml.transform.TransformerFactory; 41 import javax.xml.transform.dom.DOMResult; 42 import javax.xml.transform.sax.SAXSource; 43 import javax.xml.transform.stream.StreamResult; 44 import javax.xml.transform.stream.StreamSource; 45 46 import org.testng.Assert; 47 import org.testng.AssertJUnit; 48 import org.testng.annotations.Test; 49 import org.w3c.dom.Document; 50 import org.w3c.dom.Node; 51 import org.w3c.dom.NodeList; 52 import org.xml.sax.ContentHandler; 53 import org.xml.sax.DTDHandler; 54 import org.xml.sax.EntityResolver; 55 import org.xml.sax.ErrorHandler; 56 import org.xml.sax.InputSource; 57 import org.xml.sax.SAXException; 58 import org.xml.sax.SAXNotRecognizedException; 59 import org.xml.sax.SAXNotSupportedException; 60 import org.xml.sax.XMLReader; 61 import org.xml.sax.helpers.AttributesImpl; 62 63 /* 64 * @summary Transformer Tests 65 * @bug 6272879 6305029 6505031 8150704 66 */ 67 public class TransformerTest { 68 private Transformer createTransformer() throws TransformerException { 69 return TransformerFactory.newInstance().newTransformer(); 70 } 71 72 private Transformer createTransformerFromInputstream(InputStream xslStream) throws TransformerException { 73 return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream)); 74 } 75 76 private Transformer createTransformerFromResource(String xslResource) throws TransformerException { 77 return TransformerFactory.newInstance().newTransformer(new StreamSource(getClass().getResource(xslResource).toString())); 78 } 79 80 private Document transformInputStreamToDocument(Transformer transformer, InputStream sourceStream) throws TransformerException { 81 DOMResult response = new DOMResult(); 82 transformer.transform(new StreamSource(sourceStream), response); 83 return (Document)response.getNode(); 84 } 85 86 private StringWriter transformResourceToStringWriter(Transformer transformer, String xmlResource) throws TransformerException { 87 StringWriter sw = new StringWriter(); 88 transformer.transform(new StreamSource(getClass().getResource(xmlResource).toString()), new StreamResult(sw)); 89 return sw; 90 } 91 92 /** 93 * Reads the contents of the given file into a string. 94 * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one. 95 * 96 * @param f 97 * The file to read 98 * @return The content of the file as a string, with line terminators as \"n" 99 * for all platforms 100 * @throws IOException 101 * If there was an error reading 102 */ 103 private String getFileContentAsString(File f) throws IOException { 104 try (BufferedReader reader = new BufferedReader(new FileReader(f))) { 105 String line; 106 StringBuilder sb = new StringBuilder(); 107 while ((line = reader.readLine()) != null) { 108 sb.append(line).append("\n"); 109 } 110 return sb.toString(); 111 } 112 } 113 114 private class XMLReaderFor6305029 implements XMLReader { 115 private static final String NAMESPACES = "http://xml.org/sax/features/namespaces"; 116 private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; 117 private boolean namespaces = true; 118 private boolean namespacePrefixes = false; 119 private EntityResolver resolver; 120 private DTDHandler dtdHandler; 121 private ContentHandler contentHandler; 122 private ErrorHandler errorHandler; 123 124 public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { 125 if (name.equals(NAMESPACES)) { 126 return namespaces; 127 } else if (name.equals(NAMESPACE_PREFIXES)) { 128 return namespacePrefixes; 129 } else { 130 throw new SAXNotRecognizedException(); 131 } 132 } 133 134 public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { 135 if (name.equals(NAMESPACES)) { 136 namespaces = value; 137 } else if (name.equals(NAMESPACE_PREFIXES)) { 138 namespacePrefixes = value; 139 } else { 140 throw new SAXNotRecognizedException(); 141 } 142 } 143 144 public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { 145 return null; 146 } 147 148 public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException { 149 } 150 151 public void setEntityResolver(final EntityResolver theResolver) { 152 this.resolver = theResolver; 153 } 154 155 public EntityResolver getEntityResolver() { 156 return resolver; 157 } 158 159 public void setDTDHandler(final DTDHandler theHandler) { 160 dtdHandler = theHandler; 161 } 162 163 public DTDHandler getDTDHandler() { 164 return dtdHandler; 165 } 166 167 public void setContentHandler(final ContentHandler handler) { 168 contentHandler = handler; 169 } 170 171 public ContentHandler getContentHandler() { 172 return contentHandler; 173 } 174 175 public void setErrorHandler(final ErrorHandler handler) { 176 errorHandler = handler; 177 } 178 179 public ErrorHandler getErrorHandler() { 180 return errorHandler; 181 } 182 183 public void parse(final InputSource input) throws IOException, SAXException { 184 parse(); 185 } 186 187 public void parse(final String systemId) throws IOException, SAXException { 188 parse(); 189 } 190 191 private void parse() throws SAXException { 192 contentHandler.startDocument(); 193 contentHandler.startPrefixMapping("prefix", "namespaceUri"); 194 195 AttributesImpl atts = new AttributesImpl(); 196 if (namespacePrefixes) { 197 atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri"); 198 } 199 200 contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts); 201 contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : ""); 202 contentHandler.endPrefixMapping("prefix"); 203 contentHandler.endDocument(); 204 } 205 } 206 207 /* 208 * @bug 6272879 209 * @summary Test for JDK-6272879 210 */ 211 @Test 212 public final void testBug6272879() throws IOException, TransformerException { 213 final String LINE_SEPARATOR = System.getProperty("line.separator"); 214 215 final String xsl = 216 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + LINE_SEPARATOR + 217 "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" + LINE_SEPARATOR + 218 "<xsl:output method=\"xml\" indent=\"no\" encoding=\"ISO-8859-1\"/>" + LINE_SEPARATOR + 219 "<xsl:template match=\"/\">" + LINE_SEPARATOR + 220 "<xsl:element name=\"TransformateurXML\">" + LINE_SEPARATOR + 221 " <xsl:for-each select=\"XMLUtils/test\">" + LINE_SEPARATOR + 222 " <xsl:element name=\"test2\">" + LINE_SEPARATOR + 223 " <xsl:element name=\"valeur2\">" + LINE_SEPARATOR + 224 " <xsl:attribute name=\"attribut2\">" + LINE_SEPARATOR + 225 " <xsl:value-of select=\"valeur/@attribut\"/>" + LINE_SEPARATOR + 226 " </xsl:attribute>" + LINE_SEPARATOR + 227 " <xsl:value-of select=\"valeur\"/>" + LINE_SEPARATOR + 228 " </xsl:element>" + LINE_SEPARATOR + 229 " </xsl:element>" + LINE_SEPARATOR + 230 " </xsl:for-each>" + LINE_SEPARATOR + 231 "</xsl:element>" + LINE_SEPARATOR + 232 "</xsl:template>" + LINE_SEPARATOR + 233 "</xsl:stylesheet>"; 234 235 final String sourceXml = 236 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + LINE_SEPARATOR + 237 // "<!DOCTYPE XMLUtils [" + LINE_SEPARATOR + 238 // "<!ELEMENT XMLUtils (test*)>" + LINE_SEPARATOR + 239 // "<!ELEMENT test (valeur*)>" + LINE_SEPARATOR + 240 // "<!ELEMENT valeur (#PCDATA)>" + LINE_SEPARATOR + 241 // "<!ATTLIST valeur attribut CDATA #REQUIRED>]>" + 242 // LINE_SEPARATOR + 243 "<XMLUtils>" + LINE_SEPARATOR + 244 " <test>" + LINE_SEPARATOR + 245 " <valeur attribut=\"Attribut 1\">Valeur 1</valeur>" + LINE_SEPARATOR + 246 " </test>" + LINE_SEPARATOR + 247 " <test>" + LINE_SEPARATOR + 248 " <valeur attribut=\"Attribut 2\">Valeur 2</valeur>" + LINE_SEPARATOR + 249 " </test>" + LINE_SEPARATOR + 250 "</XMLUtils>"; 251 252 Document document; 253 Node node; 254 255 System.out.println("Stylesheet:"); 256 System.out.println("=================================="); 257 System.out.println(xsl); 258 System.out.println(); 259 260 System.out.println("Source file before transformation:"); 261 System.out.println("=================================="); 262 System.out.println(sourceXml); 263 System.out.println(); 264 265 System.out.println("Source file after transformation:"); 266 System.out.println("================================="); 267 document = transformInputStreamToDocument(createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())), 268 new ByteArrayInputStream(sourceXml.getBytes())); 269 OutputFormat format = new OutputFormat(); 270 format.setIndenting(true); 271 new XMLSerializer(System.out, format).serialize(document); 272 System.out.println(); 273 274 System.out.println("Node content for element valeur2:"); 275 System.out.println("================================="); 276 NodeList nodes = document.getElementsByTagName("valeur2"); 277 nodes = document.getElementsByTagName("valeur2"); 278 for (int i = 0; i < nodes.getLength(); i++) { 279 node = nodes.item(i); 280 System.out.println(" Node value: " + node.getFirstChild().getNodeValue()); 281 System.out.println(" Node attribute: " + node.getAttributes().item(0).getNodeValue()); 282 283 AssertJUnit.assertEquals("Node value mismatch", "Valeur " + (i + 1), node.getFirstChild().getNodeValue()); 284 AssertJUnit.assertEquals("Node attribute mismatch", "Attribut " + (i + 1), node.getAttributes().item(0).getNodeValue()); 285 } 286 } 287 288 /* 289 * @bug 6305029 290 * @summary Test for JDK-6305029 291 */ 292 @Test 293 public final void testBug6305029() throws TransformerException { 294 final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<prefix:localName xmlns:prefix=\"namespaceUri\"/>"; 295 296 // test SAXSource 297 SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource()); 298 StringWriter resultWriter = new StringWriter(); 299 createTransformer().transform(saxSource, new StreamResult(resultWriter)); 300 AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString()); 301 302 // test StreamSource 303 StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT)); 304 resultWriter = new StringWriter(); 305 createTransformer().transform(streamSource, new StreamResult(resultWriter)); 306 AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString()); 307 } 308 309 /* 310 * @bug 6505031 311 * @summary Test transformer parses keys and their values coming from different xml documents. 312 */ 313 @Test 314 public final void testBug6505031() throws TransformerException { 315 Transformer transformer = createTransformerFromResource("transform.xsl"); 316 transformer.setParameter("config", getClass().getResource("config.xml").toString()); 317 transformer.setParameter("mapsFile", getClass().getResource("maps.xml").toString()); 318 String s = transformResourceToStringWriter(transformer, "template.xml").toString(); 319 Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); 320 } 321 322 /* 323 * @bug 8150704 324 * @summary Test that XSL transformation with lots of temporary result trees will not run out of DTM IDs. 325 */ 326 @Test 327 public final void testBug8150704() throws TransformerException, IOException { 328 System.out.println("Testing transformation of Bug8150704-1.xml..."); 329 Transformer transformer = createTransformerFromResource("Bug8150704-1.xsl"); 330 StringWriter result = transformResourceToStringWriter(transformer, "Bug8150704-1.xml"); 331 String resultstring = result.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n"); 332 String reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-1.ref").getPath())); 333 Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-1.xml does not match reference"); 334 System.out.println("Passed."); 335 336 System.out.println("Testing transformation of Bug8150704-2.xml..."); 337 transformer = createTransformerFromResource("Bug8150704-2.xsl"); 338 result = transformResourceToStringWriter(transformer, "Bug8150704-2.xml"); 339 resultstring = result.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n"); 340 reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-2.ref").getPath())); 341 Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference"); 342 System.out.println("Passed."); 343 } 344 }