TransformerTest.java revision 887:0fe7231b64a6
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
24package transform;
25
26import com.sun.org.apache.xml.internal.serialize.OutputFormat;
27import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
28
29import java.io.BufferedReader;
30import java.io.ByteArrayInputStream;
31import java.io.File;
32import java.io.FileReader;
33import java.io.IOException;
34import java.io.InputStream;
35import java.io.StringReader;
36import java.io.StringWriter;
37
38import javax.xml.transform.Transformer;
39import javax.xml.transform.TransformerException;
40import javax.xml.transform.TransformerFactory;
41import javax.xml.transform.dom.DOMResult;
42import javax.xml.transform.sax.SAXSource;
43import javax.xml.transform.stream.StreamResult;
44import javax.xml.transform.stream.StreamSource;
45
46import org.testng.Assert;
47import org.testng.AssertJUnit;
48import org.testng.annotations.Test;
49import org.w3c.dom.Document;
50import org.w3c.dom.Node;
51import org.w3c.dom.NodeList;
52import org.xml.sax.ContentHandler;
53import org.xml.sax.DTDHandler;
54import org.xml.sax.EntityResolver;
55import org.xml.sax.ErrorHandler;
56import org.xml.sax.InputSource;
57import org.xml.sax.SAXException;
58import org.xml.sax.SAXNotRecognizedException;
59import org.xml.sax.SAXNotSupportedException;
60import org.xml.sax.XMLReader;
61import org.xml.sax.helpers.AttributesImpl;
62
63/*
64 * @summary Transformer Tests
65 * @bug 6272879 6305029 6505031 8150704
66 */
67public 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}
345