1   /*
2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3    *
4    * This software is open source.
5    * See the bottom of this file for the licence.
6    */
7   
8   package org.dom4j;
9   
10  import junit.textui.TestRunner;
11  
12  import java.io.ByteArrayInputStream;
13  import java.io.ByteArrayOutputStream;
14  import java.io.StringReader;
15  import java.io.StringWriter;
16  
17  import org.dom4j.io.OutputFormat;
18  import org.dom4j.io.SAXReader;
19  import org.dom4j.io.XMLWriter;
20  import org.dom4j.tree.BaseElement;
21  import org.dom4j.tree.DefaultDocument;
22  
23  import org.xml.sax.ContentHandler;
24  import org.xml.sax.SAXException;
25  import org.xml.sax.helpers.AttributesImpl;
26  
27  /***
28   * A simple test harness to check that the XML Writer works
29   * 
30   * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
31   * @version $Revision: 1.7.2.1 $
32   */
33  public class XMLWriterTest extends AbstractTestCase {
34      protected static final boolean VERBOSE = false;
35  
36      public static void main(String[] args) {
37          TestRunner.run(XMLWriterTest.class);
38      }
39  
40      // Test case(s)
41      // -------------------------------------------------------------------------
42      public void testBug1180791() throws Exception {
43          String xml = "<?xml version=\"1.0\"?><root><foo>bar</foo></root>";
44  
45          SAXReader reader = new SAXReader();
46          Document doc = reader.read(new StringReader(xml));
47          // of with newlines
48          OutputFormat format = new OutputFormat();
49          format.setNewlines(true);
50          //format.setTrimText(true);
51          // first time
52          StringWriter writer = new StringWriter();
53          XMLWriter xmlwriter = new XMLWriter(writer, format);
54          xmlwriter.write(doc);
55          System.out.println(writer.toString());
56  
57          // 2nd time
58          doc = reader.read(new StringReader(writer.toString()));
59          writer = new StringWriter();
60          xmlwriter = new XMLWriter(writer, format);
61          xmlwriter.write(doc);
62          System.out.println(writer.toString());
63      }
64  
65      public void testBug1119733() throws Exception {
66          Document doc = DocumentHelper
67                  .parseText("<root><code>foo</code> bar</root>");
68  
69          StringWriter out = new StringWriter();
70          XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
71          writer.write(doc);
72          writer.close();
73  
74          String xml = out.toString();
75  
76          System.out.println(xml);
77          assertEquals("whitespace problem", -1, xml.indexOf("</code>bar"));
78      }
79  
80      public void testBug1119733WithSAXEvents() throws Exception {
81          StringWriter out = new StringWriter();
82          XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
83          writer.startDocument();
84          writer.startElement(null, "root", "root", new AttributesImpl());
85          writer.startElement(null, "code", "code", new AttributesImpl());
86          writer.characters(new char[] { 'f', 'o', 'o' }, 0, 3);
87          writer.endElement(null, "code", "code");
88          writer.characters(new char[] { ' ', 'b', 'a', 'r' }, 0, 4);
89          writer.endElement(null, "root", "root");
90          writer.endDocument();
91          writer.close();
92  
93          String xml = out.toString();
94  
95          System.out.println(xml);
96          assertEquals("whitespace problem", -1, xml.indexOf("</code>bar"));
97      }
98  
99      public void testWriter() throws Exception {
100         Object object = document;
101         StringWriter out = new StringWriter();
102 
103         XMLWriter writer = new XMLWriter(out);
104         writer.write(object);
105         writer.close();
106 
107         String text = out.toString();
108 
109         if (VERBOSE) {
110             log("Text output is [");
111             log(text);
112             log("]. Done");
113         }
114 
115         assertTrue("Output text is bigger than 10 characters",
116                 text.length() > 10);
117     }
118 
119     public void testEncodingFormats() throws Exception {
120         testEncoding("UTF-8");
121         testEncoding("UTF-16");
122         testEncoding("ISO-8859-1");
123     }
124 
125     public void testWritingEmptyElement() throws Exception {
126         Document doc = DocumentFactory.getInstance().createDocument();
127         Element grandFather = doc.addElement("grandfather");
128         Element parent1 = grandFather.addElement("parent");
129         Element child1 = parent1.addElement("child1");
130         Element child2 = parent1.addElement("child2");
131         child2.setText("test");
132 
133         Element parent2 = grandFather.addElement("parent");
134         Element child3 = parent2.addElement("child3");
135         child3.setText("test");
136 
137         StringWriter buffer = new StringWriter();
138         OutputFormat format = OutputFormat.createPrettyPrint();
139         XMLWriter writer = new XMLWriter(buffer, format);
140         writer.write(doc);
141 
142         String xml = buffer.toString();
143 
144         System.out.println(xml);
145 
146         assertTrue("child2 not present",
147                 xml.indexOf("<child2>test</child2>") != -1);
148     }
149 
150     protected void testEncoding(String encoding) throws Exception {
151         ByteArrayOutputStream out = new ByteArrayOutputStream();
152 
153         OutputFormat format = OutputFormat.createPrettyPrint();
154         format.setEncoding(encoding);
155 
156         XMLWriter writer = new XMLWriter(out, format);
157         writer.write(document);
158         writer.close();
159 
160         log("Wrote to encoding: " + encoding);
161     }
162 
163     public void testWriterBug() throws Exception {
164         Element project = new BaseElement("project");
165         Document doc = new DefaultDocument(project);
166 
167         ByteArrayOutputStream out = new ByteArrayOutputStream();
168         XMLWriter writer = new XMLWriter(out, new OutputFormat("\t", true,
169                 "ISO-8859-1"));
170         writer.write(doc);
171 
172         ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
173         SAXReader reader = new SAXReader();
174         Document doc2 = reader.read(in);
175 
176         assertTrue("Generated document has a root element", doc2
177                 .getRootElement() != null);
178         assertEquals("Generated document has corrent named root element", doc2
179                 .getRootElement().getName(), "project");
180     }
181 
182     public void testNamespaceBug() throws Exception {
183         Document doc = DocumentHelper.createDocument();
184 
185         Element root = doc.addElement("root", "ns1");
186         Element child1 = root.addElement("joe", "ns2");
187         child1.addElement("zot", "ns1");
188 
189         StringWriter out = new StringWriter();
190         XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
191         writer.write(doc);
192 
193         String text = out.toString();
194 
195         // System.out.println( "Generated:" + text );
196         Document doc2 = DocumentHelper.parseText(text);
197         root = doc2.getRootElement();
198         assertEquals("root has incorrect namespace", "ns1", root
199                 .getNamespaceURI());
200 
201         Element joe = (Element) root.elementIterator().next();
202         assertEquals("joe has correct namespace", "ns2", joe.getNamespaceURI());
203 
204         Element zot = (Element) joe.elementIterator().next();
205         assertEquals("zot has correct namespace", "ns1", zot.getNamespaceURI());
206     }
207 
208     /***
209      * This test harness was supplied by Lari Hotari
210      * 
211      * @throws Exception DOCUMENT ME!
212      */
213     public void testContentHandler() throws Exception {
214         StringWriter out = new StringWriter();
215         OutputFormat format = OutputFormat.createPrettyPrint();
216         format.setEncoding("iso-8859-1");
217 
218         XMLWriter writer = new XMLWriter(out, format);
219         generateXML(writer);
220         writer.close();
221 
222         String text = out.toString();
223 
224         if (VERBOSE) {
225             log("Created XML");
226             log(text);
227         }
228 
229         // now lets parse the output and test it with XPath
230         Document doc = DocumentHelper.parseText(text);
231         String value = doc.valueOf("/processes[@name='arvojoo']");
232         assertEquals("Document contains the correct text", "jeejee", value);
233     }
234 
235     /***
236      * This test was provided by Manfred Lotz
237      * 
238      * @throws Exception DOCUMENT ME!
239      */
240     public void testWhitespaceBug() throws Exception {
241         String notes = "<notes> This is a      multiline\n\rentry</notes>";
242         Document doc = DocumentHelper.parseText(notes);
243 
244         OutputFormat format = new OutputFormat();
245         format.setEncoding("UTF-8");
246         format.setIndentSize(4);
247         format.setNewlines(true);
248         format.setTrimText(true);
249         format.setExpandEmptyElements(true);
250 
251         StringWriter buffer = new StringWriter();
252         XMLWriter writer = new XMLWriter(buffer, format);
253         writer.write(doc);
254 
255         String xml = buffer.toString();
256         log(xml);
257 
258         Document doc2 = DocumentHelper.parseText(xml);
259         String text = doc2.valueOf("/notes");
260         String expected = "This is a multiline entry";
261 
262         assertEquals("valueOf() returns the correct text padding", expected,
263                 text);
264 
265         assertEquals("getText() returns the correct text padding", expected,
266                 doc2.getRootElement().getText());
267     }
268 
269     /***
270      * This test was provided by Manfred Lotz
271      * 
272      * @throws Exception DOCUMENT ME!
273      */
274     public void testWhitespaceBug2() throws Exception {
275         Document doc = DocumentHelper.createDocument();
276         Element root = doc.addElement("root");
277         Element meaning = root.addElement("meaning");
278         meaning.addText("to li");
279         meaning.addText("ve");
280 
281         OutputFormat format = new OutputFormat();
282         format.setEncoding("UTF-8");
283         format.setIndentSize(4);
284         format.setNewlines(true);
285         format.setTrimText(true);
286         format.setExpandEmptyElements(true);
287 
288         StringWriter buffer = new StringWriter();
289         XMLWriter writer = new XMLWriter(buffer, format);
290         writer.write(doc);
291 
292         String xml = buffer.toString();
293         log(xml);
294 
295         Document doc2 = DocumentHelper.parseText(xml);
296         String text = doc2.valueOf("/root/meaning");
297         String expected = "to live";
298 
299         assertEquals("valueOf() returns the correct text padding", expected,
300                 text);
301 
302         assertEquals("getText() returns the correct text padding", expected,
303                 doc2.getRootElement().element("meaning").getText());
304     }
305 
306     public void testPadding() throws Exception {
307         Document doc = DocumentFactory.getInstance().createDocument();
308         Element root = doc.addElement("root");
309         root.addText("prefix    ");
310         root.addElement("b");
311         root.addText("      suffix");
312 
313         OutputFormat format = new OutputFormat("", false);
314         format.setOmitEncoding(true);
315         format.setSuppressDeclaration(true);
316         format.setExpandEmptyElements(true);
317         format.setPadText(true);
318         format.setTrimText(true);
319 
320         StringWriter buffer = new StringWriter();
321         XMLWriter writer = new XMLWriter(buffer, format);
322         writer.write(doc);
323 
324         String xml = buffer.toString();
325 
326         System.out.println("xml: " + xml);
327 
328         String expected = "<root>prefix <b></b> suffix</root>";
329         assertEquals(expected, xml);
330     }
331 
332     public void testPadding2() throws Exception {
333         Document doc = DocumentFactory.getInstance().createDocument();
334         Element root = doc.addElement("root");
335         root.addText("prefix");
336         root.addElement("b");
337         root.addText("suffix");
338 
339         OutputFormat format = new OutputFormat("", false);
340         format.setOmitEncoding(true);
341         format.setSuppressDeclaration(true);
342         format.setExpandEmptyElements(true);
343         format.setPadText(true);
344         format.setTrimText(true);
345 
346         StringWriter buffer = new StringWriter();
347         XMLWriter writer = new XMLWriter(buffer, format);
348         writer.write(doc);
349 
350         String xml = buffer.toString();
351 
352         System.out.println("xml: " + xml);
353 
354         String expected = "<root>prefix<b></b>suffix</root>";
355         assertEquals(expected, xml);
356     }
357 
358     /*
359      * This must be tested manually to see if the layout is correct.
360      */
361     public void testPrettyPrinting() throws Exception {
362         Document doc = DocumentFactory.getInstance().createDocument();
363         doc.addElement("summary").addAttribute("date", "6/7/8").addElement(
364                 "orderline").addText("puffins").addElement("ranjit")
365                 .addComment("Ranjit is a happy Puffin");
366 
367         XMLWriter writer = new XMLWriter(System.out, OutputFormat
368                 .createPrettyPrint());
369         writer.write(doc);
370 
371         doc = DocumentFactory.getInstance().createDocument();
372         doc.addElement("summary").addAttribute("date", "6/7/8").addElement(
373                 "orderline").addText("puffins").addElement("ranjit")
374                 .addComment("Ranjit is a happy Puffin").addComment(
375                         "another comment").addElement("anotherElement");
376         writer.write(doc);
377     }
378 
379     public void testAttributeQuotes() throws Exception {
380         Document doc = DocumentFactory.getInstance().createDocument();
381         doc.addElement("root").addAttribute("test", "text with ' in it");
382 
383         StringWriter out = new StringWriter();
384         XMLWriter writer = new XMLWriter(out, OutputFormat
385                 .createCompactFormat());
386         writer.write(doc);
387 
388         String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
389                 + "<root test=\"text with ' in it\"/>";
390         assertEquals(expected, out.toString());
391     }
392 
393     public void testBug868408() throws Exception {
394         Document doc = getDocument("/xml/web.xml");
395         Document doc2 = DocumentHelper.parseText(doc.asXML());
396         assertEquals(doc.asXML(), doc2.asXML());
397     }
398 
399     public void testBug923882() throws Exception {
400         Document doc = DocumentFactory.getInstance().createDocument();
401         Element root = doc.addElement("root");
402         root.addText("this is ");
403         root.addText(" sim");
404         root.addText("ple text ");
405         root.addElement("child");
406         root.addText(" contai");
407         root.addText("ning spaces and");
408         root.addText(" multiple textnodes");
409 
410         OutputFormat format = new OutputFormat();
411         format.setEncoding("UTF-8");
412         format.setIndentSize(4);
413         format.setNewlines(true);
414         format.setTrimText(true);
415         format.setExpandEmptyElements(true);
416 
417         StringWriter buffer = new StringWriter();
418         XMLWriter writer = new XMLWriter(buffer, format);
419         writer.write(doc);
420 
421         String xml = buffer.toString();
422         log(xml);
423 
424         int start = xml.indexOf("<root");
425         int end = xml.indexOf("/root>") + 6;
426         String eol = "\n"; // System.getProperty("line.separator");
427         String expected = "<root>this is simple text" + eol
428                 + "    <child></child>containing spaces and multiple textnodes"
429                 + eol + "</root>";
430         System.out.println("Expected:");
431         System.out.println(expected);
432         System.out.println("Obtained:");
433         System.out.println(xml.substring(start, end));
434         assertEquals(expected, xml.substring(start, end));
435     }
436 
437     public void testEscapeXML() throws Exception {
438         ByteArrayOutputStream os = new ByteArrayOutputStream();
439         OutputFormat format = new OutputFormat(null, false, "ISO-8859-2");
440         format.setSuppressDeclaration(true);
441 
442         XMLWriter writer = new XMLWriter(os, format);
443 
444         Document document = DocumentFactory.getInstance().createDocument();
445         Element root = document.addElement("root");
446         root.setText("bla &#c bla");
447 
448         writer.write(document);
449 
450         String result = os.toString();
451         System.out.println(result);
452 
453         Document doc2 = DocumentHelper.parseText(result);
454         doc2.normalize(); // merges adjacant Text nodes
455         System.out.println(doc2.getRootElement().getText());
456         assertNodesEqual(document, doc2);
457     }
458 
459     public void testWriteEntities() throws Exception {
460         String xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
461                 + "<!DOCTYPE xml [<!ENTITY copy \"&#169;\"> "
462                 + "<!ENTITY trade \"&#8482;\"> "
463                 + "<!ENTITY deg \"&#x00b0;\"> " + "<!ENTITY gt \"&#62;\"> "
464                 + "<!ENTITY sup2 \"&#x00b2;\"> "
465                 + "<!ENTITY frac14 \"&#x00bc;\"> "
466                 + "<!ENTITY quot \"&#34;\"> "
467                 + "<!ENTITY frac12 \"&#x00bd;\"> "
468                 + "<!ENTITY euro \"&#x20ac;\"> "
469                 + "<!ENTITY Omega \"&#937;\"> ]>\n" + "<root />";
470 
471         SAXReader reader = new SAXReader("org.apache.xerces.parsers.SAXParser");
472         reader.setIncludeInternalDTDDeclarations(true);
473 
474         Document doc = reader.read(new StringReader(xml));
475         StringWriter wr = new StringWriter();
476         XMLWriter writer = new XMLWriter(wr);
477         writer.write(doc);
478 
479         String xml2 = wr.toString();
480         System.out.println(xml2);
481 
482         Document doc2 = DocumentHelper.parseText(xml2);
483 
484         assertNodesEqual(doc, doc2);
485     }
486 
487     public void testEscapeChars() throws Exception {
488         Document document = DocumentFactory.getInstance().createDocument();
489         Element root = document.addElement("root");
490         root.setText("blahblah " + '\u008f');
491 
492         XMLWriter writer = new XMLWriter();
493         StringWriter strWriter = new StringWriter();
494         writer.setWriter(strWriter);
495         writer.setMaximumAllowedCharacter(127);
496         writer.write(document);
497 
498         String xml = strWriter.toString();
499     }
500 
501     public void testEscapeText() throws SAXException {
502         StringWriter writer = new StringWriter();
503         XMLWriter xmlWriter = new XMLWriter(writer);
504         xmlWriter.setEscapeText(false);
505 
506         String txt = "<test></test>";
507 
508         xmlWriter.startDocument();
509         xmlWriter.characters(txt.toCharArray(), 0, txt.length());
510         xmlWriter.endDocument();
511 
512         String output = writer.toString();
513         System.out.println(output);
514         assertTrue(output.indexOf("<test>") != -1);
515     }
516 
517     public void testNullCData() {
518         Element e = DocumentHelper.createElement("test");
519         e.add(DocumentHelper.createElement("another").addCDATA(null));
520 
521         Document doc = DocumentHelper.createDocument(e);
522 
523         assertEquals(-1, e.asXML().indexOf("null"));
524         assertEquals(-1, doc.asXML().indexOf("null"));
525 
526         System.out.println(e.asXML());
527         System.out.println(doc.asXML());
528     }
529 
530     protected void generateXML(ContentHandler handler) throws SAXException {
531         handler.startDocument();
532 
533         AttributesImpl attrs = new AttributesImpl();
534         attrs.clear();
535         attrs.addAttribute("", "", "name", "CDATA", "arvojoo");
536         handler.startElement("", "", "processes", attrs);
537 
538         String text = "jeejee";
539         char[] textch = text.toCharArray();
540         handler.characters(textch, 0, textch.length);
541         handler.endElement("", "", "processes");
542         handler.endDocument();
543     }
544 }
545 
546 /*
547  * Redistribution and use of this software and associated documentation
548  * ("Software"), with or without modification, are permitted provided that the
549  * following conditions are met:
550  * 
551  * 1. Redistributions of source code must retain copyright statements and
552  * notices. Redistributions must also contain a copy of this document.
553  * 
554  * 2. Redistributions in binary form must reproduce the above copyright notice,
555  * this list of conditions and the following disclaimer in the documentation
556  * and/or other materials provided with the distribution.
557  * 
558  * 3. The name "DOM4J" must not be used to endorse or promote products derived
559  * from this Software without prior written permission of MetaStuff, Ltd. For
560  * written permission, please contact dom4j-info@metastuff.com.
561  * 
562  * 4. Products derived from this Software may not be called "DOM4J" nor may
563  * "DOM4J" appear in their names without prior written permission of MetaStuff,
564  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
565  * 
566  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
567  * 
568  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
569  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
570  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
571  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
572  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
573  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
574  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
575  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
576  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
577  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
578  * POSSIBILITY OF SUCH DAMAGE.
579  * 
580  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
581  */