View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.xml;
16  
17  import java.net.URL;
18  
19  import org.htmlunit.MockWebConnection;
20  import org.htmlunit.WebDriverTestCase;
21  import org.htmlunit.junit.annotation.Alerts;
22  import org.htmlunit.junit.annotation.HtmlUnitNYI;
23  import org.htmlunit.util.MimeType;
24  import org.junit.jupiter.api.Test;
25  
26  /**
27   * Tests for {@link XSLTProcessor}.
28   *
29   * @author Ahmed Ashour
30   * @author Ronald Brill
31   */
32  public class XSLTProcessorTest extends WebDriverTestCase {
33  
34      /**
35       * @throws Exception if the test fails
36       */
37      @Test
38      @Alerts(DEFAULT = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
39                  + "<head></head><body> <h2>My CD Collection</h2> "
40                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul> </body></html>",
41              FF = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
42                  + "<body><h2>My CD Collection</h2>"
43                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
44              FF_ESR = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
45                  + "<body><h2>My CD Collection</h2>"
46                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>")
47      @HtmlUnitNYI(CHROME = "<html><body><h2>My CD Collection</h2>"
48                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
49              EDGE = "<html><body><h2>My CD Collection</h2>"
50                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
51              FF = "<html><body><h2>My CD Collection</h2>"
52                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
53              FF_ESR = "<html><body><h2>My CD Collection</h2>"
54                  + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>")
55      public void transformToDocument() throws Exception {
56          final String html = DOCTYPE_HTML
57              + "<html><head>\n"
58              + "<script>\n"
59              + LOG_TITLE_FUNCTION
60  
61              + "  function  loadXMLDocument(url) {\n"
62              + "    var xhttp = new XMLHttpRequest();\n"
63              + "    xhttp.open('GET', url, false);\n"
64              + "    xhttp.send();\n"
65              + "    return xhttp.responseXML;\n"
66              + "  }"
67  
68              + "  function test() {\n"
69              + "    try {\n"
70              + "      var xmlDoc = loadXMLDocument('" + URL_SECOND + "1');\n"
71              + "      var xslDoc = loadXMLDocument('" + URL_SECOND + "2');\n"
72  
73              + "      var processor = new XSLTProcessor();\n"
74              + "      processor.importStylesheet(xslDoc);\n"
75              + "      var newDocument = processor.transformToDocument(xmlDoc);\n"
76              + "      log(new XMLSerializer().serializeToString(newDocument.documentElement));\n"
77              + "    } catch(e) { logEx(e); }\n"
78              + "  }\n"
79  
80              + "</script></head><body onload='test()'>\n"
81              + "</body></html>";
82  
83          final String xml
84              = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
85              + "<catalog>\n"
86              + "  <cd>\n"
87              + "    <title>Empire Burlesque</title>\n"
88              + "    <artist>Bob Dylan</artist>\n"
89              + "    <country>USA</country>\n"
90              + "    <company>Columbia</company>\n"
91              + "    <price>10.90</price>\n"
92              + "    <year>1985</year>\n"
93              + "  </cd>\n"
94              + "</catalog>";
95  
96          final String xsl
97              = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
98              + "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
99              + "  <xsl:template match=\"/\">\n"
100             + "  <html>\n"
101             + "    <body>\n"
102             + "      <h2>My CD Collection</h2>\n"
103             + "      <ul>\n"
104             + "      <xsl:for-each select=\"catalog/cd\">\n"
105             + "        <li><xsl:value-of select='title'/> (<xsl:value-of select='artist'/>)</li>\n"
106             + "      </xsl:for-each>\n"
107             + "      </ul>\n"
108             + "    </body>\n"
109             + "  </html>\n"
110             + "  </xsl:template>\n"
111             + "</xsl:stylesheet>";
112 
113         final MockWebConnection conn = getMockWebConnection();
114         conn.setResponse(new URL(URL_SECOND, "1"), xml, MimeType.TEXT_XML);
115         conn.setResponse(new URL(URL_SECOND, "2"), xsl, MimeType.TEXT_XML);
116 
117         loadPageVerifyTitle2(html);
118     }
119 
120     /**
121      * @throws Exception if the test fails
122      */
123     @Test
124     @Alerts("*bar*")
125     public void transformToFragment() throws Exception {
126         final String xsl
127             = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
128             + "<xsl:template match=\"/\">*<xsl:value-of select=\"foo\" />*</xsl:template>"
129             + "</xsl:stylesheet>";
130 
131         final String html = DOCTYPE_HTML
132             + "<html><head>\n"
133             + "<script>\n"
134             + LOG_TITLE_FUNCTION
135 
136             + "  function test() {\n"
137             + "    try {\n"
138             + "      var xmlDoc = new DOMParser().parseFromString('<foo>bar</foo>', 'application/xml');\n"
139             + "      var xslDoc = new DOMParser().parseFromString('" + xsl + "', 'application/xml');\n"
140 
141             + "      var processor = new XSLTProcessor();\n"
142             + "      processor.importStylesheet(xslDoc);\n"
143             + "      var newFragment = processor.transformToFragment(xmlDoc, document);\n"
144             + "      log(new XMLSerializer().serializeToString(newFragment));\n"
145             + "    } catch(e) { logEx(e); }\n"
146             + "  }\n"
147 
148             + "</script></head><body onload='test()'>\n"
149             + "</body></html>";
150 
151         loadPageVerifyTitle2(html);
152     }
153 
154     /**
155      * @throws Exception if the test fails
156      */
157     @Test
158     @Alerts({"function", "function", "function", "function", "function",
159              "undefined", "undefined", "undefined", "undefined"})
160     public void methods() throws Exception {
161         final String html = DOCTYPE_HTML
162             + "<html><head>\n"
163             + "<script>\n"
164             + LOG_TITLE_FUNCTION
165             + "  function test() {\n"
166             + "    try {\n"
167             + "      if (XSLTProcessor) {\n"
168             + "        var processor = new XSLTProcessor();\n"
169             + "        log(typeof processor.importStylesheet);\n"
170             + "        log(typeof processor.transformToDocument);\n"
171             + "        log(typeof processor.transformToFragment);\n"
172             + "        log(typeof processor.setParameter);\n"
173             + "        log(typeof processor.getParameter);\n"
174             + "        log(typeof processor.input);\n"
175             + "        log(typeof processor.ouput);\n"
176             + "        log(typeof processor.addParameter);\n"
177             + "        log(typeof processor.transform);\n"
178             + "      } else {\n"
179             + "        log('XSLTProcessor not available');\n"
180             + "      }\n"
181             + "    } catch(e) { logEx(e); }\n"
182             + "  }\n"
183             + "</script></head><body onload='test()'>\n"
184             + "</body></html>";
185 
186         loadPageVerifyTitle2(html);
187     }
188 
189     /**
190      * @throws Exception if the test fails
191      */
192     @Test
193     @Alerts({"function", "function XSLTProcessor() { [native code] }",
194              "[object XSLTProcessor]"})
195     public void type() throws Exception {
196         final String html = DOCTYPE_HTML
197             + "<html><head>\n"
198             + "<script>\n"
199             + LOG_TITLE_FUNCTION
200             + "  function test() {\n"
201             + "    try {\n"
202             + "      log(typeof XSLTProcessor);\n"
203             + "      log(XSLTProcessor);\n"
204             + "      log(new XSLTProcessor());\n"
205             + "    } catch(e) { logEx(e) }\n"
206             + "  }\n"
207             + "</script></head><body onload='test()'>\n"
208             + "</body></html>";
209 
210         loadPageVerifyTitle2(html);
211     }
212 
213     /**
214      * @throws Exception if the test fails
215      */
216     @Test
217     @Alerts({"function XSLTProcessor() { [native code] }", "NaN", "true", "Yes", "Yes"})
218     public void browserDetection() throws Exception {
219         final String html = DOCTYPE_HTML
220             + "<html>\n"
221             + "<head>\n"
222             + "<script>\n"
223             + LOG_TITLE_FUNCTION
224             + "  function test() {\n"
225             + "    try {\n"
226             + "      log(String(XSLTProcessor));\n"
227             + "    } catch(e) { log('exception str'); }\n"
228             + "    try {\n"
229             + "      log(Number(XSLTProcessor));\n"
230             + "    } catch(e) { log('exception numb'); }\n"
231             + "    try {\n"
232             + "      log(Boolean(XSLTProcessor));\n"
233             + "    } catch(e) { log('exception bool'); }\n"
234             + "    try {\n"
235             + "      log(XSLTProcessor ? 'Yes' : 'No');\n"
236             + "    } catch(e) { log('exception ?'); }\n"
237             + "    try {\n"
238             + "      if (XSLTProcessor) { log('Yes') } else { log('No') }\n"
239             + "    } catch(e) { log('exception if'); }\n"
240             + "  }\n"
241             + "</script>\n"
242             + "</head>\n"
243             + "<body onload='test()'>\n"
244             + "</body></html>";
245         loadPageVerifyTitle2(html);
246     }
247 
248     /**
249      * @throws Exception if the test fails
250      */
251     @Test
252     @Alerts(DEFAULT = {"preparation done", "null"},
253             FF = {"preparation done", "exception "},
254             FF_ESR = {"preparation done", "exception "})
255     @HtmlUnitNYI(CHROME = {"preparation done", "exception InternalError"},
256             EDGE = {"preparation done", "exception InternalError"},
257             FF = {"preparation done", "exception InternalError"},
258             FF_ESR = {"preparation done", "exception InternalError"})
259     public void testSecurity() throws Exception {
260         final String html = DOCTYPE_HTML
261             + "<html><head>\n"
262             + "<script>\n"
263             + LOG_TITLE_FUNCTION
264 
265             + "  function  loadXMLDocument(url) {\n"
266             + "    var xhttp = new XMLHttpRequest();\n"
267             + "    xhttp.open('GET', url, false);\n"
268             + "    xhttp.send();\n"
269             + "    return xhttp.responseXML;\n"
270             + "  }"
271 
272             + "  function test() {\n"
273             + "    try {\n"
274             + "      var xmlDoc = loadXMLDocument('" + URL_SECOND + "1');\n"
275             + "      var xslDoc = loadXMLDocument('" + URL_SECOND + "2');\n"
276 
277             + "      var processor = new XSLTProcessor();\n"
278             + "      processor.importStylesheet(xslDoc);\n"
279             + "      log('preparation done');\n"
280             + "      var newDocument = processor.transformToDocument(xmlDoc);\n"
281             + "      log(newDocument);\n"
282             + "    } catch(e) { log('exception ' + e.name); }\n"
283             + "  }\n"
284             + "</script></head>"
285             + "<body onload='test()'>\n"
286             + "</body></html>";
287 
288         final String xml
289             = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
290             + "<s></s>";
291 
292         final String xsl
293             = " <xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" "
294                     + "xmlns:rt=\"http://xml.apache.org/xalan/java/java.lang.Runtime\" "
295                     + "xmlns:ob=\"http://xml.apache.org/xalan/java/java.lang.Object\">\r\n"
296             + "    <xsl:template match='/'>\n"
297             + "      <xsl:variable name='rtobject' select='rt:getRuntime()'/>\n"
298             + "      <xsl:variable name=\"rtString\" select=\"ob:toString($rtobject)\"/>\n"
299             + "      <xsl:value-of select=\"$rtString\"/>\n"
300             + "    </xsl:template>\r\n"
301             + "  </xsl:stylesheet>";
302 
303         final MockWebConnection conn = getMockWebConnection();
304         conn.setResponse(new URL(URL_SECOND, "1"), xml, MimeType.TEXT_XML);
305         conn.setResponse(new URL(URL_SECOND, "2"), xsl, MimeType.TEXT_XML);
306 
307         loadPageVerifyTitle2(html);
308     }
309 }