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 org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.htmlunit.util.MimeType;
21  import org.junit.Test;
22  import org.junit.runner.RunWith;
23  
24  /**
25   * Tests for {@link XMLDocument}.
26   *
27   * @author Ahmed Ashour
28   * @author Ronald Brill
29   * @author Frank Danek
30   */
31  @RunWith(BrowserRunner.class)
32  public class XMLDocument2Test extends WebDriverTestCase {
33  
34      /**
35       * @throws Exception if the test fails
36       */
37      @Test
38      @Alerts({"myTarget,myData,7", "myTarget,myData", "<?myTarget myData?>"})
39      public void createProcessingInstruction() throws Exception {
40          final String html = DOCTYPE_HTML
41              + "<html><head>\n"
42              + "<script>\n"
43              + LOG_TITLE_FUNCTION
44              + "  function test() {\n"
45              + "    var doc = document.implementation.createDocument('', '', null);\n"
46              + "    var d = doc.createElement('doc');\n"
47              + "    d.setAttribute('fluffy', 'true');\n"
48              + "    d.setAttribute('numAttributes', '2');\n"
49              + "    doc.appendChild(d);\n"
50              + "    var pi = doc.createProcessingInstruction('myTarget', 'myData');\n"
51              + "    doc.insertBefore(pi, d);\n"
52              + "    log(pi.nodeName + ',' + pi.nodeValue + ',' + pi.nodeType);\n"
53              + "    log(pi.target + ',' + pi.data);\n"
54              + "    log(" + XMLDocumentTest.callSerializeXMLDocumentToString("pi") + ");\n"
55              + "  }\n"
56              + XMLDocumentTest.SERIALIZE_XML_DOCUMENT_TO_STRING_FUNCTION
57              + "</script></head><body onload='test()'>\n"
58              + "</body></html>";
59  
60          loadPageVerifyTitle2(html);
61      }
62  
63      /**
64       * @throws Exception if the test fails
65       */
66      @Test
67      @Alerts({"#cdata-section,abcdefghij,4", "abcdefghij", "<![CDATA[abcdefghij]]>"})
68      public void createCDATASection() throws Exception {
69          final String html = DOCTYPE_HTML
70              + "<html><head>\n"
71              + "<script>\n"
72              + LOG_TITLE_FUNCTION
73              + "  function test() {\n"
74              + "    var doc = document.implementation.createDocument('', '', null);\n"
75              + "    var d = doc.createElement('doc');\n"
76              + "    doc.appendChild(d);\n"
77              + "    var cdata = doc.createCDATASection('abcdefghij');\n"
78              + "    d.appendChild(cdata);\n"
79              + "    log(cdata.nodeName + ',' + cdata.nodeValue + ',' + cdata.nodeType);\n"
80              + "    log(cdata.data);\n"
81              + "    log(" + XMLDocumentTest.callSerializeXMLDocumentToString("cdata") + ");\n"
82              + "  }\n"
83              + XMLDocumentTest.SERIALIZE_XML_DOCUMENT_TO_STRING_FUNCTION
84              + "</script></head><body onload='test()'>\n"
85              + "</body></html>";
86  
87          loadPageVerifyTitle2(html);
88      }
89  
90      /**
91       * @throws Exception if the test fails
92       */
93      @Test
94      @Alerts({"#cdata-section,<>&?,4", "<>&?", "<![CDATA[<>&?]]>"})
95      public void createCDATASection_specialChars() throws Exception {
96          final String html = DOCTYPE_HTML
97              + "<html><head>\n"
98              + "<script>\n"
99              + LOG_TITLE_FUNCTION
100             + "  function test() {\n"
101             + "    var doc = document.implementation.createDocument('', '', null);\n"
102             + "    var d = doc.createElement('doc');\n"
103             + "    doc.appendChild(d);\n"
104             + "    var cdata = doc.createCDATASection('<>&?');\n"
105             + "    d.appendChild(cdata);\n"
106             + "    log(cdata.nodeName + ',' + cdata.nodeValue + ',' + cdata.nodeType);\n"
107             + "    log(cdata.data);\n"
108             + "    log(" + XMLDocumentTest.callSerializeXMLDocumentToString("cdata") + ");\n"
109             + "  }\n"
110             + XMLDocumentTest.SERIALIZE_XML_DOCUMENT_TO_STRING_FUNCTION
111             + "</script></head>\n"
112             + "<body onload='test()'>\n"
113             + "</body></html>";
114 
115         loadPageVerifyTitle2(html);
116     }
117 
118     /**
119      * @throws Exception if the test fails
120      */
121     @Test
122     @Alerts("createNode not available")
123     public void createNode() throws Exception {
124         final String html = DOCTYPE_HTML
125             + "<html><head>\n"
126             + "<script>\n"
127             + LOG_TITLE_FUNCTION
128             + "  function test() {\n"
129             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromString("'<root><child/></root>'") + ";\n"
130             + "    if (document.createNode) {\n"
131             + "      var node = doc.createNode(2, 'Sci-Fi', '');\n"
132             + "      doc.documentElement.childNodes.item(0).attributes.setNamedItem(node);\n"
133             + "      log(" + XMLDocumentTest.callSerializeXMLDocumentToString("doc.documentElement") + ");\n"
134             + "    } else { log('createNode not available'); }\n"
135             + "  }\n"
136             + XMLDocumentTest.LOAD_XML_DOCUMENT_FROM_STRING_FUNCTION
137             + XMLDocumentTest.SERIALIZE_XML_DOCUMENT_TO_STRING_FUNCTION
138             + "</script></head>\n"
139             + "<body onload='test()'>\n"
140             + "</body></html>";
141 
142         loadPageVerifyTitle2(html);
143     }
144 
145     /**
146      * @throws Exception if the test fails
147      */
148     @Test
149     @Alerts("createNode not available")
150     public void createNode_element() throws Exception {
151         final String html = DOCTYPE_HTML
152             + "<html><head>\n"
153             + "<script>\n"
154             + LOG_TITLE_FUNCTION
155             + "  function test() {\n"
156             + "    var doc = document.implementation.createDocument('', '', null);\n"
157             + "    if (document.createNode) {\n"
158             + "      var node = doc.createNode(1, 'test:element', 'uri:test');\n"
159             + "      log(node.localName);\n"
160             + "      log(node.prefix);\n"
161             + "      log(node.namespaceURI);\n"
162             + "      log(node.nodeName);\n"
163             + "    } else { log('createNode not available'); }\n"
164             + "  }\n"
165             + "</script></head>\n"
166             + "<body onload='test()'>\n"
167             + "</body></html>";
168         loadPageVerifyTitle2(html);
169     }
170 
171     /**
172      * @throws Exception if the test fails
173      */
174     @Test
175     @Alerts({"a", "null", "b"})
176     public void documentElementCaching() throws Exception {
177         final String html = DOCTYPE_HTML
178             + "<html><head>\n"
179             + "<script>\n"
180             + LOG_TITLE_FUNCTION
181             + "  function test() {\n"
182             + "    var doc = document.implementation.createDocument('', '', null);\n"
183             + "    var a = doc.createElement('a');\n"
184             + "    var b = doc.createElement('b');\n"
185             + "    doc.appendChild(a);\n"
186             + "    log(doc.documentElement.tagName);\n"
187             + "    doc.removeChild(a);\n"
188             + "    log(doc.documentElement);\n"
189             + "    doc.appendChild(b);\n"
190             + "    log(doc.documentElement.tagName);\n"
191             + "  }\n"
192             + "</script></head>\n"
193             + "<body onload='test()'>\n"
194             + "</body></html>";
195 
196         loadPageVerifyTitle2(html);
197     }
198 
199     /**
200      * @throws Exception if the test fails
201      */
202     @Test
203     @Alerts("a:b")
204     public void createElement_namespace() throws Exception {
205         final String html = DOCTYPE_HTML
206             + "<html><head>\n"
207             + "<script>\n"
208             + LOG_TITLE_FUNCTION
209             + "  function test() {\n"
210             + "    var doc = document.implementation.createDocument('', '', null);\n"
211             + "    var a = doc.createElement('a:b');\n"
212             + "    log(a.tagName);\n"
213             + "  }\n"
214             + "</script></head>\n"
215             + "<body onload='test()'>\n"
216             + "</body></html>";
217 
218         loadPageVerifyTitle2(html);
219     }
220 
221     /**
222      * Test for issue #1523.
223      *
224      * @throws Exception if the test fails
225      */
226     @Test
227     @Alerts("ReferenceError")
228     public void text() throws Exception {
229         final String html = DOCTYPE_HTML
230             + "<html><head>\n"
231             + "<script>\n"
232             + LOG_TITLE_FUNCTION
233             + "  function test() {\n"
234             + "    try {\n"
235             + "      new ActiveXObject('Microsoft.XMLDOM');\n"
236             + "    } catch(e) {\n"
237             + "      logEx(e);\n"
238             + "      return;\n"
239             + "    }\n"
240             + "    var xmldoc = new ActiveXObject('Microsoft.XMLDOM');\n"
241             + "    var xml = '<Envelope><Body>content</Body></Envelope>';\n"
242             + "    xmldoc.loadXML(xml);\n"
243 
244             + "    var expression = '/Envelope/Body';\n"
245             + "    var body = xmldoc.documentElement.selectSingleNode(expression);\n"
246             + "    log(body.text);\n"
247             + "    log(body.firstChild.text);\n"
248             + "  }\n"
249             + "</script></head>\n"
250             + "<body onload='test()'>\n"
251             + "</body></html>";
252         loadPageVerifyTitle2(html);
253     }
254 
255     /**
256      * @throws Exception if the test fails
257      */
258     @Test
259     @Alerts({"foo", "foo"})
260     public void firstChild_element() throws Exception {
261         final String html = DOCTYPE_HTML
262             + "<html><head>\n"
263             + "<script>\n"
264             + LOG_TITLE_FUNCTION
265             + "  function test() {\n"
266             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
267             + "    log(doc.firstChild.nodeName);\n"
268             + "    log(doc.documentElement.nodeName);\n"
269             + "  }\n"
270             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
271             + "</script></head>\n"
272             + "<body onload='test()'>\n"
273             + "</body></html>";
274 
275         final String xml =
276                "<foo>\n"
277              + "    <foofoo name='first'>something</foofoo>\n"
278              + "    <foofoo name='second'>something else</foofoo>\n"
279              + "</foo>";
280 
281         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
282         loadPageVerifyTitle2(html);
283     }
284 
285     /**
286      * @throws Exception if the test fails
287      */
288     @Test
289     @Alerts({"foo", "foo"})
290     // Xerces does not offer any way to access the XML declaration
291     public void firstChild_xmlDeclaration() throws Exception {
292         final String html = DOCTYPE_HTML
293             + "<html><head>\n"
294             + "<script>\n"
295             + LOG_TITLE_FUNCTION
296             + "  function test() {\n"
297             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
298             + "    log(doc.firstChild.nodeName);\n"
299             + "    log(doc.documentElement.nodeName);\n"
300             + "  }\n"
301             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
302             + "</script></head><body onload='test()'>\n"
303             + "</body></html>";
304 
305         final String xml =
306                "<?xml version=\"1.0\"?>\n"
307              + "<foo>\n"
308              + "  <foofoo name='first'>something</foofoo>\n"
309              + "  <foofoo name='second'>something else</foofoo>\n"
310              + "</foo>";
311 
312         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
313         loadPageVerifyTitle2(html);
314     }
315 
316     /**
317      * @throws Exception if the test fails
318      */
319     @Test
320     @Alerts({"apache", "foo"})
321     public void firstChild_processingInstruction() throws Exception {
322         final String html = DOCTYPE_HTML
323             + "<html><head>\n"
324             + "<script>\n"
325             + LOG_TITLE_FUNCTION
326             + "  function test() {\n"
327             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
328             + "    log(doc.firstChild.nodeName);\n"
329             + "    log(doc.documentElement.nodeName);\n"
330             + "  }\n"
331             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
332             + "</script></head>\n"
333             + "<body onload='test()'>\n"
334             + "</body></html>";
335 
336         final String xml =
337                "<?apache include file=\"header.html\" ?>\n"
338              + "<foo>\n"
339              + "  <foofoo name='first'>something</foofoo>\n"
340              + "  <foofoo name='second'>something else</foofoo>\n"
341              + "</foo>";
342 
343         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
344         loadPageVerifyTitle2(html);
345     }
346 
347     /**
348      * @throws Exception if the test fails
349      */
350     @Test
351     @Alerts({"dtd", "a"})
352     public void firstChild_documentType() throws Exception {
353         final String html = DOCTYPE_HTML
354             + "<html><head>\n"
355             + "<script>\n"
356             + LOG_TITLE_FUNCTION
357             + "  function test() {\n"
358             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
359             + "    log(doc.firstChild.nodeName);\n"
360             + "    log(doc.documentElement.nodeName);\n"
361             + "  }\n"
362             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
363             + "</script></head>\n"
364             + "<body onload='test()'>\n"
365             + "</body></html>";
366 
367         final String xml =
368               "<!DOCTYPE dtd [ <!ELEMENT a (b+)> <!ELEMENT b (#PCDATA)> ]>\n"
369             + "<a><b>1</b><b>2</b></a>";
370 
371         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
372         loadPageVerifyTitle2(html);
373     }
374 
375     /**
376      * @throws Exception if the test fails
377      */
378     @Test
379     @Alerts({"#comment", "foo"})
380     public void firstChild_comment() throws Exception {
381         final String html = DOCTYPE_HTML
382             + "<html><head>\n"
383             + "<script>\n"
384             + LOG_TITLE_FUNCTION
385             + "  function test() {\n"
386             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
387             + "    log(doc.firstChild.nodeName);\n"
388             + "    log(doc.documentElement.nodeName);\n"
389             + "  }\n"
390             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
391             + "</script></head>\n"
392             + "<body onload='test()'>\n"
393             + "</body></html>";
394 
395         final String xml =
396               "<!--comment-->\n"
397             + "<foo>\n"
398             + "  <foofoo name='first'>something</foofoo>\n"
399             + "  <foofoo name='second'>something else</foofoo>\n"
400             + "</foo>";
401 
402         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
403         loadPageVerifyTitle2(html);
404     }
405 
406     /**
407      * @throws Exception if the test fails
408      */
409     @Test
410     @Alerts({"foo", "fooc1", "null"})
411     public void firstElementChild() throws Exception {
412         final String html = DOCTYPE_HTML
413             + "<html><head><script>\n"
414             + LOG_TITLE_FUNCTION
415             + "  function test() {\n"
416             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
417 
418             + "    if (doc.firstElementChild == null) { log('not available'); return };\n"
419 
420             + "    log(doc.firstElementChild.nodeName);\n"
421             + "    log(doc.firstElementChild.firstElementChild.nodeName);\n"
422             + "    log(doc.firstElementChild.firstElementChild.firstElementChild);\n"
423             + "  }\n"
424             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
425             + "</script></head>\n"
426             + "<body onload='test()'>\n"
427             + "</body></html>";
428 
429         final String xml =
430                "<foo>\n"
431             + "    <fooc1 name='first'>something</fooc1>\n"
432             + "    <fooc2 name='second'>something else</fooc2>\n"
433             + "</foo>";
434 
435         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
436         loadPageVerifyTitle2(html);
437     }
438 
439     /**
440      * @throws Exception if the test fails
441      */
442     @Test
443     @Alerts({"foo", "fooc2", "null"})
444     public void lastElementChild() throws Exception {
445         final String html = DOCTYPE_HTML
446             + "<html><head>\n"
447             + "<script>\n"
448             + LOG_TITLE_FUNCTION
449             + "  function test() {\n"
450             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
451 
452             + "    if (doc.firstElementChild == null) { log('not available'); return };\n"
453 
454             + "    log(doc.lastElementChild.nodeName);\n"
455             + "    log(doc.firstElementChild.lastElementChild.nodeName);\n"
456             + "    log(doc.firstElementChild.firstElementChild.lastElementChild);\n"
457             + "  }\n"
458             + XMLDocumentTest.LOAD_NATIVE_XML_DOCUMENT_FROM_FILE_FUNCTION
459             + "</script></head>\n"
460             + "<body onload='test()'>\n"
461             + "</body></html>";
462 
463         final String xml =
464                "<foo>\n"
465              + "    <fooc1 name='first'>something</fooc1>\n"
466              + "    <fooc2 name='second'>something else</fooc2>\n"
467              + "</foo>";
468 
469         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
470         loadPageVerifyTitle2(html);
471     }
472 
473     /**
474      * Test case for issue #1576.
475      * @throws Exception if the test fails
476      */
477     @Test
478     @Alerts({"name: item1", "id: 1", "id: 2", "name: item2", "name: item3", "id: 3"})
479     public void attributeOrder() throws Exception {
480         final String html = DOCTYPE_HTML
481             + "<html><head>\n"
482             + "<script>\n"
483             + LOG_TITLE_FUNCTION
484             + "  function test() {\n"
485             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromString(
486                     "'<items>"
487                         + "<item name=\"item1\" id=\"1\">value1</item>"
488                         + "<item id=\"2\" name=\"item2\">value2</item>"
489                         + "<item name=\"item3\" id=\"3\">value3</item>"
490                     + "</items>'") + ";\n"
491             + "    var items = doc.getElementsByTagName('item');\n"
492             + "    for(var i = 0; i < items.length; i++) {\n"
493             + "      var attribs = items[i].attributes;\n"
494             + "      for(var j = 0; j < attribs.length; j++) {\n"
495             + "        log(attribs[j].name + ': ' + attribs[j].value);\n"
496             + "      }\n"
497             + "    }\n"
498             + "  }\n"
499             + XMLDocumentTest.LOAD_XML_DOCUMENT_FROM_STRING_FUNCTION
500             + "</script></head>\n"
501             + "<body onload='test()'>\n"
502             + "</body></html>";
503 
504         loadPageVerifyTitle2(html);
505     }
506 }